void FbxToHkxConverter::findChildren(FbxNode* root, hkArray<FbxNode*>& children, FbxNodeAttribute::EType type) { for (int childIndex = 0; childIndex < root->GetChildCount(); childIndex++) { FbxNode *node = root->GetChild(childIndex); if (node->GetNodeAttribute() != NULL && node->GetNodeAttribute()->GetAttributeType() == type) { children.pushBack(node); } findChildren(node, children, type); } }
FbxNode* FBXScene::findNode(FbxNodeAttribute::EType type) { FbxNode* node = m_pScene->GetRootNode(); std::vector<FbxNode*> toExplore; for (int i = 0; i < node->GetChildCount(); ++i) { toExplore.push_back(node->GetChild(i)); } while (!toExplore.empty()) { node = toExplore.back(); toExplore.pop_back(); if (node->GetNodeAttribute()->GetAttributeType() == type) { return node; } for (int i = 0; i < node->GetChildCount(); ++i) { toExplore.push_back(node->GetChild(i)); } } LOGE << "Couldn't find any node of type " << fbxUtility::getAttributeStr(type); return nullptr; }
// Load Fbx File void GenerateLOD::LoadFbx() { FbxManager *fbxManager = FbxManager::Create(); //Create an IOSetting FbxIOSettings *ios = FbxIOSettings::Create(fbxManager, IOSROOT); fbxManager->SetIOSettings(ios); //Create an impoter FbxImporter *lImporter = FbxImporter::Create(fbxManager, "myImporter"); std::string tmp = std::string(".\\LODs\\") + srcFbxName; bool lImporterStatus = lImporter->Initialize(tmp.c_str(), -1, fbxManager->GetIOSettings()); if (!lImporterStatus) { MessageBox(NULL, "No Scuh File in .\\LODs\\ directory !", "Warning", 0); return; } FbxScene *fbxScene = FbxScene::Create(fbxManager, "myScene"); lImporter->Import(fbxScene); FbxNode *rootNode = fbxScene->GetRootNode(); if (rootNode != NULL) { for (int i = 0; i < rootNode->GetChildCount(); ++i) { FbxNode *node = rootNode->GetChild(i); FbxNodeAttribute *Att = node->GetNodeAttribute(); if (Att != NULL && Att->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh *lMesh = (FbxMesh *)(Att); //FbxMesh *lMesh = dynamic_cast<FbxMesh *>(Att); if (!lMesh->IsTriangleMesh()) { FbxGeometryConverter converter = FbxGeometryConverter(fbxManager); FbxNodeAttribute *Attr = converter.Triangulate(lMesh, true); lMesh = (FbxMesh *)(Attr); } //Following is the SImplification Reduction_EdgesCollapse_UV(node, lMesh, fbxManager, fbxScene); } } } //MessageBox(NULL, "Export Succeed!", "Export", 0); fbxManager->Destroy(); }
void ImportSkeletalMeshLOD( class USkeletalMesh* SelectedSkelMesh, const FString& Filename, int32 LODLevel ) { // Check the file extension for FBX. Anything that isn't .FBX is rejected const FString FileExtension = FPaths::GetExtension(Filename); const bool bIsFBX = FCString::Stricmp(*FileExtension, TEXT("FBX")) == 0; if (bIsFBX) { #if WITH_APEX_CLOTHING FClothingBackup ClothingBackup; if(LODLevel == 0) { ApexClothingUtils::BackupClothingDataFromSkeletalMesh(SelectedSkelMesh, ClothingBackup); } #endif// #if WITH_APEX_CLOTHING UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); // don't import material and animation UnFbx::FBXImportOptions* ImportOptions = FFbxImporter->GetImportOptions(); ImportOptions->bImportMaterials = false; ImportOptions->bImportTextures = false; ImportOptions->bImportAnimations = false; if ( !FFbxImporter->ImportFromFile( *Filename, FPaths::GetExtension( Filename ) ) ) { // Log the error message and fail the import. FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FBXImport_ParseFailed", "FBX file parsing failed.")), FFbxErrors::Generic_FBXFileParseFailed); } else { bool bUseLODs = true; int32 MaxLODLevel = 0; TArray< TArray<FbxNode*>* > MeshArray; TArray<FString> LODStrings; TArray<FbxNode*>* MeshObject = NULL;; // Populate the mesh array FFbxImporter->FillFbxSkelMeshArrayInScene(FFbxImporter->Scene->GetRootNode(), MeshArray, false); // Nothing found, error out if (MeshArray.Num() == 0) { FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FBXImport_NoMesh", "No meshes were found in file.")), FFbxErrors::Generic_MeshNotFound); FFbxImporter->ReleaseScene(); return; } MeshObject = MeshArray[0]; // check if there is LODGroup for this skeletal mesh for (int32 j = 0; j < MeshObject->Num(); j++) { FbxNode* Node = (*MeshObject)[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { // get max LODgroup level if (MaxLODLevel < (Node->GetChildCount() - 1)) { MaxLODLevel = Node->GetChildCount() - 1; } } } // No LODs found, switch to supporting a mesh array containing meshes instead of LODs if (MaxLODLevel == 0) { bUseLODs = false; MaxLODLevel = SelectedSkelMesh->LODInfo.Num(); } // Create LOD dropdown strings LODStrings.AddZeroed(MaxLODLevel + 1); LODStrings[0] = FString::Printf( TEXT("Base") ); for(int32 i = 1; i < MaxLODLevel + 1; i++) { LODStrings[i] = FString::Printf(TEXT("%d"), i); } int32 SelectedLOD = LODLevel; if (SelectedLOD > SelectedSkelMesh->LODInfo.Num()) { // Make sure they don't manage to select a bad LOD index FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FBXImport_InvalidLODIdx", "Invalid mesh LOD index {0}, no prior LOD index exists"), FText::AsNumber(SelectedLOD))), FFbxErrors::Generic_Mesh_LOD_InvalidIndex); } else { TArray<FbxNode*> SkelMeshNodeArray; if (bUseLODs || ImportOptions->bImportMorph) { for (int32 j = 0; j < MeshObject->Num(); j++) { FbxNode* Node = (*MeshObject)[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { if (Node->GetChildCount() > SelectedLOD) { SkelMeshNodeArray.Add(Node->GetChild(SelectedLOD)); } else // in less some LODGroups have less level, use the last level { SkelMeshNodeArray.Add(Node->GetChild(Node->GetChildCount() - 1)); } } else { SkelMeshNodeArray.Add(Node); } } } // Import mesh USkeletalMesh* TempSkelMesh = NULL; // @todo AssetImportData does this temp skeletal mesh need import data? UFbxSkeletalMeshImportData* TempAssetImportData = NULL; TempSkelMesh = (USkeletalMesh*)FFbxImporter->ImportSkeletalMesh(GetTransientPackage(), bUseLODs? SkelMeshNodeArray: *MeshObject, NAME_None, (EObjectFlags)0, TempAssetImportData); // Add imported mesh to existing model bool bImportSucceeded = false; if( TempSkelMesh ) { bImportSucceeded = FFbxImporter->ImportSkeletalMeshLOD(TempSkelMesh, SelectedSkelMesh, SelectedLOD); // Mark package containing skeletal mesh as dirty. SelectedSkelMesh->MarkPackageDirty(); } if(ImportOptions->bImportMorph) { FFbxImporter->ImportFbxMorphTarget(SkelMeshNodeArray, SelectedSkelMesh, SelectedSkelMesh->GetOutermost(), SelectedLOD); } if (bImportSucceeded) { // Notification of success FNotificationInfo NotificationInfo(FText::GetEmpty()); NotificationInfo.Text = FText::Format(NSLOCTEXT("UnrealEd", "LODImportSuccessful", "Mesh for LOD {0} imported successfully!"), FText::AsNumber(SelectedLOD)); NotificationInfo.ExpireDuration = 5.0f; FSlateNotificationManager::Get().AddNotification(NotificationInfo); } else { // Notification of failure FNotificationInfo NotificationInfo(FText::GetEmpty()); NotificationInfo.Text = FText::Format(NSLOCTEXT("UnrealEd", "LODImportFail", "Failed to import mesh for LOD {0}!"), FText::AsNumber(SelectedLOD)); NotificationInfo.ExpireDuration = 5.0f; FSlateNotificationManager::Get().AddNotification(NotificationInfo); } } // Cleanup for (int32 i=0; i<MeshArray.Num(); i++) { delete MeshArray[i]; } } FFbxImporter->ReleaseScene(); #if WITH_APEX_CLOTHING if(LODLevel == 0) { ApexClothingUtils::ReapplyClothingDataToSkeletalMesh(SelectedSkelMesh, ClothingBackup); } ApexClothingUtils::ReImportClothingSectionsFromClothingAsset(SelectedSkelMesh); #endif// #if WITH_APEX_CLOTHING } }
int main(int argc, char **argv) { #ifndef _DEBUG if (argc != 2) { printf("invalid arg"); return 0; } const char* filename = argv[1]; #else const char* filename = "*****@*****.**"; #endif output.open("output.txt", ios::out | ios::trunc); output2.open("output2.txt", ios::out | ios::trunc); output3.open("output3.txt", ios::out | ios::trunc); if (!output.is_open()) { exit(1); } FbxManager* fm = FbxManager::Create(); FbxIOSettings *ios = FbxIOSettings::Create(fm, IOSROOT); //ios->SetBoolProp(EXP_FBX_ANIMATION, false); ios->SetIntProp(EXP_FBX_COMPRESS_LEVEL, 9); ios->SetAllObjectFlags(true); fm->SetIOSettings(ios); FbxImporter* importer = FbxImporter::Create(fm, ""); if (!importer->Initialize(filename, -1, fm->GetIOSettings())) { printf("error returned : %s\n", importer->GetStatus().GetErrorString()); exit(-1); } FbxScene* scene = FbxScene::Create(fm, "myscene"); importer->Import(scene); importer->Destroy(); output << "some\n"; output << "charcnt : " << scene->GetCharacterCount() << endl << "node cnt : " << scene->GetNodeCount() << endl; int animstackcnt = scene->GetSrcObjectCount<FbxAnimStack>(); output << "animstackcnt : " << animstackcnt << endl; output << "------------" << endl; vector<FbxNode*> removableNodes; for (int i = 0; i < scene->GetNodeCount(); i++) { FbxNode* node = scene->GetNode(i); output << "scene's node " << i << " : " << node->GetName() << ", childcnt : " << node->GetChildCount(); if (node->GetNodeAttribute()) { output <<", att type : " << node->GetNodeAttribute()->GetAttributeType(); if (node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eMesh) { FbxMesh* mesh = node->GetMesh(); output << ", mem usage : " << mesh->MemoryUsage() << ", deformer cnt : " << mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin) << endl; collapseMesh(mesh); FbxSkin* skin = (FbxSkin*) (mesh->GetDeformer(0, FbxDeformer::EDeformerType::eSkin)); if (skin) { for (int cli = 0; cli < skin->GetClusterCount(); cli++) { FbxCluster* cluster = skin->GetCluster(cli); output << "\tcluster no." << cli << " has " << cluster->GetControlPointIndicesCount() << " connected verts" << endl; if (cluster->GetControlPointIndicesCount() == 0) removableNodes.push_back( cluster->GetLink() ); //cluster-> //skin->RemoveCluster(cluster);효과없음 } } if (mesh->IsTriangleMesh()) { output << "\tit's triangle mesh" << endl; } //mesh->RemoveDeformer(0);효과없음 } else output << endl; } else { output << ", att type : none" << endl; } } for (int rni = 0; rni < removableNodes.size(); rni++) { FbxNode* rnd = removableNodes[rni]; if (rnd && rnd->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eSkeleton) { output3 << rnd->GetName() << " node with no vert attached's curve : " << rnd->GetSrcObjectCount<FbxAnimCurve>() << "," << rnd->GetSrcObjectCount<FbxAnimCurveNode>() << endl; } } output << "-----------animinfo" << endl; int cubic = 0, linear = 0, cons = 0; for (int si = 0; si < animstackcnt; si++) { FbxAnimStack* stack = scene->GetSrcObject<FbxAnimStack>(si); for (int i = 0; i < stack->GetMemberCount<FbxAnimLayer>(); i++) { FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(i); int curvenodecnt = layer->GetMemberCount<FbxAnimCurveNode>(); int compositcnt = 0; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); compositcnt += (cnode->IsComposite() ? 1 : 0); } output << "\tanimstack's layer " << i << " : " << layer->GetName() << ", curve node cnt : " << curvenodecnt << ", composit node cnt : " << compositcnt << endl; vector<FbxAnimCurveNode*> nodes2del; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); output << "\t\tcurvenode " << j << " channel cnt : " << cnode->GetChannelsCount() << ", dst obj cnt " << cnode->GetDstObjectCount() << "("; for (int dsti = 0; dsti < cnode->GetDstObjectCount(); dsti++) { output << "," << cnode->GetDstObject(dsti)->GetName(); if (cnode->GetDstObject(dsti)->GetSrcObjectCount() > 0) output << "<" << cnode->GetDstObject(dsti)->GetSrcObjectCount<FbxSkeleton>() << ">"; } output << ")"; FbxTimeSpan interval; if (cnode->GetAnimationInterval(interval)) { output << ", start : " << interval.GetStart().GetTimeString() << ", end : " << interval.GetStop().GetTimeString() << endl; } else { nodes2del.push_back(cnode); output << ", no interval" << endl; } for (int chi = 0; chi < cnode->GetChannelsCount(); chi++) { int curvecnt = cnode->GetCurveCount(chi); output << "\t\t\tchannel." << chi << " curvecnt : " << curvecnt << endl; for (int ci = 0; ci < curvecnt; ci++) { FbxAnimCurve* curve = cnode->GetCurve(chi, ci); int keycnt = curve->KeyGetCount(); output << "\t\t\t\tcurve no." << ci << " : key count : " << keycnt; output2 << "curve " << ci << endl; vector<int> keys2Remove; for (int cki = 0; cki < keycnt; cki++) { FbxAnimCurveKey prevkey, currkey, nextkey; if (cki == 0 || cki == keycnt - 1) continue; currkey = curve->KeyGet(cki); prevkey = curve->KeyGet(cki-1); nextkey = curve->KeyGet(cki + 1); bool keepit = true; output2 << ci << "-" << cki; // keepit = keepTestHorizon(curve, prevkey, currkey, nextkey); // if (keepit) // keepit = slopkeepTest(curve, prevkey, currkey, nextkey); if (!keepit) { if (!(currkey.GetInterpolation() == FbxAnimCurveDef::EInterpolationType::eInterpolationConstant && nextkey.GetInterpolation() != FbxAnimCurveDef::EInterpolationType::eInterpolationConstant)) keys2Remove.push_back(cki); } } for (int kri = keys2Remove.size() - 1; kri >= 0; kri--) { //curve->KeyRemove(keys2Remove[kri]); } output2 << endl; //output << ", cubic:linear:const : " << cubic << ":" << linear << ":" << cons << endl; if (keys2Remove.size() > 0) output << ", " << keys2Remove.size() << " keys removed"; keycnt = curve->KeyGetCount(); } } } //이부분은 별로 효과없음 /* for (int di = 0; di < nodes2del.size(); di++) { layer->RemoveMember(nodes2del[di]); } */ } } output << "cubic:linear:const " << cubic << ":" << linear << ":" << cons << endl; FbxExporter* exporter = FbxExporter::Create(fm, ""); const char* outFBXName = "after.fbx"; bool exportstatus = exporter->Initialize(outFBXName, -1, fm->GetIOSettings()); if (exportstatus == false) { puts("err export fail"); } exporter->Export(scene); exporter->Destroy(); scene->Destroy(); ios->Destroy(); fm->Destroy(); output.close(); output2.close(); output3.close(); return 0; }
HRESULT CStaticMesh::Load_StaticMesh(const char* szFilePath,const char* szFileName, FbxManager* _pFBXManager, FbxIOSettings* _pIOsettings, FbxScene* _pFBXScene, FbxImporter* _pImporter) { HRESULT hr = E_FAIL; vector<UINT> vecIndeces; string strFullPath; strFullPath.clear(); strFullPath = szFilePath; strFullPath += szFileName;//경로에 파일이름 추가 if (!(_pImporter->Initialize(strFullPath.c_str(), -1, _pFBXManager->GetIOSettings()))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Init Failed"); if (!(_pImporter->Import(_pFBXScene))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Import Failed"); FbxGeometryConverter clsConverter(_pFBXManager); clsConverter.Triangulate(_pFBXScene, false); FbxNode* pRootNode = _pFBXScene->GetRootNode(); if (!pRootNode) return E_FAIL; vector<VTXTEX> vecVTXTEX; for (int i = 0; i < pRootNode->GetChildCount(); ++i) { FbxNode* pChildNode = pRootNode->GetChild(i); if (pChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pChildNode->GetNodeAttribute(); // 임폴트 하려는 메쉬의 데이터 D3DXVECTOR3 vPos; D3DXVECTOR2 vOutUV; D3DXVECTOR3 vOutNormal; FbxVector4* mControlPoints = pMesh->GetControlPoints(); int iVTXCounter = 0; for (int j = 0; j < pMesh->GetPolygonCount(); j++) // 폴리곤의 인덱스 { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); FbxGeometryElementUV* VtxUV = pMesh->GetElementUV(0); FbxGeometryElementNormal* VtxNormal = pMesh->GetElementNormal(0); for (int k = 0; k < iNumVertices; k++) // 폴리곤을 구성하는 버텍스의 인덱스 { //정점 데이터 얻는곳 int iControlPointIndex = pMesh->GetPolygonVertex(j, k); // 컨트롤 포인트 = 하나의 버텍스 int iTextureUVIndex = pMesh->GetTextureUVIndex(j, k); // Control = Vertex //int iNormalIndex = pMesh->GetPolygonVertexIndex(j, k); ++iVTXCounter; vPos.x = (float)mControlPoints[iControlPointIndex].mData[0]; vPos.y = -(float)mControlPoints[iControlPointIndex].mData[1]; vPos.z = (float)mControlPoints[iControlPointIndex].mData[2]; //uv 얻기 switch (VtxUV->GetMappingMode()) // UV값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxUV->GetIndexArray().GetAt(iControlPointIndex); vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } case FbxGeometryElement::eIndexToDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } //노멀얻기 switch (VtxNormal->GetMappingMode()) // 노멀값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[2]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iControlPointIndex); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } VTXTEX vtxtex; vtxtex.vPos = vPos; vtxtex.vNormal = vOutNormal; vtxtex.vTexUV = vOutUV; vecVTXTEX.push_back(vtxtex); //int index = VtxUV->GetIndexArray().GetAt(iTextureUVIndex); vecIndeces.push_back(VtxUV->GetIndexArray().GetAt(iTextureUVIndex)); } } } unsigned int n = vecVTXTEX.size(); VTXTEX* pVTXTex = new VTXTEX[n]; for (unsigned int i = 0; i < vecVTXTEX.size(); ++i) { pVTXTex[i].vPos = vecVTXTEX[i].vPos; pVTXTex[i].vNormal = vecVTXTEX[i].vNormal; pVTXTex[i].vTexUV = vecVTXTEX[i].vTexUV; } m_iVertices = vecVTXTEX.size(); m_iVertexStrides = sizeof(VTXTEX); m_iVertexOffsets = 0; MakeVertexNormal((BYTE*)pVTXTex, NULL); D3D11_BUFFER_DESC tBufferDesc; ZeroMemory(&tBufferDesc, sizeof(D3D11_BUFFER_DESC)); tBufferDesc.Usage = D3D11_USAGE_DEFAULT; tBufferDesc.ByteWidth = m_iVertexStrides * m_iVertices; tBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; tBufferDesc.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA tData; ZeroMemory(&tData, sizeof(D3D11_SUBRESOURCE_DATA)); tData.pSysMem = pVTXTex; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&tBufferDesc, &tData, &m_VertexBuffer); ::Safe_Delete(pVTXTex); if (FAILED(hr)) return E_FAIL; D3D11_BUFFER_DESC cbd; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.ByteWidth = sizeof(ConstantBuffer); cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.CPUAccessFlags = 0; cbd.MiscFlags = 0; cbd.StructureByteStride = 0; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&cbd, NULL, &m_ConstantBuffer); if (FAILED(hr)) { MessageBox(NULL, L"System Message", L"Constant Buffer Error", MB_OK); return hr; } return S_OK; }
HRESULT FBXLoader::loadFBXFile(char* filePath, VertexBuffer** vBuf, IndexBuffer** iBuf, Renderer* renderer, bool centerShift) { if (g_pFbxSdkManager == nullptr) { g_pFbxSdkManager = FbxManager::Create(); FbxIOSettings* pIOsettings = FbxIOSettings::Create(g_pFbxSdkManager, IOSROOT); g_pFbxSdkManager->SetIOSettings(pIOsettings); } this->shiftCenter = centerShift; FbxImporter* pImporter = FbxImporter::Create(g_pFbxSdkManager, ""); FbxScene* pFbxScene = FbxScene::Create(g_pFbxSdkManager, ""); bool bSuccess = pImporter->Initialize(filePath, -1, g_pFbxSdkManager->GetIOSettings()); if (!bSuccess) return E_FAIL; bSuccess = pImporter->Import(pFbxScene); if (!bSuccess) return E_FAIL; FbxAxisSystem sceneAxisSystem = pFbxScene->GetGlobalSettings().GetAxisSystem(); FbxAxisSystem DirectXAxisSystem(FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eLeftHanded); if (sceneAxisSystem != DirectXAxisSystem) { DirectXAxisSystem.ConvertScene(pFbxScene); } pImporter->Destroy(); FbxNode* pFbxRootNode = pFbxScene->GetRootNode(); if (pFbxRootNode) { // Check if the getChildCount is > 1 TODO int test = pFbxRootNode->GetChildCount(); for (int i = 0; i < pFbxRootNode->GetChildCount(); i++) { FbxNode* pFbxChildNode = pFbxRootNode->GetChild(i); if (pFbxChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pFbxChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pFbxChildNode->GetNodeAttribute(); int numControlPoints = pMesh->GetControlPointsCount(); bool initial = true; float xMin, yMin, zMin; float xMax, yMax, zMax; float xIn, yIn, zIn; float xCenter, yCenter, zCenter; if (this->shiftCenter){ for (int c = 0; c < numControlPoints; c++) { xIn = (float)pMesh->GetControlPointAt(c).mData[0]; yIn = (float)pMesh->GetControlPointAt(c).mData[1]; zIn = (float)pMesh->GetControlPointAt(c).mData[2]; if (initial) { xMin = xIn; yMin = yIn; zMin = zIn; xMax = xIn; yMax = yIn; zMax = zIn; initial = false; } else { if (xIn < xMin) { xMin = xIn; } if (yIn < yMin) { yMin = yIn; } if (zIn < zMin) { zMin = zIn; } if (xIn > xMax) { xMax = xIn; } if (yIn > yMax) { yMax = yIn; } if (zIn > zMax) { zMax = zIn; } } } xCenter = (xMin + xMax) / 2.0f; yCenter = (yMin + yMax) / 2.0f; zCenter = (zMin + zMax) / 2.0f; } else { xCenter = 0; yCenter = 0; zCenter = 0; } FbxVector4* pVertices = pMesh->GetControlPoints(); int vertexCount = pMesh->GetPolygonVertexCount(); //Vertex vertex; Vertex* vertexArray = new Vertex[vertexCount]; //Vertex vertexArray[2592]; int numIndices = vertexCount; unsigned int* indexArray = new unsigned int[numIndices]; FbxVector4 fbxNorm(0, 0, 0, 0); FbxVector2 fbxUV(0, 0); bool isMapped; int vertexIndex = 0; // Loop iterates through the polygons and fills the vertex and index arrays for the buffers for (int j = 0; j < pMesh->GetPolygonCount(); j++) { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); //1st vertex int controlIndex = pMesh->GetPolygonVertex(j, 2); pMesh->GetPolygonVertexUV(j, 2, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 2, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //2nd vertex controlIndex = pMesh->GetPolygonVertex(j, 1); pMesh->GetPolygonVertexUV(j, 1, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 1, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //3rd vertex controlIndex = pMesh->GetPolygonVertex(j, 0); pMesh->GetPolygonVertexUV(j, 0, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 0, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; } // Generate vertex and index buffers from the vertex and index arrays *vBuf = renderer->createVertexBuffer(vertexArray, vertexCount); *iBuf = renderer->createIndexBuffer(indexArray, numIndices); delete[] vertexArray; delete[] indexArray; } } return S_OK; }
UObject* UFbxFactory::RecursiveImportNode(void* VoidFbxImporter, void* VoidNode, UObject* InParent, FName InName, EObjectFlags Flags, int32& NodeIndex, int32 Total, TArray<UObject*>& OutNewAssets) { UObject* NewObject = NULL; FbxNode* Node = (FbxNode*)VoidNode; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup && Node->GetChildCount() > 0 ) { // import base mesh NewObject = ImportANode(VoidFbxImporter, Node->GetChild(0), InParent, InName, Flags, NodeIndex, Total); if ( NewObject ) { OutNewAssets.Add(NewObject); } bool bImportMeshLODs; if ( ImportUI->MeshTypeToImport == FBXIT_StaticMesh ) { bImportMeshLODs = ImportUI->StaticMeshImportData->bImportMeshLODs; } else if ( ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh ) { bImportMeshLODs = ImportUI->SkeletalMeshImportData->bImportMeshLODs; } else { bImportMeshLODs = false; } if (NewObject && bImportMeshLODs) { // import LOD meshes for (int32 LODIndex = 1; LODIndex < Node->GetChildCount(); LODIndex++) { FbxNode* ChildNode = Node->GetChild(LODIndex); ImportANode(VoidFbxImporter, ChildNode, InParent, InName, Flags, NodeIndex, Total, NewObject, LODIndex); } } } else { if (Node->GetMesh()) { NewObject = ImportANode(VoidFbxImporter, Node, InParent, InName, Flags, NodeIndex, Total); if ( NewObject ) { OutNewAssets.Add(NewObject); } } for (int32 ChildIndex=0; ChildIndex<Node->GetChildCount(); ++ChildIndex) { UObject* SubObject = RecursiveImportNode(VoidFbxImporter,Node->GetChild(ChildIndex),InParent,InName,Flags,NodeIndex,Total,OutNewAssets); if ( SubObject ) { OutNewAssets.Add(SubObject); } if (NewObject==NULL) { NewObject = SubObject; } } } return NewObject; }
UObject* UFbxFactory::FactoryCreateBinary ( UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn, bool& bOutOperationCanceled ) { if( bOperationCanceled ) { bOutOperationCanceled = true; FEditorDelegates::OnAssetPostImport.Broadcast(this, NULL); return NULL; } FEditorDelegates::OnAssetPreImport.Broadcast(this, Class, InParent, Name, Type); UObject* NewObject = NULL; if ( bDetectImportTypeOnImport ) { if ( !DetectImportType(UFactory::CurrentFilename) ) { // Failed to read the file info, fail the import FEditorDelegates::OnAssetPostImport.Broadcast(this, NULL); return NULL; } } // logger for all error/warnings // this one prints all messages that are stored in FFbxImporter UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance(); UnFbx::FFbxLoggerSetter Logger(FbxImporter); EFBXImportType ForcedImportType = FBXIT_StaticMesh; bool bIsObjFormat = false; if( FString(Type).Equals(TEXT("obj"), ESearchCase::IgnoreCase ) ) { bIsObjFormat = true; } bool bShowImportDialog = bShowOption && !GIsAutomationTesting; bool bImportAll = false; UnFbx::FBXImportOptions* ImportOptions = GetImportOptions(FbxImporter, ImportUI, bShowImportDialog, InParent->GetPathName(), bOperationCanceled, bImportAll, bIsObjFormat, bIsObjFormat, ForcedImportType ); bOutOperationCanceled = bOperationCanceled; if( bImportAll ) { // If the user chose to import all, we don't show the dialog again and use the same settings for each object until importing another set of files bShowOption = false; } // For multiple files, use the same settings bDetectImportTypeOnImport = false; if (ImportOptions) { Warn->BeginSlowTask( NSLOCTEXT("FbxFactory", "BeginImportingFbxMeshTask", "Importing FBX mesh"), true ); if ( !FbxImporter->ImportFromFile( *UFactory::CurrentFilename, Type ) ) { // Log the error message and fail the import. Warn->Log(ELogVerbosity::Error, FbxImporter->GetErrorMessage() ); } else { // Log the import message and import the mesh. const TCHAR* errorMessage = FbxImporter->GetErrorMessage(); if (errorMessage[0] != '\0') { Warn->Log( errorMessage ); } FbxNode* RootNodeToImport = NULL; RootNodeToImport = FbxImporter->Scene->GetRootNode(); // For animation and static mesh we assume there is at lease one interesting node by default int32 InterestingNodeCount = 1; TArray< TArray<FbxNode*>* > SkelMeshArray; bool bImportStaticMeshLODs = ImportUI->StaticMeshImportData->bImportMeshLODs; bool bCombineMeshes = ImportUI->bCombineMeshes; if ( ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh ) { FbxImporter->FillFbxSkelMeshArrayInScene(RootNodeToImport, SkelMeshArray, false); InterestingNodeCount = SkelMeshArray.Num(); } else if( ImportUI->MeshTypeToImport == FBXIT_StaticMesh ) { FbxImporter->ApplyTransformSettingsToFbxNode(RootNodeToImport, ImportUI->StaticMeshImportData); if( bCombineMeshes && !bImportStaticMeshLODs ) { // If Combine meshes and dont import mesh LODs, the interesting node count should be 1 so all the meshes are grouped together into one static mesh InterestingNodeCount = 1; } else { // count meshes in lod groups if we dont care about importing LODs bool bCountLODGroupMeshes = !bImportStaticMeshLODs; int32 NumLODGroups = 0; InterestingNodeCount = FbxImporter->GetFbxMeshCount(RootNodeToImport,bCountLODGroupMeshes,NumLODGroups); // if there were LODs in the file, do not combine meshes even if requested if( bImportStaticMeshLODs && bCombineMeshes ) { bCombineMeshes = NumLODGroups == 0; } } } if (InterestingNodeCount > 1) { // the option only works when there are only one asset ImportOptions->bUsedAsFullName = false; } const FString Filename( UFactory::CurrentFilename ); if (RootNodeToImport && InterestingNodeCount > 0) { int32 NodeIndex = 0; int32 ImportedMeshCount = 0; UStaticMesh* NewStaticMesh = NULL; if ( ImportUI->MeshTypeToImport == FBXIT_StaticMesh ) // static mesh { if (bCombineMeshes) { TArray<FbxNode*> FbxMeshArray; FbxImporter->FillFbxMeshArray(RootNodeToImport, FbxMeshArray, FbxImporter); if (FbxMeshArray.Num() > 0) { NewStaticMesh = FbxImporter->ImportStaticMeshAsSingle(InParent, FbxMeshArray, Name, Flags, ImportUI->StaticMeshImportData, NULL, 0); } ImportedMeshCount = NewStaticMesh ? 1 : 0; } else { TArray<UObject*> AllNewAssets; UObject* Object = RecursiveImportNode(FbxImporter,RootNodeToImport,InParent,Name,Flags,NodeIndex,InterestingNodeCount, AllNewAssets); NewStaticMesh = Cast<UStaticMesh>( Object ); // Make sure to notify the asset registry of all assets created other than the one returned, which will notify the asset registry automatically. for ( auto AssetIt = AllNewAssets.CreateConstIterator(); AssetIt; ++AssetIt ) { UObject* Asset = *AssetIt; if ( Asset != NewStaticMesh ) { FAssetRegistryModule::AssetCreated(Asset); Asset->MarkPackageDirty(); } } ImportedMeshCount = AllNewAssets.Num(); } // Importing static mesh sockets only works if one mesh is being imported if( ImportedMeshCount == 1 && NewStaticMesh ) { FbxImporter->ImportStaticMeshSockets( NewStaticMesh ); } NewObject = NewStaticMesh; } else if ( ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh )// skeletal mesh { int32 TotalNumNodes = 0; for (int32 i = 0; i < SkelMeshArray.Num(); i++) { TArray<FbxNode*> NodeArray = *SkelMeshArray[i]; TotalNumNodes += NodeArray.Num(); // check if there is LODGroup for this skeletal mesh int32 MaxLODLevel = 1; for (int32 j = 0; j < NodeArray.Num(); j++) { FbxNode* Node = NodeArray[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { // get max LODgroup level if (MaxLODLevel < Node->GetChildCount()) { MaxLODLevel = Node->GetChildCount(); } } } int32 LODIndex; bool bImportSkeletalMeshLODs = ImportUI->SkeletalMeshImportData->bImportMeshLODs; for (LODIndex = 0; LODIndex < MaxLODLevel; LODIndex++) { if ( !bImportSkeletalMeshLODs && LODIndex > 0) // not import LOD if UI option is OFF { break; } TArray<FbxNode*> SkelMeshNodeArray; for (int32 j = 0; j < NodeArray.Num(); j++) { FbxNode* Node = NodeArray[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { if (Node->GetChildCount() > LODIndex) { SkelMeshNodeArray.Add(Node->GetChild(LODIndex)); } else // in less some LODGroups have less level, use the last level { SkelMeshNodeArray.Add(Node->GetChild(Node->GetChildCount() - 1)); } } else { SkelMeshNodeArray.Add(Node); } } if (LODIndex == 0 && SkelMeshNodeArray.Num() != 0) { FName OutputName = FbxImporter->MakeNameForMesh(Name.ToString(), SkelMeshNodeArray[0]); USkeletalMesh* NewMesh = FbxImporter->ImportSkeletalMesh( InParent, SkelMeshNodeArray, OutputName, Flags, ImportUI->SkeletalMeshImportData, &bOperationCanceled ); NewObject = NewMesh; if(bOperationCanceled) { // User cancelled, clean up and return FbxImporter->ReleaseScene(); Warn->EndSlowTask(); bOperationCanceled = true; return nullptr; } if ( NewMesh && ImportUI->bImportAnimations ) { // We need to remove all scaling from the root node before we set up animation data. // Othewise some of the global transform calculations will be incorrect. FbxImporter->RemoveTransformSettingsFromFbxNode(RootNodeToImport, ImportUI->SkeletalMeshImportData); FbxImporter->SetupAnimationDataFromMesh(NewMesh, InParent, SkelMeshNodeArray, ImportUI->AnimSequenceImportData, OutputName.ToString()); // Reapply the transforms for the rest of the import FbxImporter->ApplyTransformSettingsToFbxNode(RootNodeToImport, ImportUI->SkeletalMeshImportData); } } else if (NewObject) // the base skeletal mesh is imported successfully { USkeletalMesh* BaseSkeletalMesh = Cast<USkeletalMesh>(NewObject); FName LODObjectName = NAME_None; USkeletalMesh *LODObject = FbxImporter->ImportSkeletalMesh( GetTransientPackage(), SkelMeshNodeArray, LODObjectName, RF_NoFlags, ImportUI->SkeletalMeshImportData, &bOperationCanceled ); bool bImportSucceeded = !bOperationCanceled && FbxImporter->ImportSkeletalMeshLOD(LODObject, BaseSkeletalMesh, LODIndex, false); if (bImportSucceeded) { BaseSkeletalMesh->LODInfo[LODIndex].ScreenSize = 1.0f / (MaxLODLevel * LODIndex); } else { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_SkeletalMeshLOD", "Failed to import Skeletal mesh LOD.")), FFbxErrors::SkeletalMesh_LOD_FailedToImport); } } // import morph target if ( NewObject && ImportUI->SkeletalMeshImportData->bImportMorphTargets) { // Disable material importing when importing morph targets uint32 bImportMaterials = ImportOptions->bImportMaterials; ImportOptions->bImportMaterials = 0; FbxImporter->ImportFbxMorphTarget(SkelMeshNodeArray, Cast<USkeletalMesh>(NewObject), InParent, LODIndex); ImportOptions->bImportMaterials = !!bImportMaterials; } } if (NewObject) { NodeIndex++; FFormatNamedArguments Args; Args.Add( TEXT("NodeIndex"), NodeIndex ); Args.Add( TEXT("ArrayLength"), SkelMeshArray.Num() ); GWarn->StatusUpdate( NodeIndex, SkelMeshArray.Num(), FText::Format( NSLOCTEXT("UnrealEd", "Importingf", "Importing ({NodeIndex} of {ArrayLength})"), Args ) ); } } for (int32 i = 0; i < SkelMeshArray.Num(); i++) { delete SkelMeshArray[i]; } // if total nodes we found is 0, we didn't find anything. if (TotalNumNodes == 0) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_NoMeshFoundOnRoot", "Could not find any valid mesh on the root hierarchy. If you have mesh in the sub hierarchy, please enable option of [Import Meshes In Bone Hierarchy] when import.")), FFbxErrors::SkeletalMesh_NoMeshFoundOnRoot); } } else if ( ImportUI->MeshTypeToImport == FBXIT_Animation )// animation { if (ImportOptions->SkeletonForAnimation) { // will return the last animation sequence that were added NewObject = UEditorEngine::ImportFbxAnimation( ImportOptions->SkeletonForAnimation, InParent, ImportUI->AnimSequenceImportData, *Filename, *Name.ToString(), true ); } } } else { if (RootNodeToImport == NULL) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidRoot", "Could not find root node.")), FFbxErrors::SkeletalMesh_InvalidRoot); } else if (ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidBone", "Failed to find any bone hierarchy. Try disabling the \"Import As Skeletal\" option to import as a rigid mesh. ")), FFbxErrors::SkeletalMesh_InvalidBone); } else { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidNode", "Could not find any node.")), FFbxErrors::SkeletalMesh_InvalidNode); } } } if (NewObject == NULL) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_NoObject", "Import failed.")), FFbxErrors::Generic_ImportingNewObjectFailed); } FbxImporter->ReleaseScene(); Warn->EndSlowTask(); } FEditorDelegates::OnAssetPostImport.Broadcast(this, NewObject); return NewObject; }
// This method is templated on the implementation of hctMayaSceneExporter::createHkxNodes() void FbxToHkxConverter::addNodesRecursive(hkxScene *scene, FbxNode* fbxNode, hkxNode* node, int animStackIndex) { for (int childIndex = 0; childIndex < fbxNode->GetChildCount(); childIndex++) { FbxNode* fbxChildNode = fbxNode->GetChild(childIndex); FbxNodeAttribute* fbxNodeAtttrib = fbxChildNode->GetNodeAttribute(); bool selected = fbxChildNode->GetSelected(); // Ignore nodes(and their descendants) if they're invisible and we ignore invisible objects if ( !(!m_options.m_visibleOnly || fbxNode->GetVisibility()) ) continue; // Ignore nodes(and their descendants) if they're not selected and we ignore deselected objects if ( !(!m_options.m_selectedOnly || selected) ) continue; hkxNode* newChildNode = new hkxNode(); { newChildNode->m_name = fbxChildNode->GetName(); node->m_children.pushBack(newChildNode); } newChildNode->m_selected = selected; // Extract the following types of data from this node (taken from hkxScene.h): if (fbxNodeAtttrib != NULL) { switch (fbxNodeAtttrib->GetAttributeType()) { case FbxNodeAttribute::eMesh: { // Generate hkxMesh and all its dependent data (ie: hkxSkinBinding, hkxMeshSection, hkxMaterial) if (m_options.m_exportMeshes) { addMesh(scene, fbxChildNode, newChildNode); } break; } case FbxNodeAttribute::eNurbsCurve: { if (m_options.m_exportSplines) { addSpline(scene, fbxChildNode, newChildNode); } break; } case FbxNodeAttribute::eCamera: { // Generate hkxCamera if (m_options.m_exportCameras) { addCamera(scene, fbxChildNode, newChildNode); } break; } case FbxNodeAttribute::eLight: { // Generate hkxLight if (m_options.m_exportLights) { addLight(scene, fbxChildNode, newChildNode); } break; } case FbxNodeAttribute::eSkeleton: { // Flag this node as a bone if it's associated with a skeleton attribute newChildNode->m_bone = true; break; } default: break; } } // Extract this node's animation data and bind transform extractKeyFramesAndAnnotations(scene, fbxChildNode, newChildNode, animStackIndex); if (m_options.m_exportAttributes) { addSampledNodeAttributeGroups(scene, animStackIndex, fbxChildNode, newChildNode); } GetCustomVisionData(fbxChildNode, newChildNode->m_userProperties); addNodesRecursive(scene, fbxChildNode, newChildNode, animStackIndex); newChildNode->removeReference(); } }
// Find the current camera at the given time. FbxCamera* GetCurrentCamera(FbxScene* pScene, FbxTime& pTime, FbxAnimLayer* pAnimLayer, const FbxArray<FbxNode*>& pCameraArray) { FbxGlobalSettings& lGlobalSettings = pScene->GetGlobalSettings(); FbxGlobalCameraSettings& lGlobalCameraSettings = pScene->GlobalCameraSettings(); FbxString lCurrentCameraName = lGlobalSettings.GetDefaultCamera(); // check if we need to create the Producer cameras! if (lGlobalCameraSettings.GetCameraProducerPerspective() == NULL && lGlobalCameraSettings.GetCameraProducerBottom() == NULL && lGlobalCameraSettings.GetCameraProducerTop() == NULL && lGlobalCameraSettings.GetCameraProducerFront() == NULL && lGlobalCameraSettings.GetCameraProducerBack() == NULL && lGlobalCameraSettings.GetCameraProducerRight() == NULL && lGlobalCameraSettings.GetCameraProducerLeft() == NULL) { lGlobalCameraSettings.CreateProducerCameras(); } if (lCurrentCameraName.Compare(FBXSDK_CAMERA_PERSPECTIVE) == 0) { return lGlobalCameraSettings.GetCameraProducerPerspective(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_BOTTOM) == 0) { return lGlobalCameraSettings.GetCameraProducerBottom(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_TOP) == 0) { return lGlobalCameraSettings.GetCameraProducerTop(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_FRONT) == 0) { return lGlobalCameraSettings.GetCameraProducerFront(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_BACK) == 0) { return lGlobalCameraSettings.GetCameraProducerBack(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_RIGHT) == 0) { return lGlobalCameraSettings.GetCameraProducerRight(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_LEFT) == 0) { return lGlobalCameraSettings.GetCameraProducerLeft(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_SWITCHER) == 0) { FbxCameraSwitcher* lCameraSwitcher = pScene->GlobalCameraSettings().GetCameraSwitcher(); FbxAnimCurve* lCurve = NULL; if (lCameraSwitcher) { lCurve = lCameraSwitcher->CameraIndex.GetCurve(pAnimLayer); int lCameraIndex = lCurve ? int(lCurve->Evaluate(pTime)) - 1 : 0; if (lCameraIndex >= 0 && lCameraIndex < pCameraArray.GetCount()) { FbxNode* lNode = pCameraArray[lCameraIndex]; // Get the animated parameters of the camera. GetCameraAnimatedParameters(lNode, pTime, pAnimLayer); return (FbxCamera*) lNode->GetNodeAttribute(); } } } else { int i; FbxNode* lNode = NULL; // Find the camera in the camera array. for (i = 0; i < pCameraArray.GetCount(); i++) { if (lCurrentCameraName.Compare(pCameraArray[i]->GetName()) == 0) { lNode = pCameraArray[i]; break; } } if (lNode) { // Get the animated parameters of the camera. GetCameraAnimatedParameters(lNode, pTime, pAnimLayer); return (FbxCamera*) lNode->GetNodeAttribute(); } } return lGlobalCameraSettings.GetCameraProducerPerspective(); }