使用FBX SDK 2020导出FbxScene为空的技术问题
FBX SDK导出场景后根节点无内容的问题排查与解决
我用FBX SDK创建了用于导出的场景,将节点添加到根节点后,导出的FBX文件里根节点并没有包含子节点。把生成的FBX导入Blender时没有报错,但内容是空的。查了官方文档,没找到调用AddChild()之后需要执行的额外步骤,相关代码如下:
void FbxSceneData::Export(FbxSceneData^ scene, System::String^ path) { FbxManager* fbxManager = FbxManager::Create(); FbxIOSettings* ios = FbxIOSettings::Create(fbxManager, IOSROOT); fbxManager->SetIOSettings(ios); FbxExporter* Exporter = FbxExporter::Create(fbxManager, ""); const char* pathPtr = StringToConstChar(path); // Set the FbxIOSettings EXP_FBX_EMBEDDED property to true. (*(fbxManager->GetIOSettings())).SetBoolProp(EXP_FBX_EMBEDDED, true); // Get the appropriate file format for FBX 2020 binary. int lFileFormat = fbxManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX binary (*.fbx)"); // Initialize the exporter with the specified file format Exporter->Initialize(pathPtr, lFileFormat, fbxManager->GetIOSettings()); FbxScene* fbxscene = FbxScene::Create(fbxManager, ""); FbxNode* rootNode = fbxscene->GetRootNode(); // ... Prepare the fbxscene data for export ... FbxNode* fbxNode = FbxNode::Create(fbxscene, "child1"); FbxNull* fbnull = FbxNull::Create(fbxscene, "child1"); fbxNode->SetNodeAttribute(fbnull); rootNode->AddChild(fbxNode); // Export the scene Exporter->Export(fbxscene); Exporter->Destroy(); ios->Destroy(); fbxManager->Destroy(); }
const char* StringToConstChar(System::String^ str) { // Convert the System::String^ to char* pin_ptr<const wchar_t> wch = PtrToStringChars(str); const size_t convertedSize = wcstombs(nullptr, wch, 0); std::string stdStr(convertedSize, 0); wcstombs(&stdStr[0], wch, convertedSize + 1); // Return the const char* from the std::string return stdStr.c_str(); }
问题根源与修复方案
1. 字符串转换的内存失效问题
StringToConstChar函数中,返回的std::string::c_str()指向的是函数内局部std::string的内存,函数执行完毕后该局部变量会被销毁,导致pathPtr变成野指针。这会导致导出器写入路径错误,甚至无法正确生成文件。
修复方法:将字符串转换逻辑移到Export函数内部,确保std::string在导出完成前始终有效:
void FbxSceneData::Export(FbxSceneData^ scene, System::String^ path) { FbxManager* fbxManager = FbxManager::Create(); FbxIOSettings* ios = FbxIOSettings::Create(fbxManager, IOSROOT); fbxManager->SetIOSettings(ios); FbxExporter* Exporter = FbxExporter::Create(fbxManager, ""); // 直接在函数内完成字符串转换 pin_ptr<const wchar_t> wch = PtrToStringChars(path); size_t convertedSize = wcstombs(nullptr, wch, 0); std::string stdStr(convertedSize, 0); wcstombs(&stdStr[0], wch, convertedSize + 1); const char* pathPtr = stdStr.c_str(); (*(fbxManager->GetIOSettings())).SetBoolProp(EXP_FBX_EMBEDDED, true); int lFileFormat = fbxManager->GetIOPluginRegistry()->FindWriterIDByDescription("FBX binary (*.fbx)"); // 增加初始化检查 if (!Exporter->Initialize(pathPtr, lFileFormat, fbxManager->GetIOSettings())) { printf("导出器初始化失败: %s\n", Exporter->GetStatus().GetErrorString()); // 释放资源后返回 Exporter->Destroy(); ios->Destroy(); fbxManager->Destroy(); return; } FbxScene* fbxscene = FbxScene::Create(fbxManager, ""); FbxNode* rootNode = fbxscene->GetRootNode(); FbxNode* fbxNode = FbxNode::Create(fbxscene, "child1"); FbxNull* fbnull = FbxNull::Create(fbxscene, "child1"); fbxNode->SetNodeAttribute(fbnull); // 显式设置节点变换(避免导入器忽略默认值) fbxNode->LclTranslation.Set(FbxDouble3(0, 0, 0)); fbxNode->LclRotation.Set(FbxDouble3(0, 0, 0)); fbxNode->LclScaling.Set(FbxDouble3(1, 1, 1)); rootNode->AddChild(fbxNode); Exporter->Export(fbxscene); // 调整资源销毁顺序,先销毁场景 fbxscene->Destroy(); Exporter->Destroy(); ios->Destroy(); fbxManager->Destroy(); }
2. 导出器初始化检查
之前的代码没有检查Exporter->Initialize的返回值,如果路径无效或格式不支持,导出器会初始化失败,但代码仍会执行导出操作,导致生成空文件。增加检查可以及时发现这类问题。
3. 节点变换显式设置
部分导入器(包括Blender)可能对未显式设置变换属性的节点处理异常,显式设置局部平移、旋转、缩放为默认值,能确保节点被正确识别。
内容的提问来源于stack exchange,提问作者anubis
相关产品推荐
相关产品推荐

