38 using std::make_unique;
42 using std::unique_ptr;
69 const Color4 FBXReader::BLENDER_AMBIENT_NONE(0.0f, 0.0f, 0.0f, 1.0f);
71 Model* FBXReader::read(
const string& pathName,
const string& fileName,
bool useBC7TextureCompression) {
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.");
78 Console::println(
string(
"FBXReader::read(): Autodesk FBX SDK version ") +
string(fbxManager->GetVersion()));
81 Console::println(
"FBXReader::read(): reading FBX scene");
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) {
93 auto fbxImporter = unique_ptr<FbxImporter, decltype([](FbxImporter* fbxImporter){ fbxImporter->Destroy(); })>(FbxImporter::Create(fbxManager.get(),
""));
95 vector<uint8_t> fbxData;
96 FileSystem::getInstance()->getContent(pathName, fileName, fbxData);
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);
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");
110 Console::println(
"FBXReader::read(): Authoring program: " +
string(fbxScene->GetDocumentInfo()->Original_ApplicationName.Get().Buffer()));
113 Console::println(
"FBXReader::read(): triangulating FBX");
115 FbxGeometryConverter fbxGeometryConverter(fbxManager.get());
116 fbxGeometryConverter.Triangulate(fbxScene.get(),
true);
118 Console::println(
"FBXReader::read(): importing FBX");
121 auto model = make_unique<Model>(
127 string(fbxScene->GetDocumentInfo()->Original_ApplicationName.Get().Buffer()).find(
"Blender") != -1?
128 Model::AUTHORINGTOOL_BLENDER:
129 Model::AUTHORINGTOOL_UNKNOWN
137 vector<string> possibleArmatureNodeIds;
140 processScene(fbxScene.get(), model.get(), pathName, possibleArmatureNodeIds, useBC7TextureCompression);
143 Console::println(
"FBXReader::read(): setting up animations");
146 FbxTime::SetGlobalTimeMode(FbxTime::eCustom, 30.0);
147 FbxArray<FbxString*> fbxAnimStackNameArray;
148 fbxScene->FillAnimStackNameArray(fbxAnimStackNameArray);
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();
157 FbxTimeSpan fbxTimeLineTimeSpan;
158 fbxScene->GetGlobalSettings().GetTimelineDefaultTimeSpan(fbxTimeLineTimeSpan);
159 fbxStartTime = fbxTimeLineTimeSpan.GetStart();
160 fbxEndTime = fbxTimeLineTimeSpan.GetStop();
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;
166 model->addAnimationSetup(
167 Model::ANIMATIONSETUP_DEFAULT,
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();
181 FbxTimeSpan fbxTimeLineTimeSpan;
182 fbxScene->GetGlobalSettings().GetTimelineDefaultTimeSpan(fbxTimeLineTimeSpan);
183 fbxStartTime = fbxTimeLineTimeSpan.GetStart();
184 fbxEndTime = fbxTimeLineTimeSpan.GetStop();
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());
197 model->addAnimationSetup(
199 frameOffset + startFrame,
200 frameOffset + endFrame,
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);
209 frameOffset+= endFrame - startFrame + 1;
211 FbxArrayDelete(fbxAnimStackNameArray);
214 Console::println(
"FBXReader::read(): destroying FBX SDK");
215 Console::println(
"FBXReader::read(): prepare for indexed rendering");
218 ModelTools::setupJoints(model.get());
219 ModelTools::fixAnimationLength(model.get());
220 ModelTools::prepareForIndexedRendering(model.get());
222 Console::println(
"FBXReader::read(): done");
225 return model.release();
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;
239 if (upVector == UpVector::Z_UP) {
240 return RotationOrder::YZX;
245 throw ModelFileIOException(
"Not supported rotation order(" + to_string(fbxRotationOrder) +
")");
251 auto fbxUpVector = fbxScene->GetGlobalSettings().GetAxisSystem().GetUpVector(fbxUpVectorSign);
252 switch (fbxUpVector) {
253 case FbxAxisSystem::eXAxis:
255 case FbxAxisSystem::eYAxis:
256 return UpVector::Y_UP;
257 case FbxAxisSystem::eZAxis:
258 return UpVector::Z_UP;
262 return UpVector::Y_UP;
275 FbxSystemUnit fbxSceneSystemUnit = fbxScene->GetGlobalSettings().GetSystemUnit();
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);
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:
294 possibleArmatureNodeIds.push_back(fbxNode->GetName());
297 case FbxNodeAttribute::eMesh:
299 node = unique_ptr<Node>(
processMeshNode(fbxNode, model, parentNode, pathName, useBC7TextureCompression));
302 case FbxNodeAttribute::eSkeleton:
313 if (node ==
nullptr) {
314 auto fbxNodeName = fbxNode->GetName();
315 node = make_unique<Node>(model, parentNode, fbxNodeName, fbxNodeName);
317 FbxAMatrix& fbxNodeLocalTransform = fbxNode->EvaluateLocalTransform();
318 node->setTransformMatrix(
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)
338 if (parentNode ==
nullptr) {
341 parentNode->
getSubNodes()[node->getId()] = node.get();
343 model->
getNodes()[node->getId()] = node.get();
345 parentNode = node.release();
346 for(
auto i = 0; i < fbxNode->GetChildCount(); i++) {
347 processNode(fbxNode->GetChild(i), model, parentNode, pathName, possibleArmatureNodeIds, useBC7TextureCompression);
352 string fbxNodeName = fbxNode->GetName();
353 FbxMesh* fbxMesh = (FbxMesh*)fbxNode->GetNodeAttribute();
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;
365 auto fbxVertexId = 0;
366 auto fbxPolygonCount = fbxMesh->GetPolygonCount();
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])
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])
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])
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])
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])
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));
428 fbxMaterial = fbxMesh->GetNode()->GetMaterial(fbxMaterialElement->GetIndexArray().GetAt(i));
432 if (fbxMaterial ==
nullptr) {
434 if (material ==
nullptr) {
435 auto newMaterial = make_unique<Material>(
"fbx.nomaterial");
436 model->
getMaterials()[newMaterial->getId()] = newMaterial.get();
437 material = newMaterial.release();
440 string fbxMaterialName = fbxMaterial->GetName();
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(
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()),
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(
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()),
475 1.0f -
static_cast<float>(fbxTransparency) < Math::EPSILON?
477 1.0f -
static_cast<float>(fbxTransparency)
482 fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Emissive;
483 fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->EmissiveFactor;
484 if (fbxColor3.IsValid() ==
true && fbxFactor.IsValid() ==
true) {
485 specularMaterialProperties->setEmissionColor(
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()),
494 fbxColor3 = ((FbxSurfacePhong*)fbxMaterial)->Specular;
495 fbxFactor = ((FbxSurfacePhong*)fbxMaterial)->SpecularFactor;
496 if (fbxColor3.IsValid() ==
true && fbxFactor.IsValid() ==
true) {
497 specularMaterialProperties->setSpecularColor(
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()),
506 fbxShininess = ((FbxSurfacePhong*)fbxMaterial)->Shininess;
507 if (fbxShininess.IsValid() ==
true && fbxShininessFactor.IsValid() ==
true) {
508 specularMaterialProperties->setShininess(
static_cast<float>(fbxShininess.Get()));
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()));
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(
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()),
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(
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()),
543 1.0f -
static_cast<float>(fbxTransparency) < Math::EPSILON?
545 1.0f -
static_cast<float>(fbxTransparency)
549 fbxColor3 = ((FbxSurfaceLambert*)fbxMaterial)->Emissive;
550 fbxFactor = ((FbxSurfaceLambert*)fbxMaterial)->EmissiveFactor;
551 if (fbxColor3.IsValid() ==
true && fbxFactor.IsValid() ==
true) {
552 specularMaterialProperties->setEmissionColor(
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()),
562 Console::println(
"FBXReader::processMeshNode(): unsupported material shading class: " + fbxMaterialName);
564 FbxProperty fbxProperty;
565 fbxProperty = fbxMaterial->FindProperty(FbxSurfaceMaterial::sDiffuse);
566 string diffuseTextureFileName;
568 if (fbxProperty.GetSrcObjectCount<FbxLayeredTexture>() > 0) {
569 auto texture = FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0));
570 diffuseTextureFileName = texture->GetFileName();
575 textureMatrix.
multiply(Matrix3x3::rotateAroundTextureCenter(texture->GetRotationU()));
576 textureMatrix.
multiply(
Matrix3x3().identity().setTranslation(
Vector2(texture->GetTranslationU(), texture->GetTranslationV())));
577 newMaterial->setTextureMatrix(textureMatrix);
579 if (fbxProperty.GetSrcObjectCount<FbxTexture>() > 0) {
580 auto texture = FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxTexture>(0));
581 diffuseTextureFileName = texture->GetFileName();
586 textureMatrix.
multiply(Matrix3x3::rotateAroundTextureCenter(texture->GetRotationU()));
587 textureMatrix.
multiply(
Matrix3x3().identity().setTranslation(
Vector2(texture->GetTranslationU(), texture->GetTranslationV())));
588 newMaterial->setTextureMatrix(textureMatrix);
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():
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():
607 FbxCast<FbxFileTexture>(fbxProperty.GetSrcObject<FbxLayeredTexture>(0))->GetFileName();
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)
620 if (specularMaterialProperties->getDiffuseTexture() !=
nullptr) specularMaterialProperties->getDiffuseTexture()->setUseCompression(useBC7TextureCompression);
621 if (specularMaterialProperties->hasDiffuseTextureTransparency() ==
true) specularMaterialProperties->setDiffuseTextureMaskedTransparency(
true);
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():
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)
638 if (specularMaterialProperties->getNormalTexture() !=
nullptr) specularMaterialProperties->getNormalTexture()->setUseCompression(useBC7TextureCompression);
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():
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)
655 if (specularMaterialProperties->getSpecularTexture() !=
nullptr) specularMaterialProperties->getSpecularTexture()->setUseCompression(useBC7TextureCompression);
659 specularMaterialProperties->setAmbientColor(
667 specularMaterialProperties->setDiffuseColor(
672 specularMaterialProperties->getDiffuseColor().getAlpha()
676 newMaterial->setSpecularMaterialProperties(specularMaterialProperties.release());
677 model->
getMaterials()[newMaterial->getId()] = newMaterial.get();
679 material = newMaterial.release();
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) {
690 faces = facesEntityLookUp.getFaces();
691 facesEntity = &facesEntityLookUp;
693 foundFacesEntity =
true;
697 if (foundFacesEntity ==
false) {
698 if (facesEntity !=
nullptr) {
702 facesEntities.emplace_back(node.get(), facesEntityName);
703 facesEntity = &facesEntities[facesEntities.size() - 1];
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:
728 textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxControlPointIndex;
731 case FbxGeometryElement::eIndexToDirect:
733 textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxUV->GetIndexArray().GetAt(fbxControlPointIndex);
740 case FbxGeometryElement::eByPolygonVertex:
742 switch (fbxUV->GetReferenceMode()) {
743 case FbxGeometryElement::eDirect:
744 case FbxGeometryElement::eIndexToDirect:
746 textureCoordinateIndices[textureCoordinateIndicesIdx++] = fbxMesh->GetTextureUVIndex(i, j);
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:
764 normalIndices[normalIndicesIdx++] = fbxVertexId;
767 case FbxGeometryElement::eIndexToDirect:
769 normalIndices[normalIndicesIdx++] = fbxNormal->GetIndexArray().GetAt(fbxVertexId);
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:
784 tangentIndices[tangentIndicesIdx++] = fbxVertexId;
787 case FbxGeometryElement::eIndexToDirect:
789 tangentIndices[tangentIndicesIdx++] = fbxTangent->GetIndexArray().GetAt(fbxVertexId);
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:
803 binormalIndices[binormalIndicesIdx++] = fbxVertexId;
806 case FbxGeometryElement::eIndexToDirect:
808 binormalIndices[binormalIndicesIdx++] = fbxBinormal->GetIndexArray().GetAt(fbxVertexId);
820 controlPointIndices[0],
821 controlPointIndices[1],
822 controlPointIndices[2],
827 if (textureCoordinateIndicesIdx == 3) {
829 textureCoordinateIndices[0],
830 textureCoordinateIndices[1],
831 textureCoordinateIndices[2]
834 if (tangentIndicesIdx == 3 && binormalIndicesIdx == 3) {
848 if (facesEntity !=
nullptr) {
852 node->setVertices(vertices);
853 node->setNormals(normals);
854 if (tangents.size() > 0 && bitangents.size() > 0) {
855 node->setTangents(tangents);
856 node->setBitangents(bitangents);
858 if (textureCoordinates.size() > 0) node->setTextureCoordinates(textureCoordinates);
859 node->setFacesEntities(facesEntities);
861 int fbxSkinCount = fbxNode->GetMesh()->GetDeformerCount(FbxDeformer::eSkin);
862 if (fbxSkinCount == 0) {
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);
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)
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)
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)
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);
949 skinning->setVerticesJointsWeights(verticesJointsWeights);
950 node->setSkinning(skinning.release());
952 Console::println(
"FBXReader::processMeshNode(): " + to_string(fbxSkinCount) +
" skins per mesh: Not supported");
955 return node.release();
959 return make_unique<Node>(model, parentNode, fbxNode->GetName(), fbxNode->GetName()).release();
963 auto fbxNodeName = fbxNode->GetName();
966 if (node->getAnimation() ==
nullptr) node->setAnimation(
new Animation());
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)
993 node->getAnimation()->setTransformMatrices(transformMatrices);
994 for(
auto i = 0; i < fbxNode->GetChildCount(); i++) {
995 processAnimation(fbxNode->GetChild(i), fbxStartFrame, fbxEndFrame, model, frameOffset);
Color 4 definition class.
static void processScene(FbxScene *fbxScene, Model *model, const string &pathName, vector< string > &possibleArmatureNodeIds, bool useBC7TextureCompression)
Process FBX scene.
static constexpr float BLENDER_AMBIENT_FROM_DIFFUSE_SCALE
static void processNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName, vector< string > &possibleArmatureNodeIds, bool useBC7TextureCompression)
Process FBX node.
static UpVector * getSceneUpVector(FbxScene *fbxScene)
Get scene up vector.
static Node * processSkeletonNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName)
Process FBX skeleton node.
static constexpr float BLENDER_DIFFUSE_SCALE
static Node * processMeshNode(FbxNode *fbxNode, Model *model, Node *parentNode, const string &pathName, bool useBC7TextureCompression)
Process FBX mesh node.
static STATIC_DLL_IMPEXT const Color4 BLENDER_AMBIENT_NONE
static void setupModelScaleRotationMatrix(FbxScene *fbxScene, Model *model)
Set up model import scale maxtrix.
static void setupModelImportRotationMatrix(Model *model)
Set up model import rotation maxtrix.
static RotationOrder * getSceneRotationOrder(FbxScene *fbxScene)
Get scene rotation order.
static void processAnimation(FbxNode *fbxNode, const FbxTime &fbxStartFrame, const FbxTime &fbxEndFrame, Model *model, int frameOffset)
Process animation.
const vector< Matrix4x4 > & getTransformMatrices() const
Returns transform matrices.
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
void setTextureCoordinateIndices(int32_t vt0, int32_t vt1, int32_t vt2)
Set up optional texture coordinate indices.
void setTangentIndices(int32_t ti0, int32_t ti1, int32_t ti2)
Set tangent indices.
void setBitangentIndices(int32_t bi0, int32_t bi1, int32_t bi2)
Set bitangent indices.
Node faces entity A node can have multiple entities containing faces and a applied material.
void setMaterial(Material *material)
Set up the entity's material.
void setFaces(const vector< Face > &faces)
Set up entity's faces.
void setBindMatrix(const Matrix4x4 &bindMatrix)
Bind matrix.
const string & getId() const
Representation of a 3D model.
unordered_map< string, Node * > & getSubNodes()
Returns object's sub nodes.
unordered_map< string, Material * > & getMaterials()
Returns all object materials.
void setImportTransformMatrix(const Matrix4x4 &importTransformMatrix)
Set import transform matrix.
AnimationSetup * getAnimationSetup(const string &id)
AuthoringTool getAuthoringTool()
const Matrix4x4 & getImportTransformMatrix()
unordered_map< string, Node * > & getNodes()
Returns all object's nodes.
Node * getNodeById(const string &id)
Returns a node by given name or null.
unordered_map< string, Node * > & getSubNodes()
Animation * getAnimation()
Represents rotation orders of a model.
Skinning definition for nodes.
Represents specular material properties.
Matrix3x3 class representing matrix3x3 mathematical structure and operations for 2d space.
Matrix3x3 & identity()
Creates identity matrix.
Matrix3x3 & multiply(const Matrix3x3 &matrix)
Multiplies this matrix with given matrix.
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Matrix4x4 clone() const
Clones this matrix.
Matrix4x4 & scale(float scalar)
Scales by scalar.
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
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.
Matrix4x4 & invert()
Inverts this matrix.
Matrix4x4 & setAxes(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis)
Set coordinate system axes.
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
File system singleton class.