/** * Adds Fbx Clusters necessary to skin a skeletal mesh to the bones in the BoneNodes list */ void FFbxExporter::BindMeshToSkeleton(const USkeletalMesh* SkelMesh, FbxNode* MeshRootNode, TArray<FbxNode*>& BoneNodes) { const FSkeletalMeshResource* SkelMeshResource = SkelMesh->GetImportedResource(); const FStaticLODModel& SourceModel = SkelMeshResource->LODModels[0]; const int32 VertexCount = SourceModel.NumVertices; FbxAMatrix MeshMatrix; FbxScene* lScene = MeshRootNode->GetScene(); if( lScene ) { MeshMatrix = MeshRootNode->EvaluateGlobalTransform(); } FbxGeometry* MeshAttribute = (FbxGeometry*) MeshRootNode->GetNodeAttribute(); FbxSkin* Skin = FbxSkin::Create(Scene, ""); const int32 BoneCount = BoneNodes.Num(); for(int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { FbxNode* BoneNode = BoneNodes[BoneIndex]; // Create the deforming cluster FbxCluster *CurrentCluster = FbxCluster::Create(Scene,""); CurrentCluster->SetLink(BoneNode); CurrentCluster->SetLinkMode(FbxCluster::eTotalOne); // Add all the vertices that are weighted to the current skeletal bone to the cluster // NOTE: the bone influence indices contained in the vertex data are based on a per-chunk // list of verts. The convert the chunk bone index to the mesh bone index, the chunk's // boneMap is needed int32 VertIndex = 0; const int32 SectionCount = SourceModel.Sections.Num(); for(int32 SectionIndex = 0; SectionIndex < SectionCount; ++SectionIndex) { const FSkelMeshSection& Section = SourceModel.Sections[SectionIndex]; for(int32 SoftIndex = 0; SoftIndex < Section.SoftVertices.Num(); ++SoftIndex) { const FSoftSkinVertex& Vert = Section.SoftVertices[SoftIndex]; for(int32 InfluenceIndex = 0; InfluenceIndex < MAX_TOTAL_INFLUENCES; ++InfluenceIndex) { int32 InfluenceBone = Section.BoneMap[ Vert.InfluenceBones[InfluenceIndex] ]; float InfluenceWeight = Vert.InfluenceWeights[InfluenceIndex] / 255.f; if(InfluenceBone == BoneIndex && InfluenceWeight > 0.f) { CurrentCluster->AddControlPointIndex(VertIndex, InfluenceWeight); } } ++VertIndex; } } // Now we have the Patch and the skeleton correctly positioned, // set the Transform and TransformLink matrix accordingly. CurrentCluster->SetTransformMatrix(MeshMatrix); FbxAMatrix LinkMatrix; if( lScene ) { LinkMatrix = BoneNode->EvaluateGlobalTransform(); } CurrentCluster->SetTransformLinkMatrix(LinkMatrix); // Add the clusters to the mesh by creating a skin and adding those clusters to that skin. Skin->AddCluster(CurrentCluster); } // Add the skin to the mesh after the clusters have been added MeshAttribute->AddDeformer(Skin); }
void ExportFbxMesh(const Value& obj) { string name = obj["Name"].GetString(); FbxNode* pNode = FbxNode::Create(pManager, name.c_str()); FbxMesh* pMesh = FbxMesh::Create(pManager, name.c_str()); pNode->AddNodeAttribute(pMesh); pScene->GetRootNode()->AddChild(pNode); int numVertex = obj["NumVertex"].GetInt(); { pMesh->InitControlPoints(numVertex); FbxVector4* lControlPoints = pMesh->GetControlPoints(); const Value& pos = obj["Position"]; for (int i = 0; i < numVertex; i++) { double x = pos[i * 3 + 0].GetDouble(); x = -x; double y = pos[i * 3 + 1].GetDouble(); double z = pos[i * 3 + 2].GetDouble(); lControlPoints[i] = FbxVector4(x, y, z); } } { FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal(); lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxVector4>& array = lGeometryElementNormal->GetDirectArray(); const Value& normal = obj["Normal"]; for (int i = 0; i < numVertex; i++) { double x = normal[i * 3 + 0].GetDouble(); x = -x; double y = normal[i * 3 + 1].GetDouble(); double z = normal[i * 3 + 2].GetDouble(); array.Add(FbxVector4(x, y, z)); } } { FbxGeometryElementUV* lUVDiffuseElement = pMesh->CreateElementUV("DiffuseUV"); FBX_ASSERT(lUVDiffuseElement != NULL); lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint); lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxVector2>& array = lUVDiffuseElement->GetDirectArray(); const Value& v = obj["UV0"]; for (int i = 0; i < numVertex; i++) { double x = v[i * 2 + 0].GetDouble(); double y = v[i * 2 + 1].GetDouble(); array.Add(FbxVector2(x, y)); } } { const Value& color = obj["Color"]; if (!color.IsNull()) { FbxGeometryElementVertexColor* pColorElement = pMesh->CreateElementVertexColor(); FBX_ASSERT(pColorElement != NULL); pColorElement->SetMappingMode(FbxGeometryElement::eByControlPoint); pColorElement->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxColor>& array = pColorElement->GetDirectArray(); for (int i = 0; i < numVertex; i++) { double r = color[i * 4 + 0].GetDouble(); double g = color[i * 4 + 1].GetDouble(); double b = color[i * 4 + 2].GetDouble(); double a = color[i * 4 + 3].GetDouble(); array.Add(FbxColor(r, g, b, a)); } } } { const Value& Indeices = obj["Indeices"]; for (uint32_t subMesh = 0; subMesh < Indeices.Size(); subMesh++) { const Value& index0 = Indeices[subMesh]; int numIndex = index0.Size(); printf("index %d\n", numIndex); for (int i = 0; i < numIndex / 3; i++) { pMesh->BeginPolygon(-1, -1, subMesh); int index[3] = { index0[i * 3 + 0].GetInt(), index0[i * 3 + 1].GetInt(), index0[i * 3 + 2].GetInt(), }; pMesh->AddPolygon(index[0]); pMesh->AddPolygon(index[2]); pMesh->AddPolygon(index[1]); pMesh->EndPolygon(); } } } ////////////////////////////////////////////////////////////////////////// // export skin const Value& boneIndex = obj["BoneIndex"]; if (!boneIndex.IsNull()) { if (fbxBones.empty()) { printf("no bones, can not export skin"); return; } const Value& boneWeight = obj["BoneWeight"]; vector<FbxCluster*> clusters(fbxBones.size(), NULL); for (uint32_t i = 0; i < fbxBones.size(); i++) { FbxCluster* pCluster = FbxCluster::Create(pScene, ""); pCluster->SetLink(fbxBones[i]); pCluster->SetLinkMode(FbxCluster::eTotalOne); clusters[i] = pCluster; } for (int i = 0; i < numVertex; i++) { for (int j = 0; j < 4; j++) { int bone = boneIndex[i * 4 + j].GetInt(); double weight = boneWeight[i * 4 + j].GetDouble(); clusters[bone]->AddControlPointIndex(i, weight); } } FbxSkin* lSkin = FbxSkin::Create(pScene, ""); FbxScene* p = pNode->GetScene(); FbxAMatrix modelMatrix = pNode->EvaluateGlobalTransform(); for (uint32_t i = 0; i < clusters.size(); i++) { clusters[i]->SetTransformMatrix(modelMatrix); FbxAMatrix boneMatrix = fbxBones[i]->EvaluateGlobalTransform(); clusters[i]->SetTransformLinkMatrix(boneMatrix); lSkin->AddCluster(clusters[i]); } pMesh->AddDeformer(lSkin); } }