1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsFBXUtility.h"
4#include "Math/BsVector2.h"
5#include "Math/BsVector3.h"
6#include "Math/BsVector4.h"
7
8namespace bs
9{
10 struct SmoothNormal
11 {
12 int group = 0;
13 Vector3 normal = Vector3::ZERO;
14
15 void addNormal(int group, const Vector3& normal)
16 {
17 this->group |= group;
18 this->normal += normal;
19 }
20
21 void addNormal(const SmoothNormal& other)
22 {
23 this->group |= other.group;
24 this->normal += other.normal;
25 }
26
27 void normalize()
28 {
29 normal.normalize();
30 }
31 };
32
33 struct SmoothVertex
34 {
35 Vector<SmoothNormal> normals;
36
37 void addNormal(int group, const Vector3& normal)
38 {
39 bool found = false;
40
41 for (size_t i = 0; i < normals.size(); i++)
42 {
43 if ((normals[i].group & group) != 0)
44 {
45 bool otherGroups = (group & ~normals[i].group) != 0;
46
47 if (otherGroups)
48 {
49 for (size_t j = i + 1; j < normals.size(); j++)
50 {
51 if ((normals[j].group & group) != 0)
52 {
53 normals[i].addNormal(normals[j]);
54 normals.erase(normals.begin() + j);
55 --j;
56 }
57 }
58 }
59
60 normals[i].addNormal(group, normal);
61
62 found = true;
63 break;;
64 }
65 }
66
67 if (!found)
68 {
69 SmoothNormal smoothNormal;
70 smoothNormal.addNormal(group, normal);
71
72 normals.push_back(smoothNormal);
73 }
74 }
75
76 Vector3 getNormal(int group) const
77 {
78 for (size_t i = 0; i < normals.size(); i++)
79 {
80 if (normals[i].group & group)
81 return normals[i].normal;
82 }
83
84 return Vector3::ZERO;
85 }
86
87 void normalize()
88 {
89 for (size_t i = 0; i < normals.size(); ++i)
90 normals[i].normalize();
91 }
92 };
93
94 void FBXUtility::normalsFromSmoothing(const Vector<Vector3>& positions, const Vector<int>& indices,
95 const Vector<int>& smoothing, Vector<Vector3>& normals)
96 {
97 std::vector<SmoothVertex> smoothNormals;
98 smoothNormals.resize(positions.size());
99
100 normals.resize(indices.size(), Vector3::ZERO);
101
102 UINT32 numPolygons = (UINT32)(indices.size() / 3);
103
104 int idx = 0;
105 for (UINT32 i = 0; i < numPolygons; i++)
106 {
107 for (UINT32 j = 0; j < 3; j++)
108 {
109 int prevOffset = (j > 0 ? j - 1 : 2);
110 int nextOffset = (j < 2 ? j + 1 : 0);
111
112 int current = indices[idx + j];
113
114 Vector3 v0 = (Vector3)positions[indices[idx + prevOffset]];
115 Vector3 v1 = (Vector3)positions[current];
116 Vector3 v2 = (Vector3)positions[indices[idx + nextOffset]];
117
118 Vector3 normal = Vector3::cross(v0 - v1, v2 - v1);
119 smoothNormals[current].addNormal(smoothing[idx + j], normal);
120
121 normals[idx + j] = normal;
122 }
123
124 idx += 3;
125 }
126
127 for (size_t i = 0; i < smoothNormals.size(); ++i)
128 smoothNormals[i].normalize();
129
130 idx = 0;
131 for (UINT32 i = 0; i < numPolygons; i++)
132 {
133 for (UINT32 j = 0; j < 3; j++)
134 {
135 if (smoothing[idx + j] != 0)
136 {
137 int current = indices[idx + j];
138
139 normals[idx + j] = smoothNormals[current].getNormal(smoothing[idx + j]);
140 }
141 }
142
143 idx += 3;
144 }
145 }
146
147 void FBXUtility::splitVertices(const FBXImportMesh& source, FBXImportMesh& dest)
148 {
149 dest.indices = source.indices;
150 dest.materials = source.materials;
151
152 dest.positions = source.positions;
153 dest.boneInfluences = source.boneInfluences;
154
155 // Make room for minimal set of vertices
156 UINT32 vertexCount = (UINT32)source.positions.size();
157 if (!source.normals.empty())
158 dest.normals.resize(vertexCount);
159
160 if (!source.tangents.empty())
161 dest.tangents.resize(vertexCount);
162
163 if (!source.bitangents.empty())
164 dest.bitangents.resize(vertexCount);
165
166 if (!source.colors.empty())
167 dest.colors.resize(vertexCount);
168
169 for (UINT32 i = 0; i < FBX_IMPORT_MAX_UV_LAYERS; i++)
170 {
171 if (!source.UV[i].empty())
172 dest.UV[i].resize(vertexCount);
173 }
174
175 UINT32 numBlendShapes = (UINT32)source.blendShapes.size();
176 dest.blendShapes.resize(numBlendShapes);
177 for (UINT32 i = 0; i < numBlendShapes; i++)
178 {
179 const FBXBlendShape& sourceShape = source.blendShapes[i];
180 FBXBlendShape& destShape = dest.blendShapes[i];
181
182 UINT32 numFrames = (UINT32)sourceShape.frames.size();
183 destShape.frames.resize(numFrames);
184 destShape.name = sourceShape.name;
185
186 for (UINT32 j = 0; j < numFrames; j++)
187 {
188 const FBXBlendShapeFrame& sourceFrame = sourceShape.frames[j];
189 FBXBlendShapeFrame& destFrame = destShape.frames[j];
190
191 destFrame.name = sourceFrame.name;
192 destFrame.weight = sourceFrame.weight;
193 destFrame.positions = sourceFrame.positions;
194
195 if (!sourceFrame.normals.empty())
196 destFrame.normals.resize(vertexCount);
197
198 if (!sourceFrame.tangents.empty())
199 destFrame.tangents.resize(vertexCount);
200
201 if (!sourceFrame.bitangents.empty())
202 destFrame.bitangents.resize(vertexCount);
203 }
204 }
205
206 Vector<Vector<int>> splitsPerVertex;
207 splitsPerVertex.resize(source.positions.size());
208
209 Vector<int>& indices = dest.indices;
210 int indexCount = (int)dest.indices.size();
211 for (int i = 0; i < indexCount; i++)
212 {
213 int srcVertIdx = indices[i];
214 int dstVertIdx = -1;
215
216 // See if we already processed this vertex and if its attributes
217 // are close enough with the previous version
218 Vector<int>& splits = splitsPerVertex[srcVertIdx];
219 for (auto& splitVertIdx : splits)
220 {
221 if (!needsSplitAttributes(source, i, dest, splitVertIdx))
222 dstVertIdx = splitVertIdx;
223 }
224
225 // We didn't find a close-enough match
226 if (dstVertIdx == -1)
227 {
228 // First time we visited this vertex, so just copy over attributes
229 if (splits.empty())
230 {
231 dstVertIdx = srcVertIdx;
232 copyVertexAttributes(source, i, dest, dstVertIdx);
233 }
234 else // Split occurred, add a brand new vertex
235 {
236 dstVertIdx = (int)dest.positions.size();
237 addVertex(source, i, srcVertIdx, dest);
238 }
239
240 splits.push_back(dstVertIdx);
241 }
242
243 indices[i] = dstVertIdx;
244 }
245 }
246
247 void FBXUtility::flipWindingOrder(FBXImportMesh& input)
248 {
249 for (UINT32 i = 0; i < (UINT32)input.materials.size(); i += 3)
250 {
251 std::swap(input.materials[i + 1], input.materials[i + 2]);
252 }
253
254 for (UINT32 i = 0; i < (UINT32)input.indices.size(); i += 3)
255 {
256 std::swap(input.indices[i + 1], input.indices[i + 2]);
257 }
258 }
259
260 void FBXUtility::copyVertexAttributes(const FBXImportMesh& srcMesh, int srcIdx, FBXImportMesh& destMesh, int dstIdx)
261 {
262 if (!srcMesh.normals.empty())
263 destMesh.normals[dstIdx] = srcMesh.normals[srcIdx];
264
265 if (!srcMesh.tangents.empty())
266 destMesh.tangents[dstIdx] = srcMesh.tangents[srcIdx];
267
268 if (!srcMesh.bitangents.empty())
269 destMesh.bitangents[dstIdx] = srcMesh.bitangents[srcIdx];
270
271 if (!srcMesh.colors.empty())
272 destMesh.colors[dstIdx] = srcMesh.colors[srcIdx];
273
274 for (UINT32 i = 0; i < FBX_IMPORT_MAX_UV_LAYERS; i++)
275 {
276 if (!srcMesh.UV[i].empty())
277 destMesh.UV[i][dstIdx] = srcMesh.UV[i][srcIdx];
278 }
279
280 UINT32 numBlendShapes = (UINT32)srcMesh.blendShapes.size();
281 for (UINT32 i = 0; i < numBlendShapes; i++)
282 {
283 const FBXBlendShape& sourceShape = srcMesh.blendShapes[i];
284 FBXBlendShape& destShape = destMesh.blendShapes[i];
285
286 UINT32 numFrames = (UINT32)sourceShape.frames.size();
287 for (UINT32 j = 0; j < numFrames; j++)
288 {
289 const FBXBlendShapeFrame& sourceFrame = sourceShape.frames[j];
290 FBXBlendShapeFrame& destFrame = destShape.frames[j];
291
292 if (!sourceFrame.normals.empty())
293 destFrame.normals[dstIdx] = sourceFrame.normals[srcIdx];
294
295 if (!sourceFrame.tangents.empty())
296 destFrame.tangents[dstIdx] = sourceFrame.tangents[srcIdx];
297
298 if (!sourceFrame.bitangents.empty())
299 destFrame.bitangents[dstIdx] = sourceFrame.bitangents[srcIdx];
300 }
301 }
302 }
303
304 void FBXUtility::addVertex(const FBXImportMesh& srcMesh, int srcIdx, int srcVertex, FBXImportMesh& destMesh)
305 {
306 destMesh.positions.push_back(srcMesh.positions[srcVertex]);
307
308 if (!srcMesh.boneInfluences.empty())
309 destMesh.boneInfluences.push_back(srcMesh.boneInfluences[srcVertex]);
310
311 if (!srcMesh.normals.empty())
312 destMesh.normals.push_back(srcMesh.normals[srcIdx]);
313
314 if (!srcMesh.tangents.empty())
315 destMesh.tangents.push_back(srcMesh.tangents[srcIdx]);
316
317 if (!srcMesh.bitangents.empty())
318 destMesh.bitangents.push_back(srcMesh.bitangents[srcIdx]);
319
320 if (!srcMesh.colors.empty())
321 destMesh.colors.push_back(srcMesh.colors[srcIdx]);
322
323 for (UINT32 i = 0; i < FBX_IMPORT_MAX_UV_LAYERS; i++)
324 {
325 if (!srcMesh.UV[i].empty())
326 destMesh.UV[i].push_back(srcMesh.UV[i][srcIdx]);
327 }
328
329 UINT32 numBlendShapes = (UINT32)srcMesh.blendShapes.size();
330 for (UINT32 i = 0; i < numBlendShapes; i++)
331 {
332 const FBXBlendShape& sourceShape = srcMesh.blendShapes[i];
333 FBXBlendShape& destShape = destMesh.blendShapes[i];
334
335 UINT32 numFrames = (UINT32)sourceShape.frames.size();
336 for (UINT32 j = 0; j < numFrames; j++)
337 {
338 const FBXBlendShapeFrame& sourceFrame = sourceShape.frames[j];
339 FBXBlendShapeFrame& destFrame = destShape.frames[j];
340
341 destFrame.positions.push_back(sourceFrame.positions[srcVertex]);
342
343 if (!sourceFrame.normals.empty())
344 destFrame.normals.push_back(sourceFrame.normals[srcIdx]);
345
346 if (!sourceFrame.tangents.empty())
347 destFrame.tangents.push_back(sourceFrame.tangents[srcIdx]);
348
349 if (!sourceFrame.bitangents.empty())
350 destFrame.bitangents.push_back(sourceFrame.bitangents[srcIdx]);
351 }
352 }
353 }
354
355 bool FBXUtility::needsSplitAttributes(const FBXImportMesh& meshA, int idxA, const FBXImportMesh& meshB, int idxB)
356 {
357 static const float SplitAngleCosine = Math::cos(Degree(1.0f));
358 static const float UVEpsilon = 0.001f;
359
360 if (!meshA.colors.empty())
361 {
362 if (meshA.colors[idxA] != meshB.colors[idxB])
363 return true;
364 }
365
366 if (!meshA.normals.empty())
367 {
368 float angleCosine = meshA.normals[idxA].dot(meshB.normals[idxB]);
369 if (angleCosine < SplitAngleCosine)
370 return true;
371 }
372
373 if (!meshA.tangents.empty())
374 {
375 float angleCosine = meshA.tangents[idxA].dot(meshB.tangents[idxB]);
376 if (angleCosine < SplitAngleCosine)
377 return true;
378 }
379
380 if (!meshA.bitangents.empty())
381 {
382 float angleCosine = meshA.bitangents[idxA].dot(meshB.bitangents[idxB]);
383 if (angleCosine < SplitAngleCosine)
384 return true;
385 }
386
387 for (UINT32 i = 0; i < FBX_IMPORT_MAX_UV_LAYERS; i++)
388 {
389 if (!meshA.UV[i].empty())
390 {
391 if (!Math::approxEquals(meshA.UV[i][idxA], meshB.UV[i][idxB], UVEpsilon))
392 return true;
393 }
394 }
395
396 UINT32 numBlendShapes = (UINT32)meshA.blendShapes.size();
397 for (UINT32 i = 0; i < numBlendShapes; i++)
398 {
399 const FBXBlendShape& shapeA = meshA.blendShapes[i];
400 const FBXBlendShape& shapeB = meshB.blendShapes[i];
401
402 UINT32 numFrames = (UINT32)shapeA.frames.size();
403 for (UINT32 j = 0; j < numFrames; j++)
404 {
405 const FBXBlendShapeFrame& frameA = shapeA.frames[j];
406 const FBXBlendShapeFrame& frameB = shapeB.frames[j];
407
408 if (!frameA.normals.empty())
409 {
410 float angleCosine = frameA.normals[idxA].dot(frameB.normals[idxB]);
411 if (angleCosine < SplitAngleCosine)
412 return true;
413 }
414
415 if (!frameA.tangents.empty())
416 {
417 float angleCosine = frameA.tangents[idxA].dot(frameB.tangents[idxB]);
418 if (angleCosine < SplitAngleCosine)
419 return true;
420 }
421
422 if (!frameA.bitangents.empty())
423 {
424 float angleCosine = frameA.bitangents[idxA].dot(frameB.bitangents[idxB]);
425 if (angleCosine < SplitAngleCosine)
426 return true;
427 }
428 }
429 }
430
431 return false;
432 }
433}