TDME2  1.9.200
FBXReader.cpp
Go to the documentation of this file.
2 
3 #define FBXSDK_SHARED
4 #include <fbxsdk.h>
5 #undef isnan
6 
7 #include <map>
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include <tdme/tdme.h>
15 #include <tdme/engine/model/Face.h>
21 #include <tdme/engine/model/Node.h>
26 #include <tdme/engine/Texture.h>
27 #include <tdme/math/Math.h>
28 #include <tdme/math/Matrix3x3.h>
29 #include <tdme/math/Vector2.h>
30 #include <tdme/math/Vector3.h>
34 #include <tdme/utilities/Console.h>
37 
38 using std::make_unique;
39 using std::map;
40 using std::string;
41 using std::to_string;
42 using std::unique_ptr;
43 using std::vector;
44 
58 using tdme::math::Math;
68 
69 const Color4 FBXReader::BLENDER_AMBIENT_NONE(0.0f, 0.0f, 0.0f, 1.0f);
70 
71 Model* FBXReader::read(const string& pathName, const string& fileName, bool useBC7TextureCompression) {
72  // init fbx sdk
73  auto fbxManager = unique_ptr<FbxManager, decltype([](FbxManager* fbxManager){ fbxManager->Destroy(); })>(FbxManager::Create());
74  if (fbxManager == nullptr) {
75  Console::println("FBXReader::read(): Unable to create FBX manager.");
76  return nullptr;
77  } else {
78  Console::println(string("FBXReader::read(): Autodesk FBX SDK version ") + string(fbxManager->GetVersion()));
79  }
80 
81  Console::println("FBXReader::read(): reading FBX scene");
82 
83  auto ios = unique_ptr<FbxIOSettings, decltype([](FbxIOSettings* fbxIOSettings){ fbxIOSettings->Destroy(); })>(FbxIOSettings::Create(fbxManager.get(), IOSROOT));
84  fbxManager->SetIOSettings(ios.get());
85  auto lPath = FbxGetApplicationDirectory();
86  fbxManager->LoadPluginsDirectory(lPath.Buffer());
87  auto fbxScene = unique_ptr<FbxScene, decltype([](FbxScene* fbxScene){ fbxScene->Destroy(); })>(FbxScene::Create(fbxManager.get(), "My Scene"));
88  if (fbxScene == nullptr) {
89  throw ModelFileIOException("FBXReader::read(): Error: Unable to create FBX scene");
90  }
91 
92  // create import and import scene
93  auto fbxImporter = unique_ptr<FbxImporter, decltype([](FbxImporter* fbxImporter){ fbxImporter->Destroy(); })>(FbxImporter::Create(fbxManager.get(), ""));
94  //
95  vector<uint8_t> fbxData;
96  FileSystem::getInstance()->getContent(pathName, fileName, fbxData);
97  FBXReaderStream fbxReaderStream(fbxManager.get(), &fbxData);
98  // see: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/class_fbx_stream.html,topicNumber=cpp_ref_class_fbx_stream_html2b5775d9-5d58-4231-a2a1-de97aada1fe6
99  auto fbxImportStatus = fbxImporter->Initialize(&fbxReaderStream, nullptr, -1, fbxManager->GetIOSettings());
100  if (fbxImportStatus == false) {
101  throw ModelFileIOException("FBXReader::read(): Error: Unable to import FBX scene from '" + pathName + "/" + fileName);
102  }
103  // import the scene
104  fbxImportStatus = fbxImporter->Import(fbxScene.get());
105  if (fbxImportStatus == false) {
106  throw ModelFileIOException("FBXReader::read(): Error: Unable to import FBX scene from '" + pathName + "/" + fileName + " into scene");
107  }
108 
109  //
110  Console::println("FBXReader::read(): Authoring program: " + string(fbxScene->GetDocumentInfo()->Original_ApplicationName.Get().Buffer()));
111 
112  //
113  Console::println("FBXReader::read(): triangulating FBX");
114  // triangulate
115  FbxGeometryConverter fbxGeometryConverter(fbxManager.get());
116  fbxGeometryConverter.Triangulate(fbxScene.get(), true);
117 
118  Console::println("FBXReader::read(): importing FBX");
119 
120  // create model
121  auto model = make_unique<Model>(
122  fileName,
123  fileName,
124  getSceneUpVector(fbxScene.get()),
125  getSceneRotationOrder(fbxScene.get()),
126  nullptr,
127  string(fbxScene->GetDocumentInfo()->Original_ApplicationName.Get().Buffer()).find("Blender") != -1?
128  Model::AUTHORINGTOOL_BLENDER:
129  Model::AUTHORINGTOOL_UNKNOWN
130  );
131 
132  // set up model import matrix
133  setupModelImportRotationMatrix(model.get());
134  setupModelScaleRotationMatrix(fbxScene.get(), model.get());
135 
136  // store possible armuature node ids (Blender only)
137  vector<string> possibleArmatureNodeIds;
138 
139  // process nodes
140  processScene(fbxScene.get(), model.get(), pathName, possibleArmatureNodeIds, useBC7TextureCompression);
141 
142  //
143  Console::println("FBXReader::read(): setting up animations");
144 
145  // parse animations stacks
146  FbxTime::SetGlobalTimeMode(FbxTime::eCustom, 30.0);
147  FbxArray<FbxString*> fbxAnimStackNameArray;
148  fbxScene->FillAnimStackNameArray(fbxAnimStackNameArray);
149  int framesTotal = 0;
150  for(auto i = 0; i < fbxAnimStackNameArray.GetCount(); i++) {
151  FbxTime fbxStartTime, fbxEndTime;
152  auto fbxCurrentTakeInfo = fbxScene->GetTakeInfo(*(fbxAnimStackNameArray[i]));
153  if (fbxCurrentTakeInfo != nullptr) {
154  fbxStartTime = fbxCurrentTakeInfo->mLocalTimeSpan.GetStart();
155  fbxEndTime = fbxCurrentTakeInfo->mLocalTimeSpan.GetStop();
156  } else {
157  FbxTimeSpan fbxTimeLineTimeSpan;
158  fbxScene->GetGlobalSettings().GetTimelineDefaultTimeSpan(fbxTimeLineTimeSpan);
159  fbxStartTime = fbxTimeLineTimeSpan.GetStart();
160  fbxEndTime = fbxTimeLineTimeSpan.GetStop();
161  }
162  int startFrame = (int)Math::ceil(fbxStartTime.GetMilliSeconds() / (1000.0f * 1.0f / 30.0f));
163  int endFrame = (int)Math::ceil(fbxEndTime.GetMilliSeconds() / (1000.0f * 1.0f / 30.0f)) - 1;
164  framesTotal+= endFrame - startFrame + 1;
165  }
166  model->addAnimationSetup(
167  Model::ANIMATIONSETUP_DEFAULT,
168  0,
169  framesTotal,
170  true
171  );
172  int frameOffset = 0;
173  for(auto i = 0; i < fbxAnimStackNameArray.GetCount(); i++ ) {
174  auto fbxCurrentAnimationStack = fbxScene->FindMember<FbxAnimStack>(fbxAnimStackNameArray[i]->Buffer());
175  auto fbxCurrentTakeInfo = fbxScene->GetTakeInfo(*(fbxAnimStackNameArray[i]));
176  FbxTime fbxStartTime, fbxEndTime;
177  if (fbxCurrentTakeInfo != nullptr) {
178  fbxStartTime = fbxCurrentTakeInfo->mLocalTimeSpan.GetStart();
179  fbxEndTime = fbxCurrentTakeInfo->mLocalTimeSpan.GetStop();
180  } else {
181  FbxTimeSpan fbxTimeLineTimeSpan;
182  fbxScene->GetGlobalSettings().GetTimelineDefaultTimeSpan(fbxTimeLineTimeSpan);
183  fbxStartTime = fbxTimeLineTimeSpan.GetStart();
184  fbxEndTime = fbxTimeLineTimeSpan.GetStop();
185  }
186  int startFrame = (int)Math::ceil(fbxStartTime.GetMilliSeconds() / (1000.0f * 1.0f / 30.0f));
187  int endFrame = (int)Math::ceil(fbxEndTime.GetMilliSeconds() / (1000.0f * 1.0f / 30.0f)) - 1;
188  auto animationName = string(fbxAnimStackNameArray[i]->Buffer());
189  if (possibleArmatureNodeIds.size() == 1) {
190  for (const auto& possibleArmatureNodeId: possibleArmatureNodeIds) {
191  if (StringTools::startsWith(animationName, possibleArmatureNodeId + "|") == true) {
192  animationName = StringTools::substring(animationName, possibleArmatureNodeId.size() + 1, animationName.size());
193  break;
194  }
195  }
196  }
197  model->addAnimationSetup(
198  animationName,
199  frameOffset + startFrame,
200  frameOffset + endFrame,
201  false
202  );
203  fbxScene->SetCurrentAnimationStack(fbxCurrentAnimationStack);
204  FbxNode* fbxNode = fbxScene->GetRootNode();
205  if (fbxNode == nullptr) continue;
206  for(auto i = 0; i < fbxNode->GetChildCount(); i++) {
207  processAnimation(fbxNode->GetChild(i), fbxStartTime, fbxEndTime, model.get(), frameOffset);
208  }
209  frameOffset+= endFrame - startFrame + 1;
210  }
211  FbxArrayDelete(fbxAnimStackNameArray);
212 
213  //
214  Console::println("FBXReader::read(): destroying FBX SDK");
215  Console::println("FBXReader::read(): prepare for indexed rendering");
216 
217  //
218  ModelTools::setupJoints(model.get());
219  ModelTools::fixAnimationLength(model.get());
220  ModelTools::prepareForIndexedRendering(model.get());
221 
222  Console::println("FBXReader::read(): done");
223 
224  //
225  return model.release();
226 }
227 
229  auto upVector = getSceneUpVector(fbxScene);
230 
231  // take rotation order from root node now
232  FbxNode* fbxNode = fbxScene->GetRootNode();
233  EFbxRotationOrder fbxRotationOrder;
234  fbxNode->GetRotationOrder(FbxNode::eSourcePivot, fbxRotationOrder);
235  if (fbxRotationOrder == eEulerXYZ) {
236  if (upVector == UpVector::Y_UP) {
237  return RotationOrder::ZYX;
238  } else
239  if (upVector == UpVector::Z_UP) {
240  return RotationOrder::YZX;
241  } else {
242  throw ModelFileIOException("Unknown Up vector");
243  }
244  } else {
245  throw ModelFileIOException("Not supported rotation order(" + to_string(fbxRotationOrder) + ")");
246  }
247 }
248 
249 UpVector* FBXReader::getSceneUpVector(FbxScene* fbxScene) {
250  int fbxUpVectorSign;
251  auto fbxUpVector = fbxScene->GetGlobalSettings().GetAxisSystem().GetUpVector(fbxUpVectorSign);
252  switch (fbxUpVector) {
253  case FbxAxisSystem::eXAxis:
254  throw ModelFileIOException("X-Up is not supported");
255  case FbxAxisSystem::eYAxis:
256  return UpVector::Y_UP;
257  case FbxAxisSystem::eZAxis:
258  return UpVector::Z_UP;
259  default:
260  throw ModelFileIOException("Unknown Up vector");
261  }
262  return UpVector::Y_UP;
263 }
264 
266  if (model->getUpVector() == UpVector::Y_UP) {
267  // no op
268  } else
269  if (model->getUpVector() == UpVector::Z_UP) {
270  model->setImportTransformMatrix(model->getImportTransformMatrix().clone().setAxes(Vector3(1.0f, 0.0f, 0.0f), -90.0));
271  }
272 }
273 
274 void FBXReader::setupModelScaleRotationMatrix(FbxScene* fbxScene, Model* model) {
275  FbxSystemUnit fbxSceneSystemUnit = fbxScene->GetGlobalSettings().GetSystemUnit();
276  model->setImportTransformMatrix(model->getImportTransformMatrix().clone().scale(static_cast<float>(fbxSceneSystemUnit.GetConversionFactorTo(FbxSystemUnit::m))));
277 }
278 
279 void FBXReader::processScene(FbxScene* fbxScene, Model* model, const string& pathName, vector<string>& possibleArmatureNodeIds, bool useBC7TextureCompression) {
280  FbxNode* fbxNode = fbxScene->GetRootNode();
281  if (fbxNode == nullptr) return;
282  for(auto i = 0; i < fbxNode->GetChildCount(); i++) {
283  processNode(fbxNode->GetChild(i), model, nullptr, pathName, possibleArmatureNodeIds, useBC7TextureCompression);
284  }
285 }
286 
287 void FBXReader::processNode(FbxNode* fbxNode, Model* model, Node* parentNode, const string& pathName, vector<string>& possibleArmatureNodeIds, bool useBC7TextureCompression) {
288  unique_ptr<Node> node;
289  if (fbxNode->GetNodeAttribute() != nullptr) {
290  auto fbxAttributeType = fbxNode->GetNodeAttribute()->GetAttributeType();
291  switch (fbxAttributeType) {
292  case FbxNodeAttribute::eNull:
293  {
294  possibleArmatureNodeIds.push_back(fbxNode->GetName());
295  break;
296  }
297  case FbxNodeAttribute::eMesh:
298  {
299  node = unique_ptr<Node>(processMeshNode(fbxNode, model, parentNode, pathName, useBC7TextureCompression));
300  break;
301  }
302  case FbxNodeAttribute::eSkeleton:
303  {
304  node = unique_ptr<Node>(processSkeletonNode(fbxNode, model, parentNode, pathName));
305  break;
306  }
307  default:
308  {
309  break;
310  }
311  }
312  }
313  if (node == nullptr) {
314  auto fbxNodeName = fbxNode->GetName();
315  node = make_unique<Node>(model, parentNode, fbxNodeName, fbxNodeName);
316  }
317  FbxAMatrix& fbxNodeLocalTransform = fbxNode->EvaluateLocalTransform();
318  node->setTransformMatrix(
319  Matrix4x4(
320  fbxNodeLocalTransform.Get(0,0),
321  fbxNodeLocalTransform.Get(0,1),
322  fbxNodeLocalTransform.Get(0,2),
323  fbxNodeLocalTransform.Get(0,3),
324  fbxNodeLocalTransform.Get(1,0),
325  fbxNodeLocalTransform.Get(1,1),
326  fbxNodeLocalTransform.Get(1,2),
327  fbxNodeLocalTransform.Get(1,3),
328  fbxNodeLocalTransform.Get(2,0),
329  fbxNodeLocalTransform.Get(2,1),
330  fbxNodeLocalTransform.Get(2,2),
331  fbxNodeLocalTransform.Get(2,3),
332  fbxNodeLocalTransform.Get(3,0),
333  fbxNodeLocalTransform.Get(3,1),
334  fbxNodeLocalTransform.Get(3,2),
335  fbxNodeLocalTransform.Get(3,3)
336  )
337  );
338  if (parentNode == nullptr) {
339  model->getSubNodes()[node->getId()] = node.get();
340  } else {
341  parentNode->getSubNodes()[node->getId()] = node.get();
342  }
343  model->getNodes()[node->getId()] = node.get();
344  //
345  parentNode = node.release();
346  for(auto i = 0; i < fbxNode->GetChildCount(); i++) {
347  processNode(fbxNode->GetChild(i), model, parentNode, pathName, possibleArmatureNodeIds, useBC7TextureCompression);
348  }
349 }
350 
351 Node* FBXReader::processMeshNode(FbxNode* fbxNode, Model* model, Node* parentNode, const string& pathName, bool useBC7TextureCompression) {
352  string fbxNodeName = fbxNode->GetName();
353  FbxMesh* fbxMesh = (FbxMesh*)fbxNode->GetNodeAttribute();
354 
355  auto node = make_unique<Node>(model, parentNode, fbxNodeName, fbxNodeName);
356  vector<Vector3> vertices;
357  vector<Vector3> normals;
358  vector<Vector2> textureCoordinates;
359  vector<Vector3> tangents;
360  vector<Vector3> bitangents;
361  vector<FacesEntity> facesEntities;
362  vector<Face> faces;
363  FacesEntity* facesEntity = nullptr;
364 
365  auto fbxVertexId = 0;
366  auto fbxPolygonCount = fbxMesh->GetPolygonCount();
367 
368  FbxVector4* fbxControlPoints = fbxMesh->GetControlPoints();
369  for (auto i = 0; i < fbxMesh->GetControlPointsCount(); i++) {
370  auto fbxControlPoint = fbxControlPoints[i];
371  vertices.emplace_back(
372  static_cast<float>(fbxControlPoint[0]),
373  static_cast<float>(fbxControlPoint[1]),
374  static_cast<float>(fbxControlPoint[2])
375  );
376  }
377  for (auto l = 0; l < fbxMesh->GetElementUVCount() && l < 1; ++l) {
378  auto fbxUV = fbxMesh->GetElementUV(l);
379  for (int i = 0; i < fbxUV->GetDirectArray().GetCount(); i++) {
380  auto fbxUVArray = fbxUV->GetDirectArray().GetAt(i);
381  textureCoordinates.emplace_back(
382  static_cast<float>(fbxUVArray[0]),
383  static_cast<float>(1.0f - fbxUVArray[1])
384  );
385  }
386  }
387  for (auto l = 0; l < fbxMesh->GetElementNormalCount() && l < 1; ++l) {
388  auto fbxNormal = fbxMesh->GetElementNormal(l);
389  for (int i = 0; i < fbxNormal->GetDirectArray().GetCount(); i++) {
390  auto fbxNormalArray = fbxNormal->GetDirectArray().GetAt(i);
391  normals.emplace_back(
392  static_cast<float>(fbxNormalArray[0]),
393  static_cast<float>(fbxNormalArray[1]),
394  static_cast<float>(fbxNormalArray[2])
395  );
396  }
397  }
398  for (auto l = 0; l < fbxMesh->GetElementTangentCount() && l < 1; ++l) {
399  auto fbxTangent = fbxMesh->GetElementTangent(l);
400  for (int i = 0; i < fbxTangent->GetDirectArray().GetCount(); i++) {
401  auto fbxTangentArray = fbxTangent->GetDirectArray().GetAt(i);
402  tangents.emplace_back(
403  static_cast<float>(fbxTangentArray[0]),
404  static_cast<float>(fbxTangentArray[1]),
405  static_cast<float>(fbxTangentArray[2])
406  );
407  }
408  }
409  for (auto l = 0; l < fbxMesh->GetElementBinormalCount() && l < 1; ++l) {
410  auto fbxBinormal = fbxMesh->GetElementBinormal(l);
411  for (int i = 0; i < fbxBinormal->GetDirectArray().GetCount(); i++) {
412  auto fbxBinormalArray = fbxBinormal->GetDirectArray().GetAt(i);
413  bitangents.emplace_back(
414  static_cast<float>(fbxBinormalArray[0]),
415  static_cast<float>(fbxBinormalArray[1]),
416  static_cast<float>(fbxBinormalArray[2])
417  );
418  }
419  }
420 
421  for (auto i = 0; i < fbxPolygonCount; i++) {
422  FbxSurfaceMaterial* fbxMaterial = nullptr;
423  for (auto l = 0; l < fbxMesh->GetElementMaterialCount() & l < 1; l++) {
424  FbxGeometryElementMaterial* fbxMaterialElement = fbxMesh->GetElementMaterial(l);
425  if (fbxMaterialElement->GetMappingMode() == FbxGeometryElement::eAllSame) {
426  fbxMaterial = fbxMesh->GetNode()->GetMaterial(fbxMaterialElement->GetIndexArray().GetAt(0));
427  } else {
428  fbxMaterial = fbxMesh->GetNode()->GetMaterial(fbxMaterialElement->GetIndexArray().GetAt(i));
429  }
430  }
431  Material* material = nullptr;
432  if (fbxMaterial == nullptr) {
433  material = model->getMaterials()["fbx.nomaterial"];
434  if (material == nullptr) {
435  auto newMaterial = make_unique<Material>("fbx.nomaterial");
436  model->getMaterials()[newMaterial->getId()] = newMaterial.get();
437  material = newMaterial.release();
438  }
439  } else {
440  string fbxMaterialName = fbxMaterial->GetName();
441  material = model->getMaterials()[fbxMaterialName];
442  if (material == nullptr) {
443  auto newMaterial = make_unique<Material>(fbxMaterialName);
444  auto specularMaterialProperties = make_unique<SpecularMaterialProperties>();
445  if (fbxMaterial->GetClassId().Is(FbxSurfacePhong::ClassId)) {
446  FbxPropertyT<FbxDouble3> fbxColor3;
447  FbxPropertyT<FbxDouble> fbxTransparency;
448  FbxPropertyT<FbxDouble> fbxFactor;
449  FbxPropertyT<FbxDouble> fbxShininess;
450  FbxPropertyT<FbxDouble> fbxShininessFactor;
451  FbxPropertyT<FbxDouble> fbxReflection;
452  fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Ambient;
453  fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->AmbientFactor;
454  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true) {
455  specularMaterialProperties->setAmbientColor(
456  Color4(
457  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
458  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
459  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
460  1.0f
461  )
462  );
463  }
464  fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Diffuse;
465  fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->DiffuseFactor;
466  fbxTransparency = ((FbxSurfacePhong*)fbxMaterial)->TransparencyFactor;
467  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true && fbxTransparency.IsValid() == true) {
468  specularMaterialProperties->setDiffuseColor(
469  Color4(
470  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
471  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
472  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
473  // TODO: I am not sure about this here, but it seem to work
474  (
475  1.0f - static_cast<float>(fbxTransparency) < Math::EPSILON?
476  1.0f:
477  1.0f - static_cast<float>(fbxTransparency)
478  )
479  )
480  );
481  }
482  fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Emissive;
483  fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->EmissiveFactor;
484  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true) {
485  specularMaterialProperties->setEmissionColor(
486  Color4(
487  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
488  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
489  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
490  1.0f
491  )
492  );
493  }
494  fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Specular;
495  fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->SpecularFactor;
496  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true) {
497  specularMaterialProperties->setSpecularColor(
498  Color4(
499  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
500  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
501  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
502  1.0f
503  )
504  );
505  }
506  fbxShininess = ((FbxSurfacePhong*)fbxMaterial)->Shininess;
507  if (fbxShininess.IsValid() == true && fbxShininessFactor.IsValid() == true) {
508  specularMaterialProperties->setShininess(static_cast<float>(fbxShininess.Get()));
509  }
510  fbxReflection = ((FbxSurfacePhong*)fbxMaterial)->Reflection;
511  fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->ReflectionFactor;
512  if (fbxReflection.IsValid() == true && fbxFactor.IsValid() == true) {
513  specularMaterialProperties->setReflection(static_cast<float>(fbxReflection.Get() * fbxFactor.Get()));
514  }
515  } else
516  if (fbxMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId)) {
517  FbxPropertyT<FbxDouble3> fbxColor3;
518  FbxPropertyT<FbxDouble> fbxTransparency;
519  FbxPropertyT<FbxDouble> fbxFactor;
520  fbxColor3 = ((FbxSurfaceLambert*)fbxMaterial)->Ambient;
521  fbxFactor = ((FbxSurfaceLambert*)fbxMaterial)->AmbientFactor;
522  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true) {
523  specularMaterialProperties->setAmbientColor(
524  Color4(
525  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
526  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
527  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
528  1.0f
529  )
530  );
531  }
532  fbxColor3 = ((FbxSurfaceLambert*)fbxMaterial)->Diffuse;
533  fbxFactor = ((FbxSurfaceLambert*)fbxMaterial)->DiffuseFactor;
534  fbxTransparency = ((FbxSurfaceLambert*)fbxMaterial)->TransparencyFactor;
535  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true && fbxTransparency.IsValid() == true)
536  specularMaterialProperties->setDiffuseColor(
537  Color4(
538  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
539  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
540  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
541  // TODO: I am not sure about this here, but it seem to work
542  (
543  1.0f - static_cast<float>(fbxTransparency) < Math::EPSILON?
544  1.0f:
545  1.0f - static_cast<float>(fbxTransparency)
546  )
547  )
548  );
549  fbxColor3 = ((FbxSurfaceLambert*)fbxMaterial)->Emissive;
550  fbxFactor = ((FbxSurfaceLambert*)fbxMaterial)->EmissiveFactor;
551  if (fbxColor3.IsValid() == true && fbxFactor.IsValid() == true) {
552  specularMaterialProperties->setEmissionColor(
553  Color4(
554  static_cast<float>(fbxColor3.Get()[0] * fbxFactor.Get()),
555  static_cast<float>(fbxColor3.Get()[1] * fbxFactor.Get()),
556  static_cast<float>(fbxColor3.Get()[2] * fbxFactor.Get()),
557  1.0f
558  )
559  );
560  }
561  } else {
562  Console::println("FBXReader::processMeshNode(): unsupported material shading class: " + fbxMaterialName);
563  }
564  FbxProperty fbxProperty;
565  fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sDiffuse);
566  string diffuseTextureFileName;
567  {
568  if (fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() > 0) {
569  auto texture = FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0));
570  diffuseTextureFileName = texture->GetFileName();
571  Matrix3x3 textureMatrix;
572  textureMatrix.identity();
573  textureMatrix.multiply(Matrix3x3().identity().scale(Vector2(texture->GetScaleU(), texture->GetScaleV())));
574  // TODO: not sure about texture rotation with 2D textures here and I have no test model for now
575  textureMatrix.multiply(Matrix3x3::rotateAroundTextureCenter(texture->GetRotationU()));
576  textureMatrix.multiply(Matrix3x3().identity().setTranslation(Vector2(texture->GetTranslationU(), texture->GetTranslationV())));
577  newMaterial->setTextureMatrix(textureMatrix);
578  } else
579  if (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0) {
580  auto texture = FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0));
581  diffuseTextureFileName = texture->GetFileName();
582  Matrix3x3 textureMatrix;
583  textureMatrix.identity();
584  textureMatrix.multiply(Matrix3x3().identity().scale(Vector2(texture->GetScaleU(), texture->GetScaleV())));
585  // TODO: not sure about texture rotation with 2D textures here and I have no test model for now
586  textureMatrix.multiply(Matrix3x3::rotateAroundTextureCenter(texture->GetRotationU()));
587  textureMatrix.multiply(Matrix3x3().identity().setTranslation(Vector2(texture->GetTranslationU(), texture->GetTranslationV())));
588  newMaterial->setTextureMatrix(textureMatrix);
589  }
590  }
591  fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sTransparentColor);
592  string diffuseTransparencyTextureFileName =
593  fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() == 0?
594  (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0?
595  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0))->GetFileName():
596  ""
597  ):
598  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0))->GetFileName();
599  if (diffuseTransparencyTextureFileName.length() == 0) {
600  fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sTransparencyFactor);
601  diffuseTransparencyTextureFileName =
602  fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() == 0?
603  (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0?
604  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0))->GetFileName():
605  ""
606  ):
607  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0))->GetFileName();
608  }
609  if (diffuseTextureFileName.length() > 0) {
610  specularMaterialProperties->setDiffuseTexture(
611  FileSystem::getInstance()->exists(
612  FileSystem::getInstance()->composeURI(pathName, FileSystem::getInstance()->getFileName(diffuseTextureFileName))
613  )?pathName:FileSystem::getInstance()->getPathName(diffuseTextureFileName),
614  FileSystem::getInstance()->getFileName(diffuseTextureFileName),
615  FileSystem::getInstance()->exists(
616  FileSystem::getInstance()->composeURI(pathName, FileSystem::getInstance()->getFileName(diffuseTransparencyTextureFileName))
617  )?pathName:FileSystem::getInstance()->getPathName(diffuseTransparencyTextureFileName),
618  FileSystem::getInstance()->getFileName(diffuseTransparencyTextureFileName)
619  );
620  if (specularMaterialProperties->getDiffuseTexture() != nullptr) specularMaterialProperties->getDiffuseTexture()->setUseCompression(useBC7TextureCompression);
621  if (specularMaterialProperties->hasDiffuseTextureTransparency() == true) specularMaterialProperties->setDiffuseTextureMaskedTransparency(true);
622  }
623  fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sNormalMap);
624  string normalTextureFileName =
625  fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() == 0?
626  (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0?
627  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0))->GetFileName():
628  ""
629  ):
630  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0))->GetFileName();
631  if (normalTextureFileName.length() > 0) {
632  specularMaterialProperties->setNormalTexture(
633  FileSystem::getInstance()->exists(
634  FileSystem::getInstance()->composeURI(pathName, FileSystem::getInstance()->getFileName(normalTextureFileName))
635  )?pathName:FileSystem::getInstance()->getPathName(normalTextureFileName),
636  FileSystem::getInstance()->getFileName(normalTextureFileName)
637  );
638  if (specularMaterialProperties->getNormalTexture() != nullptr) specularMaterialProperties->getNormalTexture()->setUseCompression(useBC7TextureCompression);
639  }
640  fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sSpecular);
641  string specularTextureFileName =
642  fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() == 0?
643  (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0?
644  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0))->GetFileName():
645  ""
646  ):
647  FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0))->GetFileName();
648  if (specularTextureFileName.length() > 0) {
649  specularMaterialProperties->setSpecularTexture(
650  FileSystem::getInstance()->exists(
651  FileSystem::getInstance()->composeURI(pathName, FileSystem::getInstance()->getFileName(specularTextureFileName))
652  )?pathName:FileSystem::getInstance()->getPathName(specularTextureFileName),
653  FileSystem::getInstance()->getFileName(specularTextureFileName)
654  );
655  if (specularMaterialProperties->getSpecularTexture() != nullptr) specularMaterialProperties->getSpecularTexture()->setUseCompression(useBC7TextureCompression);
656  }
657  // adjust ambient light with blender
658  if (model->getAuthoringTool() == Model::AUTHORINGTOOL_BLENDER && specularMaterialProperties->getAmbientColor().equals(BLENDER_AMBIENT_NONE)) {
659  specularMaterialProperties->setAmbientColor(
660  Color4(
661  specularMaterialProperties->getDiffuseColor().getRed() * BLENDER_AMBIENT_FROM_DIFFUSE_SCALE,
662  specularMaterialProperties->getDiffuseColor().getGreen() * BLENDER_AMBIENT_FROM_DIFFUSE_SCALE,
663  specularMaterialProperties->getDiffuseColor().getBlue() * BLENDER_AMBIENT_FROM_DIFFUSE_SCALE,
664  1.0f
665  )
666  );
667  specularMaterialProperties->setDiffuseColor(
668  Color4(
669  specularMaterialProperties->getDiffuseColor().getRed() * BLENDER_DIFFUSE_SCALE,
670  specularMaterialProperties->getDiffuseColor().getGreen() * BLENDER_DIFFUSE_SCALE,
671  specularMaterialProperties->getDiffuseColor().getBlue() * BLENDER_DIFFUSE_SCALE,
672  specularMaterialProperties->getDiffuseColor().getAlpha()
673  )
674  );
675  }
676  newMaterial->setSpecularMaterialProperties(specularMaterialProperties.release());
677  model->getMaterials()[newMaterial->getId()] = newMaterial.get();
678  //
679  material = newMaterial.release();
680  }
681  }
682  auto foundFacesEntity = false;
683  auto facesEntityName = "facesentity-" + material->getId();
684  for (auto& facesEntityLookUp: facesEntities) {
685  if (facesEntityLookUp.getId() == facesEntityName) {
686  if (&facesEntityLookUp != facesEntity) {
687  if (facesEntity != nullptr) {
688  facesEntity->setFaces(faces);
689  }
690  faces = facesEntityLookUp.getFaces();
691  facesEntity = &facesEntityLookUp;
692  }
693  foundFacesEntity = true;
694  break;
695  }
696  }
697  if (foundFacesEntity == false) {
698  if (facesEntity != nullptr) {
699  facesEntity->setFaces(faces);
700  faces.clear();
701  }
702  facesEntities.emplace_back(node.get(), facesEntityName);
703  facesEntity = &facesEntities[facesEntities.size() - 1];
704  facesEntity->setMaterial(material);
705  }
706  auto fbxPolygonSize = fbxMesh->GetPolygonSize(i);
707  if (fbxPolygonSize != 3) throw ModelFileIOException("we only support triangles in '" + node->getName() + "'");
708  auto controlPointIndicesIdx = 0;
709  array<int, 3> controlPointIndices;
710  int textureCoordinateIndicesIdx = 0;
711  array<int, 3> textureCoordinateIndices;
712  int normalIndicesIdx = 0;
713  array<int, 3> normalIndices;
714  int tangentIndicesIdx = 0;
715  array<int, 3> tangentIndices;
716  int binormalIndicesIdx = 0;
717  array<int, 3> binormalIndices;
718  for (auto j = 0; j < fbxPolygonSize; j++) {
719  int fbxControlPointIndex = fbxMesh->GetPolygonVertex(i, j);
720  controlPointIndices[controlPointIndicesIdx++] = fbxControlPointIndex;
721  for (auto l = 0; l < fbxMesh->GetElementUVCount() && l < 1; ++l) {
722  FbxGeometryElementUV* fbxUV = fbxMesh->GetElementUV(l);
723  switch (fbxUV->GetMappingMode()) {
724  case FbxGeometryElement::eByControlPoint:
725  switch (fbxUV->GetReferenceMode()) {
726  case FbxGeometryElement::eDirect:
727  {
728  textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxControlPointIndex;
729  break;
730  }
731  case FbxGeometryElement::eIndexToDirect:
732  {
733  textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxUV->GetIndexArray().GetAt(fbxControlPointIndex);
734  break;
735  }
736  default:
737  break;
738  }
739  break;
740  case FbxGeometryElement::eByPolygonVertex:
741  {
742  switch (fbxUV->GetReferenceMode()) {
743  case FbxGeometryElement::eDirect:
744  case FbxGeometryElement::eIndexToDirect:
745  {
746  textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxMesh->GetTextureUVIndex(i, j);
747  break;
748  }
749  default:
750  break;
751  }
752  break;
753  }
754  default:
755  break;
756  }
757  }
758  for (auto l = 0; l < fbxMesh->GetElementNormalCount() && l < 1; ++l) {
759  FbxGeometryElementNormal* fbxNormal = fbxMesh->GetElementNormal(l);
760  if (fbxNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
761  switch (fbxNormal->GetReferenceMode()) {
762  case FbxGeometryElement::eDirect:
763  {
764  normalIndices[normalIndicesIdx++] = fbxVertexId;
765  break;
766  }
767  case FbxGeometryElement::eIndexToDirect:
768  {
769  normalIndices[normalIndicesIdx++] = fbxNormal->GetIndexArray().GetAt(fbxVertexId);
770  break;
771  }
772  default:
773  break;
774  }
775  } else {
776  }
777  }
778  for (auto l = 0; l < fbxMesh->GetElementTangentCount() && l < 1; ++l) {
779  FbxGeometryElementTangent* fbxTangent = fbxMesh->GetElementTangent(l);
780  if (fbxTangent->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
781  switch (fbxTangent->GetReferenceMode()) {
782  case FbxGeometryElement::eDirect:
783  {
784  tangentIndices[tangentIndicesIdx++] = fbxVertexId;
785  break;
786  }
787  case FbxGeometryElement::eIndexToDirect:
788  {
789  tangentIndices[tangentIndicesIdx++] = fbxTangent->GetIndexArray().GetAt(fbxVertexId);
790  break;
791  }
792  default:
793  break;
794  }
795  }
796  }
797  for (auto l = 0; l < fbxMesh->GetElementBinormalCount() && l < 1; ++l) {
798  FbxGeometryElementBinormal* fbxBinormal = fbxMesh->GetElementBinormal(l);
799  if (fbxBinormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
800  switch (fbxBinormal->GetReferenceMode()) {
801  case FbxGeometryElement::eDirect:
802  {
803  binormalIndices[binormalIndicesIdx++] = fbxVertexId;
804  break;
805  }
806  case FbxGeometryElement::eIndexToDirect:
807  {
808  binormalIndices[binormalIndicesIdx++] = fbxBinormal->GetIndexArray().GetAt(fbxVertexId);
809  break;
810  }
811  default:
812  break;
813  }
814  }
815  }
816  fbxVertexId++;
817  }
818  Face f(
819  node.get(),
820  controlPointIndices[0],
821  controlPointIndices[1],
822  controlPointIndices[2],
823  normalIndices[0],
824  normalIndices[1],
825  normalIndices[2]
826  );
827  if (textureCoordinateIndicesIdx == 3) {
829  textureCoordinateIndices[0],
830  textureCoordinateIndices[1],
831  textureCoordinateIndices[2]
832  );
833  }
834  if (tangentIndicesIdx == 3 && binormalIndicesIdx == 3) {
836  tangentIndices[0],
837  tangentIndices[1],
838  tangentIndices[2]
839  );
841  binormalIndices[0],
842  binormalIndices[1],
843  binormalIndices[2]
844  );
845  }
846  faces.push_back(f);
847  }
848  if (facesEntity != nullptr) {
849  facesEntity->setFaces(faces);
850  }
851 
852  node->setVertices(vertices);
853  node->setNormals(normals);
854  if (tangents.size() > 0 && bitangents.size() > 0) {
855  node->setTangents(tangents);
856  node->setBitangents(bitangents);
857  }
858  if (textureCoordinates.size() > 0) node->setTextureCoordinates(textureCoordinates);
859  node->setFacesEntities(facesEntities);
860 
861  int fbxSkinCount = fbxNode->GetMesh()->GetDeformerCount(FbxDeformer::eSkin);
862  if (fbxSkinCount == 0) {
863  // no op
864  } else
865  if (fbxSkinCount == 1) {
866  FbxSkin* fbxSkinDeformer = (FbxSkin*)fbxNode->GetMesh()->GetDeformer(0, FbxDeformer::eSkin);
867  auto fbxClusterCount = fbxSkinDeformer->GetClusterCount();
868  auto skinning = make_unique<Skinning>();
869  vector<Joint> joints;
870  vector<float> weights;
871  map<int, vector<JointWeight>> jointWeightsByVertices;
872  for (auto fbxClusterIndex = 0; fbxClusterIndex < fbxClusterCount; fbxClusterIndex++) {
873  FbxCluster* fbxCluster = fbxSkinDeformer->GetCluster(fbxClusterIndex);
874  if (fbxCluster->GetLink() == nullptr) continue;
875  auto fbxJointName = fbxCluster->GetLink()->GetName();
876  auto jointIndex = joints.size();
877  FbxAMatrix transformMatrix;
878  FbxAMatrix transformLinkMatrix;
879  fbxCluster->GetTransformMatrix(transformMatrix);
880  fbxCluster->GetTransformLinkMatrix(transformLinkMatrix);
881  Joint joint(fbxJointName);
882  Matrix4x4 bindMatrix;
883  bindMatrix.set(
884  Matrix4x4(
885  transformMatrix.Get(0,0),
886  transformMatrix.Get(0,1),
887  transformMatrix.Get(0,2),
888  transformMatrix.Get(0,3),
889  transformMatrix.Get(1,0),
890  transformMatrix.Get(1,1),
891  transformMatrix.Get(1,2),
892  transformMatrix.Get(1,3),
893  transformMatrix.Get(2,0),
894  transformMatrix.Get(2,1),
895  transformMatrix.Get(2,2),
896  transformMatrix.Get(2,3),
897  transformMatrix.Get(3,0),
898  transformMatrix.Get(3,1),
899  transformMatrix.Get(3,2),
900  transformMatrix.Get(3,3)
901  )
902  );
903  bindMatrix.multiply(
904  Matrix4x4(
905  transformLinkMatrix.Get(0,0),
906  transformLinkMatrix.Get(0,1),
907  transformLinkMatrix.Get(0,2),
908  transformLinkMatrix.Get(0,3),
909  transformLinkMatrix.Get(1,0),
910  transformLinkMatrix.Get(1,1),
911  transformLinkMatrix.Get(1,2),
912  transformLinkMatrix.Get(1,3),
913  transformLinkMatrix.Get(2,0),
914  transformLinkMatrix.Get(2,1),
915  transformLinkMatrix.Get(2,2),
916  transformLinkMatrix.Get(2,3),
917  transformLinkMatrix.Get(3,0),
918  transformLinkMatrix.Get(3,1),
919  transformLinkMatrix.Get(3,2),
920  transformLinkMatrix.Get(3,3)
921  ).invert()
922  );
923  joint.setBindMatrix(bindMatrix);
924  joints.push_back(joint);
925  auto fbxClusterControlPointIndexCount = fbxCluster->GetControlPointIndicesCount();
926  auto fbxClusterControlPointIndices = fbxCluster->GetControlPointIndices();
927  for (auto fbxClusterControlPointIndex = 0; fbxClusterControlPointIndex < fbxClusterControlPointIndexCount; fbxClusterControlPointIndex++) {
928  auto fbxControlPointIndex = fbxClusterControlPointIndices[fbxClusterControlPointIndex];
929  auto weightIndex = weights.size();
930  weights.push_back(fbxCluster->GetControlPointWeights()[fbxClusterControlPointIndex]);
931  jointWeightsByVertices[fbxControlPointIndex].emplace_back(
932  static_cast<int32_t>(jointIndex),
933  static_cast<int32_t>(weightIndex)
934  );
935  }
936  }
937  skinning->setJoints(joints);
938  skinning->setWeights(weights);
939  vector<vector<JointWeight>> verticesJointsWeights;
940  for (auto vertexIndex = 0; vertexIndex < vertices.size(); vertexIndex++) {
941  verticesJointsWeights.emplace_back();
942  auto jointWeightsByVerticesIt = jointWeightsByVertices.find(vertexIndex);
943  if (jointWeightsByVerticesIt != jointWeightsByVertices.end()) {
944  for (const auto& jointWeight: jointWeightsByVerticesIt->second) {
945  verticesJointsWeights[verticesJointsWeights.size() - 1].push_back(jointWeight);
946  }
947  }
948  }
949  skinning->setVerticesJointsWeights(verticesJointsWeights);
950  node->setSkinning(skinning.release());
951  } else {
952  Console::println("FBXReader::processMeshNode(): " + to_string(fbxSkinCount) + " skins per mesh: Not supported");
953  }
954  //
955  return node.release();
956 }
957 
958 Node* FBXReader::processSkeletonNode(FbxNode* fbxNode, Model* model, Node* parentNode, const string& pathName) {
959  return make_unique<Node>(model, parentNode, fbxNode->GetName(), fbxNode->GetName()).release();
960 }
961 
962 void FBXReader::processAnimation(FbxNode* fbxNode, const FbxTime& fbxStartFrame, const FbxTime& fbxEndFrame, Model* model, int frameOffset) {
963  auto fbxNodeName = fbxNode->GetName();
964  auto node = model->getNodeById(fbxNodeName);
965  auto animation = node->getAnimation();
966  if (node->getAnimation() == nullptr) node->setAnimation(new Animation());
967  auto transformMatrices = node->getAnimation()->getTransformMatrices();
968  transformMatrices.resize(model->getAnimationSetup(Model::ANIMATIONSETUP_DEFAULT)->getFrames());
969  FbxTime fbxFrameTime;
970  fbxFrameTime.SetMilliSeconds(1000.0f * 1.0f / 30.0f);
971  for(auto i = fbxStartFrame; i < fbxEndFrame; i+= fbxFrameTime) {
972  FbxAMatrix& fbxTransformMatrix = fbxNode->EvaluateLocalTransform(i);
973  auto frameIdx = frameOffset + (int)Math::ceil((i.GetMilliSeconds() - fbxStartFrame.GetMilliSeconds()) / (1000.0f * 1.0f / 30.0f));
974  transformMatrices[frameIdx].set(
975  fbxTransformMatrix.Get(0,0),
976  fbxTransformMatrix.Get(0,1),
977  fbxTransformMatrix.Get(0,2),
978  fbxTransformMatrix.Get(0,3),
979  fbxTransformMatrix.Get(1,0),
980  fbxTransformMatrix.Get(1,1),
981  fbxTransformMatrix.Get(1,2),
982  fbxTransformMatrix.Get(1,3),
983  fbxTransformMatrix.Get(2,0),
984  fbxTransformMatrix.Get(2,1),
985  fbxTransformMatrix.Get(2,2),
986  fbxTransformMatrix.Get(2,3),
987  fbxTransformMatrix.Get(3,0),
988  fbxTransformMatrix.Get(3,1),
989  fbxTransformMatrix.Get(3,2),
990  fbxTransformMatrix.Get(3,3)
991  );
992  }
993  node->getAnimation()->setTransformMatrices(transformMatrices);
994  for(auto i = 0; i < fbxNode->GetChildCount(); i++) {
995  processAnimation(fbxNode->GetChild(i), fbxStartFrame, fbxEndFrame, model, frameOffset);
996  }
997 }
Color 4 definition class.
Definition: Color4.h:18
Texture entity.
Definition: Texture.h:24
static void processScene(FbxScene *fbxScene, Model *model, const string &pathName, vector< string > &possibleArmatureNodeIds, bool useBC7TextureCompression)
Process FBX scene.
Definition: FBXReader.cpp:279
static constexpr float BLENDER_AMBIENT_FROM_DIFFUSE_SCALE
Definition: FBXReader.h:203
static void processNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName, vector< string > &possibleArmatureNodeIds, bool useBC7TextureCompression)
Process FBX node.
Definition: FBXReader.cpp:287
static UpVector * getSceneUpVector(FbxScene *fbxScene)
Get scene up vector.
Definition: FBXReader.cpp:249
static Node * processSkeletonNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName)
Process FBX skeleton node.
Definition: FBXReader.cpp:958
static constexpr float BLENDER_DIFFUSE_SCALE
Definition: FBXReader.h:204
static Node * processMeshNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName, bool useBC7TextureCompression)
Process FBX mesh node.
Definition: FBXReader.cpp:351
static STATIC_DLL_IMPEXT const Color4 BLENDER_AMBIENT_NONE
Definition: FBXReader.h:202
static void setupModelScaleRotationMatrix(FbxScene *fbxScene, Model *model)
Set up model import scale maxtrix.
Definition: FBXReader.cpp:274
static void setupModelImportRotationMatrix(Model *model)
Set up model import rotation maxtrix.
Definition: FBXReader.cpp:265
static RotationOrder * getSceneRotationOrder(FbxScene *fbxScene)
Get scene rotation order.
Definition: FBXReader.cpp:228
static void processAnimation(FbxNode *fbxNode, const FbxTime &fbxStartFrame, const FbxTime &fbxEndFrame, Model *model, int frameOffset)
Process animation.
Definition: FBXReader.cpp:962
const vector< Matrix4x4 > & getTransformMatrices() const
Returns transform matrices.
Definition: Animation.h:43
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
Definition: Face.h:18
void setTextureCoordinateIndices(int32_t vt0, int32_t vt1, int32_t vt2)
Set up optional texture coordinate indices.
Definition: Face.cpp:45
void setTangentIndices(int32_t ti0, int32_t ti1, int32_t ti2)
Set tangent indices.
Definition: Face.cpp:52
void setBitangentIndices(int32_t bi0, int32_t bi1, int32_t bi2)
Set bitangent indices.
Definition: Face.cpp:59
Node faces entity A node can have multiple entities containing faces and a applied material.
Definition: FacesEntity.h:23
void setMaterial(Material *material)
Set up the entity's material.
Definition: FacesEntity.h:67
void setFaces(const vector< Face > &faces)
Set up entity's faces.
Definition: FacesEntity.cpp:43
Joint / Bone.
Definition: Joint.h:19
void setBindMatrix(const Matrix4x4 &bindMatrix)
Bind matrix.
Definition: Joint.h:56
Represents a material.
Definition: Material.h:23
const string & getId() const
Definition: Material.h:57
Representation of a 3D model.
Definition: Model.h:35
unordered_map< string, Node * > & getSubNodes()
Returns object's sub nodes.
Definition: Model.h:220
unordered_map< string, Material * > & getMaterials()
Returns all object materials.
Definition: Model.h:185
void setImportTransformMatrix(const Matrix4x4 &importTransformMatrix)
Set import transform matrix.
Definition: Model.h:348
AnimationSetup * getAnimationSetup(const string &id)
Definition: Model.h:274
AuthoringTool getAuthoringTool()
Definition: Model.h:114
const Matrix4x4 & getImportTransformMatrix()
Definition: Model.h:340
unordered_map< string, Node * > & getNodes()
Returns all object's nodes.
Definition: Model.h:199
UpVector * getUpVector()
Definition: Model.h:142
Node * getNodeById(const string &id)
Returns a node by given name or null.
Definition: Model.h:208
Model node.
Definition: Node.h:32
unordered_map< string, Node * > & getSubNodes()
Definition: Node.h:293
Animation * getAnimation()
Definition: Node.h:229
Represents rotation orders of a model.
Definition: RotationOrder.h:23
Skinning definition for nodes.
Definition: Skinning.h:25
Represents specular material properties.
Model up vector.
Definition: UpVector.h:20
Standard math functions.
Definition: Math.h:19
Matrix3x3 class representing matrix3x3 mathematical structure and operations for 2d space.
Definition: Matrix3x3.h:20
Matrix3x3 & identity()
Creates identity matrix.
Definition: Matrix3x3.h:128
Matrix3x3 & multiply(const Matrix3x3 &matrix)
Multiplies this matrix with given matrix.
Definition: Matrix3x3.h:176
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Matrix4x4 clone() const
Clones this matrix.
Definition: Matrix4x4.h:619
Matrix4x4 & scale(float scalar)
Scales by scalar.
Definition: Matrix4x4.h:183
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
Definition: Matrix4x4.h:225
Matrix4x4 & set(float r0c0, float r0c1, float r0c2, float r0c3, float r1c0, float r1c1, float r1c2, float r1c3, float r2c0, float r2c1, float r2c2, float r2c3, float r3c0, float r3c1, float r3c2, float r3c3)
Sets this matrix by its components.
Definition: Matrix4x4.h:108
Matrix4x4 & invert()
Inverts this matrix.
Definition: Matrix4x4.h:479
Matrix4x4 & setAxes(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis)
Set coordinate system axes.
Definition: Matrix4x4.h:334
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
File system singleton class.
Definition: FileSystem.h:17
Base class of buffers.
Definition: Buffer.h:21
Console class.
Definition: Console.h:29
Model tools functions class.
Definition: ModelTools.h:42
String tools class.
Definition: StringTools.h:22