23 #include <QMessageBox>
24 #include <QPushButton>
36 QStringList{
"fbx"},
"fbx", QStringList{
"FBX mesh (*.fbx)"},
41 bool& exclusive)
const {
57 FbxNode* lNode = FbxNode::Create(pScene, qPrintable(mesh->
getName()));
58 FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->
getName()));
59 lNode->SetNodeAttribute(lMesh);
63 unsigned vertCount = cloud->
size();
64 unsigned faceCount = mesh->
size();
68 lMesh->InitControlPoints(vertCount);
69 FbxVector4* lControlPoints = lMesh->GetControlPoints();
71 for (
unsigned i = 0; i < vertCount; ++i) {
73 lControlPoints[i] = FbxVector4(P->
x, P->
y, P->
z);
81 asCCMesh =
static_cast<ccMesh*
>(mesh);
86 FbxGeometryElementNormal* lGeometryElementNormal =
87 lMesh->CreateElementNormal();
91 lGeometryElementNormal->SetMappingMode(
92 FbxGeometryElement::eByPolygonVertex);
93 lGeometryElementNormal->SetReferenceMode(
94 FbxGeometryElement::eIndexToDirect);
95 lGeometryElementNormal->GetIndexArray().SetCount(faceCount * 3);
100 for (
unsigned i = 0; i < triNorms->
currentSize(); ++i) {
103 FbxVector4 Nfbx(N.
x, N.
y, N.
z);
104 lGeometryElementNormal->GetDirectArray().Add(Nfbx);
106 for (
unsigned j = 0; j < faceCount; ++j) {
109 lGeometryElementNormal->GetIndexArray().SetAt(
110 static_cast<int>(j) * 3 + 0, i1);
111 lGeometryElementNormal->GetIndexArray().SetAt(
112 static_cast<int>(j) * 3 + 1, i2);
113 lGeometryElementNormal->GetIndexArray().SetAt(
114 static_cast<int>(j) * 3 + 2, i3);
117 for (
unsigned j = 0; j < faceCount; ++j) {
121 lGeometryElementNormal->GetDirectArray().Add(
122 FbxVector4(Na.
x, Na.
y, Na.
z));
123 lGeometryElementNormal->GetDirectArray().Add(
124 FbxVector4(Nb.
x, Nb.
y, Nb.
z));
125 lGeometryElementNormal->GetDirectArray().Add(
126 FbxVector4(Nc.
x, Nc.
y, Nc.
z));
129 lGeometryElementNormal->GetIndexArray().SetAt(
130 static_cast<int>(j) * 3 + 0,
131 static_cast<int>(j) * 3 + 0);
132 lGeometryElementNormal->GetIndexArray().SetAt(
133 static_cast<int>(j) * 3 + 1,
134 static_cast<int>(j) * 3 + 1);
135 lGeometryElementNormal->GetIndexArray().SetAt(
136 static_cast<int>(j) * 3 + 2,
137 static_cast<int>(j) * 3 + 2);
143 lGeometryElementNormal->SetMappingMode(
144 FbxGeometryElement::eByControlPoint);
147 lGeometryElementNormal->SetReferenceMode(
148 FbxGeometryElement::eDirect);
149 for (
unsigned i = 0; i < vertCount; ++i) {
151 FbxVector4 Nfbx(N.
x, N.
y, N.
z);
152 lGeometryElementNormal->GetDirectArray().Add(Nfbx);
157 "[FBX] Mesh has no normal! You can manually compute them "
158 "(select it then call \"Edit > Normals > Compute\")");
162 bool hasMaterial =
false;
165 size_t matCount = matSet->size();
172 for (
size_t i = 0; i < matCount; ++i) {
174 if (mat->hasTexture()) {
181 static const char gDiffuseElementName[] =
"DiffuseUV";
185 FbxGeometryElementUV* lUVDiffuseElement =
186 lMesh->CreateElementUV(gDiffuseElementName);
187 assert(lUVDiffuseElement != 0);
188 lUVDiffuseElement->SetMappingMode(
189 FbxGeometryElement::eByPolygonVertex);
190 lUVDiffuseElement->SetReferenceMode(
191 FbxGeometryElement::eIndexToDirect);
199 lUVDiffuseElement->GetDirectArray().SetCount(
200 static_cast<int>(
count));
201 for (
unsigned i = 0; i <
count; ++i) {
203 lUVDiffuseElement->GetDirectArray().SetAt(
204 i, FbxVector2(
uv.tx,
uv.ty));
211 unsigned triCount = asCCMesh->
size();
212 lUVDiffuseElement->GetIndexArray().SetCount(
213 static_cast<int>(3 * triCount));
214 for (
unsigned j = 0; j < triCount; ++j) {
215 int t1 = 0, t2 = 0, t3 = 0;
218 lUVDiffuseElement->GetIndexArray().SetAt(j * 3 + 0, t1);
219 lUVDiffuseElement->GetIndexArray().SetAt(j * 3 + 1, t2);
220 lUVDiffuseElement->GetIndexArray().SetAt(j * 3 + 2, t3);
226 QMap<QString, QString> texFilenames;
229 QString textDirName = info.baseName() + QString(
".fbm");
230 QDir baseDir = info.absoluteDir();
231 QDir texDir = QDir(baseDir.absolutePath() + QString(
"/") + textDirName);
233 for (
size_t i = 0; i < matCount; ++i) {
235 FbxSurfacePhong* lMaterial =
236 FbxSurfacePhong::Create(pScene, qPrintable(mat->getName()));
242 lMaterial->Emissive.Set(
243 FbxDouble3(emission.
r, emission.
g, emission.
b));
244 lMaterial->Ambient.Set(FbxDouble3(ambient.
r, ambient.
g, ambient.
b));
245 lMaterial->Diffuse.Set(FbxDouble3(diffuse.
r, diffuse.
g, diffuse.
b));
246 lMaterial->Specular.Set(
247 FbxDouble3(specular.
r, specular.
g, specular.
b));
248 lMaterial->Shininess = mat->getShininessFront();
249 lMaterial->ShadingModel.Set(
"Phong");
251 if (hasTextures && mat->hasTexture()) {
252 QString texFilename = mat->getTextureFilename();
255 if (!texFilenames.contains(texFilename)) {
258 if (!texDir.exists()) {
260 if (texDir.mkdir(textDirName)) {
261 texDir.cd(textDirName);
263 textDirName = QString();
265 "[FBX] Failed to create subfolder '%1' to "
266 "store texture files (files will be stored "
267 "next to the .fbx file)");
271 QFileInfo fileInfo(texFilename);
272 QString baseTexName = fileInfo.fileName();
274 QString extension = QFileInfo(texFilename).suffix();
275 if (fileInfo.suffix().isEmpty())
276 baseTexName += QString(
".png");
278 QString absoluteFilename =
279 texDir.absolutePath() + QString(
"/") + baseTexName;
282 .arg(absoluteFilename));
284 texFilenames[texFilename] = absoluteFilename;
289 FbxFileTexture* lTexture =
290 FbxFileTexture::Create(pScene,
"DiffuseTexture");
291 assert(!texFilenames[texFilename].isEmpty());
292 lTexture->SetFileName(qPrintable(texFilenames[texFilename]));
293 lTexture->SetTextureUse(FbxTexture::eStandard);
294 lTexture->SetMappingType(FbxTexture::eUV);
295 lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
296 lTexture->SetSwapUV(
false);
297 lTexture->SetTranslation(0.0, 0.0);
298 lTexture->SetScale(1.0, 1.0);
299 lTexture->SetRotation(0.0, 0.0);
301 FbxString(gDiffuseElementName));
306 lMaterial->Diffuse.ConnectSrcObject(lTexture);
309 int matIndex = lNode->AddMaterial(lMaterial);
310 assert(matIndex ==
static_cast<int>(i));
315 for (QMap<QString, QString>::ConstIterator it =
316 texFilenames.begin();
317 it != texFilenames.end(); ++it) {
319 image.save(it.value());
322 texFilenames.clear();
327 FbxGeometryElementMaterial* lMaterialElement =
328 lMesh->CreateElementMaterial();
329 lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
330 lMaterialElement->SetReferenceMode(
331 FbxGeometryElement::eIndexToDirect);
339 FbxGeometryElementVertexColor* lGeometryElementVertexColor =
340 lMesh->CreateElementVertexColor();
341 lGeometryElementVertexColor->SetMappingMode(
342 FbxGeometryElement::eByControlPoint);
343 lGeometryElementVertexColor->SetReferenceMode(
344 FbxGeometryElement::eDirect);
345 lGeometryElementVertexColor->GetDirectArray().SetCount(vertCount);
346 for (
unsigned i = 0; i < vertCount; ++i) {
351 lGeometryElementVertexColor->GetDirectArray().SetAt(i, col);
357 FbxSurfacePhong* lMaterial =
358 FbxSurfacePhong::Create(pScene,
"ColorMaterial");
360 lMaterial->Emissive.Set(FbxDouble3(0, 0, 0));
361 lMaterial->Ambient.Set(FbxDouble3(0, 0, 0));
362 lMaterial->Diffuse.Set(FbxDouble3(1, 1, 1));
363 lMaterial->Specular.Set(FbxDouble3(0, 0, 0));
364 lMaterial->Shininess = 0;
365 lMaterial->ShadingModel.Set(
"Phong");
367 FbxGeometryElementMaterial* lMaterialElement =
368 lMesh->CreateElementMaterial();
369 lMaterialElement->SetMappingMode(FbxGeometryElement::eAllSame);
370 lMaterialElement->SetReferenceMode(FbxGeometryElement::eDirect);
371 lNode->AddMaterial(lMaterial);
377 for (
unsigned j = 0; j < faceCount; ++j) {
382 lMesh->BeginPolygon(matIndex);
383 lMesh->AddPolygon(tsi->
i1);
384 lMesh->AddPolygon(tsi->
i2);
385 lMesh->AddPolygon(tsi->
i3);
395 const char* pFilename,
396 int pFileFormat = -1,
397 bool pEmbedMedia =
false) {
399 FbxExporter* lExporter = FbxExporter::Create(pManager,
"");
401 if (pFileFormat < 0 ||
403 pManager->GetIOPluginRegistry()->GetWriterFormatCount()) {
405 pFileFormat = pManager->GetIOPluginRegistry()->GetNativeWriterFormat();
410 pManager->GetIOPluginRegistry()->GetWriterFormatCount();
412 for (lFormatIndex = 0; lFormatIndex < lFormatCount; lFormatIndex++) {
413 if (pManager->GetIOPluginRegistry()->WriterIsFBX(lFormatIndex)) {
415 pManager->GetIOPluginRegistry()
416 ->GetWriterFormatDescription(lFormatIndex);
417 const char* lASCII =
"ascii";
418 if (lDesc.Find(lASCII) >= 0) {
419 pFileFormat = lFormatIndex;
429 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_MATERIAL,
true);
430 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_TEXTURE,
true);
431 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_EMBEDDED, pEmbedMedia);
432 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_SHAPE,
true);
433 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_GOBO,
true);
434 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_ANIMATION,
true);
435 (*(pManager->GetIOSettings())).SetBoolProp(EXP_FBX_GLOBAL_SETTINGS,
true);
438 if (lExporter->Initialize(pFilename, pFileFormat,
439 pManager->GetIOSettings()) ==
false) {
442 lExporter->GetStatus().GetErrorString());
447 bool lStatus = lExporter->Export(pScene);
450 lExporter->Destroy();
462 format.replace(
"(*.fbx)",
"");
474 double scaleFactor = 0.0;
476 std::vector<ccGenericMesh*> meshes;
491 if (scaleFactor == 0.0) {
494 }
else if (scaleFactor != sf) {
496 "[FBX] Attempt to save mutliple meshes "
497 "with different units!");
501 "[FBX] Internal error: invalid FBX scale "
508 "[FBX] Reminder: default FBX units are 'cm'");
515 if (meshes.empty()) {
521 FbxManager* lSdkManager = FbxManager::Create();
527 lSdkManager->GetVersion());
533 FbxIOSettings* ios = FbxIOSettings::Create(lSdkManager, IOSROOT);
534 lSdkManager->SetIOSettings(ios);
542 FbxScene* lScene = FbxScene::Create(lSdkManager,
"My Scene");
550 FbxDocumentInfo* sceneInfo =
551 FbxDocumentInfo::Create(lSdkManager,
"SceneInfo");
552 sceneInfo->mTitle = qPrintable(
553 QString(
"Mesh: ") + (meshes.size() == 1
554 ? meshes[0]->getName()
555 : QString(
"Multiple meshes")));
556 sceneInfo->mAuthor =
"ACloudViewer";
557 sceneInfo->mRevision =
"rev. 1.0";
558 sceneInfo->mKeywords =
"CloudViewer mesh";
562 lScene->SetSceneInfo(sceneInfo);
566 if (scaleFactor != 1.0 && scaleFactor > 0.0) {
567 lScene->GetGlobalSettings().SetSystemUnit(
568 FbxSystemUnit(scaleFactor));
586 FbxNode* lRootNode = lScene->GetRootNode();
588 for (
size_t i = 0; i < meshes.size(); ++i) {
591 lRootNode->AddChild(meshNode);
595 .arg(meshes[i]->getName()));
603 FbxManager* pSdkManager = FbxManager::GetDefaultManager();
604 int lFormatCount = pSdkManager ? pSdkManager->GetIOPluginRegistry()
605 ->GetWriterFormatCount()
608 if (lFormatCount > 0) {
611 QMessageBox msgBox(QMessageBox::Question,
"FBX format",
612 "Choose output format:");
613 QMap<QAbstractButton*, int> buttons;
614 for (
int lFormatIndex = 0; lFormatIndex < lFormatCount;
616 if (pSdkManager->GetIOPluginRegistry()->WriterIsFBX(
619 pSdkManager->GetIOPluginRegistry()
620 ->GetWriterFormatDescription(
622 QPushButton* button = msgBox.addButton(
624 QMessageBox::AcceptRole);
625 buttons[button] = lFormatIndex;
630 fileFormat = buttons[msgBox.clickedButton()];
635 for (
int lFormatIndex = 0; lFormatIndex < lFormatCount;
637 if (pSdkManager->GetIOPluginRegistry()->WriterIsFBX(
640 pSdkManager->GetIOPluginRegistry()
641 ->GetWriterFormatDescription(
643 QString sanitizedDesc =
648 .arg(sanitizedDesc));
649 fileFormat = lFormatIndex;
657 if (fileFormat < 0) {
659 QString(
"[FBX] File format '%1' not supported")
662 for (
int lFormatIndex = 0; lFormatIndex < lFormatCount;
664 if (pSdkManager->GetIOPluginRegistry()->WriterIsFBX(
667 pSdkManager->GetIOPluginRegistry()
668 ->GetWriterFormatDescription(
682 "[FBX] Output filename contains special characters. It "
683 "might be rejected by the third party library..."));
691 if (lSdkManager) lSdkManager->Destroy();
702 case FbxNodeAttribute::eUnknown:
703 return (
"unidentified");
704 case FbxNodeAttribute::eNull:
706 case FbxNodeAttribute::eMarker:
708 case FbxNodeAttribute::eSkeleton:
710 case FbxNodeAttribute::eMesh:
712 case FbxNodeAttribute::eNurbs:
714 case FbxNodeAttribute::ePatch:
716 case FbxNodeAttribute::eCamera:
718 case FbxNodeAttribute::eCameraStereo:
720 case FbxNodeAttribute::eCameraSwitcher:
721 return (
"camera switcher");
722 case FbxNodeAttribute::eLight:
724 case FbxNodeAttribute::eOpticalReference:
725 return (
"optical reference");
726 case FbxNodeAttribute::eOpticalMarker:
728 case FbxNodeAttribute::eNurbsCurve:
729 return (
"nurbs curve");
730 case FbxNodeAttribute::eTrimNurbsSurface:
731 return (
"trim nurbs surface");
732 case FbxNodeAttribute::eBoundary:
734 case FbxNodeAttribute::eNurbsSurface:
735 return (
"nurbs surface");
736 case FbxNodeAttribute::eShape:
738 case FbxNodeAttribute::eLODGroup:
740 case FbxNodeAttribute::eSubDiv:
752 if (!fbxMesh)
return 0;
754 int polyCount = fbxMesh->GetPolygonCount();
756 unsigned triCount = 0;
757 unsigned polyVertCount = 0;
761 unsigned skipped = 0;
762 for (
int i = 0; i < polyCount; ++i) {
763 int pSize = fbxMesh->GetPolygonSize(i);
768 }
else if (pSize == 4) {
778 "'%1'! (polygons with more than 4 vertices "
779 "are not supported for the moment)")
780 .arg(fbxMesh->GetName()));
782 }
else if (skipped != 0) {
784 "ignored (%2): polygons with more than 4 "
785 "vertices are not supported for the moment)")
786 .arg(fbxMesh->GetName())
792 int vertCount = fbxMesh->GetControlPointsCount();
793 if (vertCount <= 0) {
794 CVLog::Warning(QString(
"[FBX] Mesh '%1' has no vetex or no polygon?!")
795 .arg(fbxMesh->GetName()));
801 mesh->
setName(fbxMesh->GetName());
805 if (!mesh->
reserve(
static_cast<unsigned>(triCount)) ||
806 !vertices->
reserve(vertCount)) {
807 CVLog::Warning(QString(
"[FBX] Not enough memory to load mesh '%1'!")
808 .arg(fbxMesh->GetName()));
815 for (
int l = 0; l < fbxMesh->GetElementVertexColorCount(); l++) {
816 FbxGeometryElementVertexColor* vertColor =
817 fbxMesh->GetElementVertexColor(l);
819 if (vertColor->GetMappingMode() ==
820 FbxGeometryElement::eByControlPoint) {
821 if (vertColor->GetReferenceMode() ==
822 FbxGeometryElement::eDirect ||
823 vertColor->GetReferenceMode() ==
824 FbxGeometryElement::eIndexToDirect) {
826 switch (vertColor->GetReferenceMode()) {
827 case FbxGeometryElement::eDirect: {
828 for (
int i = 0; i < vertCount; ++i) {
830 vertColor->GetDirectArray().GetAt(
841 case FbxGeometryElement::eIndexToDirect: {
842 for (
int i = 0; i < vertCount; ++i) {
844 vertColor->GetIndexArray().GetAt(i);
846 vertColor->GetDirectArray().GetAt(
868 "load mesh '%1' colors!")
869 .arg(fbxMesh->GetName()));
873 "will be ignored (unhandled type)")
875 .arg(fbxMesh->GetName()));
879 "will be ignored (unhandled type)")
881 .arg(fbxMesh->GetName()));
887 int perPointNormals = -1;
888 int perVertexNormals = -1;
889 int perPolygonNormals = -1;
891 for (
int j = 0; j < fbxMesh->GetElementNormalCount(); j++) {
892 FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(j);
893 switch (leNormals->GetMappingMode()) {
894 case FbxGeometryElement::eByControlPoint:
897 case FbxGeometryElement::eByPolygonVertex:
898 perVertexNormals = j;
900 case FbxGeometryElement::eByPolygon:
901 perPolygonNormals = j;
911 if (perPointNormals >= 0) {
912 FbxGeometryElementNormal* leNormals =
913 fbxMesh->GetElementNormal(perPointNormals);
914 FbxLayerElement::EReferenceMode refMode = leNormals->GetReferenceMode();
915 const FbxLayerElementArrayTemplate<FbxVector4>&
normals =
916 leNormals->GetDirectArray();
917 assert(
normals.GetCount() == vertCount);
918 if (
normals.GetCount() != vertCount) {
920 QString(
"[FBX] Wrong number of normals on mesh '%1'!")
921 .arg(fbxMesh->GetName()));
922 perPointNormals = -1;
924 CVLog::Warning(QString(
"[FBX] Not enough memory to load mesh '%1' "
926 .arg(fbxMesh->GetName()));
927 perPointNormals = -1;
930 for (
int i = 0; i < vertCount; ++i) {
931 int id = refMode != FbxGeometryElement::eDirect
932 ? leNormals->GetIndexArray().GetAt(i)
934 FbxVector4 N =
normals.GetAt(
id);
944 perVertexNormals = -1;
945 perPolygonNormals = -1;
951 if (perVertexNormals >= 0 || perPolygonNormals >= 0) {
955 CVLog::Warning(QString(
"[FBX] Not enough memory to load mesh '%1' "
957 .arg(fbxMesh->GetName()));
970 FbxNode* lNode = fbxMesh->GetNode();
971 int lMaterialCount = lNode ? lNode->GetMaterialCount() : 0;
972 for (
int i = 0; i < lMaterialCount; i++) {
973 FbxSurfaceMaterial* lBaseMaterial = lNode->GetMaterial(i);
976 lBaseMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId);
978 lBaseMaterial->GetClassId().Is(FbxSurfacePhong::ClassId);
979 if (isLambert || isPhong) {
983 FbxSurfaceLambert* lLambertMat =
984 static_cast<FbxSurfaceLambert*
>(lBaseMaterial);
991 FbxSurfacePhong* lPhongMat =
992 isPhong ?
static_cast<FbxSurfacePhong*
>(lBaseMaterial)
995 for (
int k = 0; k < 3; ++k) {
997 static_cast<float>(lLambertMat->Ambient.Get()[k]);
999 static_cast<float>(lLambertMat->Diffuse.Get()[k]);
1001 static_cast<float>(lLambertMat->Emissive.Get()[k]);
1004 specular.
rgba[k] =
static_cast<float>(
1005 lPhongMat->Specular.Get()[k]);
1009 mat->setAmbient(ambient);
1010 mat->setDiffuse(diffuse);
1011 mat->setEmission(emission);
1013 mat->setSpecular(specular);
1015 mat->setShininess(
static_cast<float>(lPhongMat->Shininess));
1021 FBXSDK_FOR_EACH_TEXTURE(lTextureIndex) {
1022 FbxProperty lProperty = lBaseMaterial->FindProperty(
1023 FbxLayerElement::sTextureChannelNames
1025 if (lProperty.IsValid()) {
1027 lProperty.GetSrcObjectCount<FbxTexture>();
1028 FbxTexture* texture =
1032 for (
int j = 0; j < lTextureCount; ++j) {
1035 FbxLayeredTexture* lLayeredTexture =
1036 lProperty.GetSrcObject<
1037 FbxLayeredTexture>(j);
1038 if (lLayeredTexture) {
1053 FbxTexture* lTexture =
1054 lProperty.GetSrcObject<FbxTexture>(
1066 FbxFileTexture* lFileTexture =
1067 FbxCast<FbxFileTexture>(texture);
1069 const char* texAbsoluteFilename =
1070 lFileTexture->GetFileName();
1072 QString(
"[FBX] Texture absolue "
1074 .arg(texAbsoluteFilename));
1075 if (texAbsoluteFilename != 0 &&
1076 texAbsoluteFilename[0] != 0) {
1077 if (!mat->loadAndSetTexture(
1078 texAbsoluteFilename)) {
1080 QString(
"[FBX] Failed to "
1083 .arg(texAbsoluteFilename));
1099 QString(
"[FBX] Material '%1' has an unhandled type")
1100 .arg(lBaseMaterial->GetName()));
1107 bool hasTexUVIndexes =
false;
1109 for (
int l = 0; l < fbxMesh->GetElementUVCount(); ++l) {
1110 FbxGeometryElementUV* leUV = fbxMesh->GetElementUV(l);
1112 if (leUV->GetMappingMode() ==
1113 FbxGeometryElement::eByPolygonVertex) {
1115 int uvCount = leUV->GetDirectArray().GetCount();
1122 "mesh '%1' UV coordinates!")
1123 .arg(fbxMesh->GetName()));
1125 FbxLayerElement::EReferenceMode refMode =
1126 leUV->GetReferenceMode();
1127 for (
int i = 0; i < uvCount; ++i) {
1128 FbxVector2
uv = leUV->GetDirectArray().GetAt(i);
1131 static_cast<float>(
uv.Buffer()[1]));
1135 if (refMode == FbxGeometryElement::eIndexToDirect) {
1136 hasTexUVIndexes =
true;
1141 }
else if (refMode == FbxGeometryElement::eDirect) {
1148 QString(
"[FBX] UV coordinates for mesh '%1' "
1149 "are encoded in an unhandled mode!")
1150 .arg(fbxMesh->GetName()));
1166 for (
int i = 0; i < polyCount; ++i) {
1167 int pSize = fbxMesh->GetPolygonSize(i);
1171 if (!hasTexUVIndexes) uvIndex += pSize;
1177 int i1 = fbxMesh->GetPolygonVertex(i, 0);
1178 int i2 = fbxMesh->GetPolygonVertex(i, 1);
1179 int i3 = fbxMesh->GetPolygonVertex(i, 2);
1184 i4 = fbxMesh->GetPolygonVertex(i, 3);
1188 if (vertTexUVTable) {
1189 if (hasTexUVIndexes) {
1190 i1 = fbxMesh->GetTextureUVIndex(i, 0);
1191 if (i1 > uvIndex) uvIndex = i1;
1192 i2 = fbxMesh->GetTextureUVIndex(i, 1);
1193 if (i2 > uvIndex) uvIndex = i2;
1194 i3 = fbxMesh->GetTextureUVIndex(i, 2);
1195 if (i3 > uvIndex) uvIndex = i3;
1203 if (hasTexUVIndexes) {
1204 i4 = fbxMesh->GetTextureUVIndex(i, 3);
1205 if (i4 > uvIndex) uvIndex = i4;
1213 static_cast<int>(vertTexUVTable->
currentSize())) {
1215 "indexes mismatch!")
1216 .arg(fbxMesh->GetName()));
1224 int nIndex =
static_cast<int>(normsTable->
currentSize());
1225 for (
int j = 0; j < pSize; ++j) {
1227 fbxMesh->GetPolygonVertexNormal(i, j, N);
1243 if (vertTexUVTable) {
1247 if (mesh->
size() == 0) {
1249 QString(
"[FBX] No triangle found in mesh '%1'! (only "
1250 "triangles are supported for the moment)")
1251 .arg(fbxMesh->GetName()));
1259 const FbxVector4* fbxVertices = fbxMesh->GetControlPoints();
1260 assert(vertices && fbxVertices);
1262 for (
int i = 0; i < vertCount; ++i, ++fbxVertices) {
1267 bool preserveCoordinateShift =
true;
1269 P, Pshift, preserveCoordinateShift, parameters)) {
1270 if (preserveCoordinateShift) {
1274 "[FBX] Mesh has been recentered! Translation: "
1275 "(%.2f ; %.2f ; %.2f)",
1276 Pshift.
x, Pshift.
y, Pshift.
z);
1287 int fbxMatCount = fbxMesh->GetElementMaterialCount();
1288 for (
int i = 0; i < fbxMatCount; ++i) {
1289 FbxGeometryElementMaterial* lMaterialElement =
1290 fbxMesh->GetElementMaterial(i);
1291 if (lMaterialElement->GetMappingMode() ==
1292 FbxGeometryElement::eByPolygon &&
1293 lMaterialElement->GetReferenceMode() ==
1294 FbxGeometryElement::eIndexToDirect &&
1295 lMaterialElement->GetIndexArray().GetCount() ==
1296 fbxMesh->GetPolygonCount()) {
1298 int maxMaterialIndex =
static_cast<int>(materials->size());
1300 lMaterialElement->GetIndexArray().GetCount();
1301 for (
int j = 0; j < matElemCount; ++j) {
1303 lMaterialElement->GetIndexArray().GetAt(j);
1305 mtlIndex < maxMaterialIndex ? mtlIndex : -1);
1309 "[FBX] Not enough memory to load materials!");
1313 else if (lMaterialElement->GetMappingMode() == FbxGeometryElement::eAllSame
1317 if (lMaterialElement->GetReferenceMode() ==
1318 FbxGeometryElement::eIndexToDirect) {
1319 assert(lMaterialElement->GetIndexArray().GetCount() > 0);
1320 mtlIndex = lMaterialElement->GetIndexArray().GetAt(0);
1324 for (
unsigned j = 0; j < mesh->
size(); ++j) {
1329 "[FBX] Not enough memory to load materials!");
1356 FbxManager* lSdkManager = FbxManager::Create();
1359 FbxIOSettings* ios = FbxIOSettings::Create(lSdkManager, IOSROOT);
1360 lSdkManager->SetIOSettings(ios);
1371 FbxImporter* lImporter = FbxImporter::Create(lSdkManager,
"");
1375 "[FBX] Input filename contains special characters. It "
1376 "might be rejected by the third party library..."));
1380 if (!lImporter->Initialize(qPrintable(
filename), -1,
1381 lSdkManager->GetIOSettings())) {
1383 QString(
"[FBX] Error: %1")
1384 .arg(lImporter->GetStatus().GetErrorString()));
1389 FbxScene* lScene = FbxScene::Create(lSdkManager,
"myScene");
1392 if (lImporter->Import(lScene)) {
1396 FbxNode* lRootNode = lScene->GetRootNode();
1397 std::vector<FbxNode*> nodes;
1398 nodes.push_back(lRootNode);
1401 FbxSystemUnit unitSystem =
1402 lScene->GetGlobalSettings().GetSystemUnit();
1403 double scaleFactor = unitSystem.GetScaleFactor();
1405 while (!nodes.empty()) {
1406 FbxNode* lNode = nodes.back();
1409 const char* nodeName = lNode->GetName();
1413 .arg(lNode->GetNodeAttributeCount()));
1416 for (
int i = 0; i < lNode->GetNodeAttributeCount(); i++) {
1417 FbxNodeAttribute* pAttribute =
1418 lNode->GetNodeAttributeByIndex(i);
1419 FbxNodeAttribute::EType
type =
1420 pAttribute->GetAttributeType();
1427 case FbxNodeAttribute::eMesh: {
1429 static_cast<FbxMesh*
>(pAttribute),
1433 FbxAMatrix& transform =
1434 lNode->EvaluateGlobalTransform();
1436 float* data = mat.
data();
1437 for (
int c = 0; c < 4; ++c, data++) {
1438 FbxVector4 C = transform.GetColumn(c);
1439 data[0] =
static_cast<float>(C[0]);
1440 data[4] =
static_cast<float>(C[1]);
1441 data[8] =
static_cast<float>(C[2]);
1442 data[12] =
static_cast<float>(C[3]);
1456 if (mesh->
getName().isEmpty()) {
1460 if (scaleFactor != 1.0) {
1472 case FbxNodeAttribute::eUnknown:
1473 case FbxNodeAttribute::eNull:
1474 case FbxNodeAttribute::eMarker:
1475 case FbxNodeAttribute::eSkeleton:
1476 case FbxNodeAttribute::eNurbs:
1477 case FbxNodeAttribute::ePatch:
1478 case FbxNodeAttribute::eCamera:
1479 case FbxNodeAttribute::eCameraStereo:
1480 case FbxNodeAttribute::eCameraSwitcher:
1481 case FbxNodeAttribute::eLight:
1482 case FbxNodeAttribute::eOpticalReference:
1483 case FbxNodeAttribute::eOpticalMarker:
1484 case FbxNodeAttribute::eNurbsCurve:
1485 case FbxNodeAttribute::eTrimNurbsSurface:
1486 case FbxNodeAttribute::eBoundary:
1487 case FbxNodeAttribute::eNurbsSurface:
1488 case FbxNodeAttribute::eShape:
1489 case FbxNodeAttribute::eLODGroup:
1490 case FbxNodeAttribute::eSubDiv:
1498 for (
int j = 0; j < lNode->GetChildCount(); j++) {
1499 nodes.push_back(lNode->GetChild(j));
1510 lImporter->Destroy();
1512 lSdkManager->Destroy();
1514 CVLog::Warning(
"[FBX] FBX SDK has thrown an unknown exception!");
float PointCoordinateType
Type of the coordinates of a (N-D) point.
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
QString GetAttributeTypeName(FbxNodeAttribute::EType type)
static bool SaveScene(FbxManager *pManager, FbxDocument *pScene, const char *pFilename, int pFileFormat=-1, bool pEmbedMedia=false)
static QString s_defaultOutputFormat
static FbxNode * ToFbxMesh(ccGenericMesh *mesh, FbxScene *pScene, QString filename, size_t meshIndex)
QString SanitizeFBXFormatString(QString format)
static const char FBX_SCALE_METADATA_KEY[]
static ccMesh * FromFbxMesh(FbxMesh *fbxMesh, FileIOFilter::LoadParameters ¶meters)
std::shared_ptr< core::Tensor > image
filament::Texture::InternalFormat format
CC_FILE_ERROR
Typical I/O filter errors.
@ CC_FERR_THIRD_PARTY_LIB_EXCEPTION
virtual void release()
Decrease counter and deletes object when 0.
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters ¶meters) override
Saves an entity (or a group of) to a file.
bool canSave(CV_CLASS_ENUM type, bool &multiple, bool &exclusive) const override
Returns whether this I/O filter can save the specified type of entity.
static void SetDefaultOutputFormat(QString format)
CC_FILE_ERROR loadFile(const QString &filename, ccHObject &container, LoadParameters ¶meters) override
Loads one or more entities from a file.
static bool CheckForSpecialChars(const QString &filename)
Returns whether special characters are present in the input string.
static bool HandleGlobalShift(const CCVector3d &P, CCVector3d &Pshift, bool &preserveCoordinateShift, LoadParameters &loadParameters, bool useInputCoordinatesShiftIfPossible=false)
Shortcut to the ecvGlobalShiftManager mechanism specific for files.
Array of compressed 3D normals (single index)
Array of 2D texture coordinates.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Type & getValue(size_t index)
bool reserveSafe(size_t count)
Reserves memory (no exception thrown)
unsigned currentSize() const
void addElement(const Type &value)
virtual bool hasColors() const
Returns whether colors are enabled or not.
virtual bool hasNormals() const
Returns whether normals are enabled or not.
virtual void showNormals(bool state)
Sets normals visibility.
virtual void showColors(bool state)
Sets colors visibility.
T * data()
Returns a pointer to internal data.
Float version of ccGLMatrixTpl.
void showNormals(bool state) override
Sets normals visibility.
virtual bool hasTriNormals() const =0
Returns whether the mesh has per-triangle normals.
virtual bool getTriangleNormals(unsigned triangleIndex, CCVector3 &Na, CCVector3 &Nb, CCVector3 &Nc) const =0
Returns a given triangle normal.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
virtual void showMaterials(bool state)
Sets whether textures should be displayed or not.
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual const CCVector3 & getPointNormal(unsigned pointIndex) const =0
Returns normal corresponding to a given point.
virtual const ecvColor::Rgb & getPointColor(unsigned pointIndex) const =0
Returns color corresponding to a given point.
Hierarchical CLOUDVIEWER Object.
virtual void resetGLTransformationHistory_recursive()
void applyGLTransformation_recursive(const ccGLMatrix *trans=nullptr)
Applies the active OpenGL transformation to the entity (recursive)
unsigned getChildrenNumber() const
Returns the number of children.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
void removeChild(ccHObject *child)
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Mesh (triangle) material.
int addMaterial(ccMaterial::CShared mat, bool allowDuplicateNames=false)
Adds a material.
Mesh (triangle) material.
static QImage GetTexture(const QString &absoluteFilename)
Returns the texture image associated to a given name.
QSharedPointer< const ccMaterial > CShared
Const + Shared type.
QSharedPointer< ccMaterial > Shared
Shared type.
void getTriangleTexCoordinatesIndexes(unsigned triangleIndex, int &i1, int &i2, int &i3) const override
Returns the triplet of tex coords indexes for a given triangle.
const ccMaterialSet * getMaterialSet() const override
TextureCoordsContainer * getTexCoordinatesTable() const override
Returns per-triangle texture coordinates array.
NormsIndexesTableType * getTriNormsTable() const override
Returns per-triangle normals shared array.
void getTriangleNormalIndexes(unsigned triangleIndex, int &i1, int &i2, int &i3) const override
Returns a triplet of normal indexes for a given triangle (if any)
bool hasMaterials() const override
bool reservePerTriangleMtlIndexes()
Reserves memory to store per-triangle material index.
void setTriNormsTable(NormsIndexesTableType *triNormsTable, bool autoReleaseOldTable=true)
Sets per-triangle normals array (may be shared)
void addTriangleMtlIndex(int mtlIndex)
Adds triangle material index for next triangle.
void setMaterialSet(ccMaterialSet *materialSet, bool autoReleaseOldMaterialSet=true)
Sets associated material set (may be shared)
bool reserve(std::size_t n)
Reserves the memory to store the vertex indexes (3 per triangle)
void addTriangleTexCoordIndexes(int i1, int i2, int i3)
Adds a triplet of tex coords indexes for next triangle.
bool hasTextures() const override
Returns whether textures are available for this mesh.
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
bool reservePerTriangleNormalIndexes()
Reserves memory to store per-triangle triplets of normal indexes.
bool hasPerTriangleTexCoordIndexes() const override
Returns whether this mesh as per-triangle triplets of tex coords indexes.
void setTexCoordinatesTable(TextureCoordsContainer *texCoordsTable, bool autoReleaseOldTable=true)
Sets per-triangle texture coordinates array (may be shared)
void addTriangleNormalIndexes(int i1, int i2, int i3)
Adds a triplet of normal indexes for next triangle.
bool reservePerTriangleTexCoordIndexes()
Reserves memory to store per-triangle triplets of tex coords indexes.
virtual unsigned size() const override
Returns the number of triangles.
int getTriangleMtlIndex(unsigned triangleIndex) const override
Returns a given triangle material indexes.
bool hasPerTriangleMtlIndexes() const
Returns whether this mesh as per-triangle material index.
static const CCVector3 & GetNormal(unsigned normIndex)
Static access to ccNormalVectors::getNormal.
static CompressedNormType GetNormIndex(const PointCoordinateType N[])
Returns the compressed index corresponding to a normal vector.
virtual QString getName() const
Returns object name.
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
bool isA(CV_CLASS_ENUM type) const
QVariant getMetaData(const QString &key) const
Returns a given associated meta data.
bool hasMetaData(const QString &key) const
Returns whether a meta-data element with the given key exists or not.
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
bool isKindOf(CV_CLASS_ENUM type) const
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addNorm(const CCVector3 &N)
Pushes a normal vector on stack (shortcut)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
bool reserveTheNormsTable()
Reserves memory to store the compressed normals.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
virtual VerticesIndexes * getTriangleVertIndexes(unsigned triangleIndex)=0
Returns the indexes of the vertices of a given triangle.
virtual unsigned size() const =0
Returns the number of triangles.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned char ColorCompType
Default color components type (R,G and B)
constexpr ColorCompType MAX
Max value of a single color component (default type)
Generic loading parameters.
Generic saving parameters.
Triangle described by the indexes of its 3 vertices.