/** * Adds an Fbx Mesh to the FBX scene based on the data in the given FStaticLODModel */ FbxNode* FFbxExporter::CreateMesh(const USkeletalMesh* SkelMesh, const TCHAR* MeshName) { const FSkeletalMeshResource* SkelMeshResource = SkelMesh->GetImportedResource(); const FStaticLODModel& SourceModel = SkelMeshResource->LODModels[0]; const int32 VertexCount = SourceModel.NumVertices; // Verify the integrity of the mesh. if (VertexCount == 0) return NULL; // Copy all the vertex data from the various chunks to a single buffer. // Makes the rest of the code in this function cleaner and easier to maintain. TArray<FSoftSkinVertex> Vertices; SourceModel.GetVertices(Vertices); if (Vertices.Num() != VertexCount) return NULL; FbxMesh* Mesh = FbxMesh::Create(Scene, TCHAR_TO_UTF8(MeshName)); // Create and fill in the vertex position data source. Mesh->InitControlPoints(VertexCount); FbxVector4* ControlPoints = Mesh->GetControlPoints(); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FVector Position = Vertices[VertIndex].Position; ControlPoints[VertIndex] = Converter.ConvertToFbxPos(Position); } // Create Layer 0 to hold the normals FbxLayer* LayerZero = Mesh->GetLayer(0); if (LayerZero == NULL) { Mesh->CreateLayer(); LayerZero = Mesh->GetLayer(0); } // Create and fill in the per-face-vertex normal data source. // We extract the Z-tangent and drop the X/Y-tangents which are also stored in the render mesh. FbxLayerElementNormal* LayerElementNormal= FbxLayerElementNormal::Create(Mesh, ""); LayerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint); // Set the normal values for every control point. LayerElementNormal->SetReferenceMode(FbxLayerElement::eDirect); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FVector Normal = Vertices[VertIndex].TangentZ; FbxVector4 FbxNormal = Converter.ConvertToFbxPos(Normal); LayerElementNormal->GetDirectArray().Add(FbxNormal); } LayerZero->SetNormals(LayerElementNormal); // Create and fill in the per-face-vertex texture coordinate data source(s). // Create UV for Diffuse channel. const int32 TexCoordSourceCount = SourceModel.NumTexCoords; TCHAR UVChannelName[32]; for (int32 TexCoordSourceIndex = 0; TexCoordSourceIndex < TexCoordSourceCount; ++TexCoordSourceIndex) { FbxLayer* Layer = Mesh->GetLayer(TexCoordSourceIndex); if (Layer == NULL) { Mesh->CreateLayer(); Layer = Mesh->GetLayer(TexCoordSourceIndex); } if (TexCoordSourceIndex == 1) { FCString::Sprintf(UVChannelName, TEXT("LightMapUV")); } else { FCString::Sprintf(UVChannelName, TEXT("DiffuseUV")); } FbxLayerElementUV* UVDiffuseLayer = FbxLayerElementUV::Create(Mesh, TCHAR_TO_UTF8(UVChannelName)); UVDiffuseLayer->SetMappingMode(FbxLayerElement::eByControlPoint); UVDiffuseLayer->SetReferenceMode(FbxLayerElement::eDirect); // Create the texture coordinate data source. for (int32 TexCoordIndex = 0; TexCoordIndex < VertexCount; ++TexCoordIndex) { const FVector2D& TexCoord = Vertices[TexCoordIndex].UVs[TexCoordSourceIndex]; UVDiffuseLayer->GetDirectArray().Add(FbxVector2(TexCoord.X, -TexCoord.Y + 1.0)); } Layer->SetUVs(UVDiffuseLayer, FbxLayerElement::eTextureDiffuse); } FbxLayerElementMaterial* MatLayer = FbxLayerElementMaterial::Create(Mesh, ""); MatLayer->SetMappingMode(FbxLayerElement::eByPolygon); MatLayer->SetReferenceMode(FbxLayerElement::eIndexToDirect); LayerZero->SetMaterials(MatLayer); // Create the per-material polygons sets. TArray<uint32> Indices; SourceModel.MultiSizeIndexContainer.GetIndexBuffer(Indices); int32 SectionCount = SourceModel.Sections.Num(); for (int32 SectionIndex = 0; SectionIndex < SectionCount; ++SectionIndex) { const FSkelMeshSection& Section = SourceModel.Sections[SectionIndex]; int32 MatIndex = Section.MaterialIndex; // Static meshes contain one triangle list per element. int32 TriangleCount = Section.NumTriangles; // Copy over the index buffer into the FBX polygons set. for (int32 TriangleIndex = 0; TriangleIndex < TriangleCount; ++TriangleIndex) { Mesh->BeginPolygon(MatIndex); for (int32 PointIndex = 0; PointIndex < 3; PointIndex++) { Mesh->AddPolygon(Indices[Section.BaseIndex + ((TriangleIndex * 3) + PointIndex)]); } Mesh->EndPolygon(); } } // Create and fill in the vertex color data source. FbxLayerElementVertexColor* VertexColor = FbxLayerElementVertexColor::Create(Mesh, ""); VertexColor->SetMappingMode(FbxLayerElement::eByControlPoint); VertexColor->SetReferenceMode(FbxLayerElement::eDirect); FbxLayerElementArrayTemplate<FbxColor>& VertexColorArray = VertexColor->GetDirectArray(); LayerZero->SetVertexColors(VertexColor); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FLinearColor VertColor = Vertices[VertIndex].Color.ReinterpretAsLinear(); VertexColorArray.Add( FbxColor(VertColor.R, VertColor.G, VertColor.B, VertColor.A )); } FbxNode* MeshNode = FbxNode::Create(Scene, TCHAR_TO_UTF8(MeshName)); MeshNode->SetNodeAttribute(Mesh); // Add the materials for the mesh int32 MaterialCount = SkelMesh->Materials.Num(); for(int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex) { UMaterialInterface* MatInterface = SkelMesh->Materials[MaterialIndex].MaterialInterface; FbxSurfaceMaterial* FbxMaterial = NULL; if(MatInterface && !FbxMaterials.Find(MatInterface)) { FbxMaterial = ExportMaterial(MatInterface); } else { // Note: The vertex data relies on there being a set number of Materials. // If you try to add the same material again it will not be added, so create a // default material with a unique name to ensure the proper number of materials TCHAR NewMaterialName[MAX_SPRINTF]=TEXT(""); FCString::Sprintf( NewMaterialName, TEXT("Fbx Default Material %i"), MaterialIndex ); FbxMaterial = FbxSurfaceLambert::Create(Scene, TCHAR_TO_UTF8(NewMaterialName)); ((FbxSurfaceLambert*)FbxMaterial)->Diffuse.Set(FbxDouble3(0.72, 0.72, 0.72)); } MeshNode->AddMaterial(FbxMaterial); } int32 SavedMaterialCount = MeshNode->GetMaterialCount(); check(SavedMaterialCount == MaterialCount); return MeshNode; }
void FbxLoader::LoadAttribute(FbxNodeAttribute* pAttribute) { if (pAttribute->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh* pMesh = (FbxMesh*)pAttribute; FbxVector4* IControlPoints = pMesh->GetControlPoints(); m_vertexCount = pMesh->GetControlPointsCount(); m_vertexBuffer = new float[m_vertexCount * 4]; for (int i = 0; i < m_vertexCount * 4; i+=4) { m_vertexBuffer[i] = (float)IControlPoints[i / 4].mData[0]; m_vertexBuffer[i + 1] = (float)IControlPoints[i / 4].mData[1]; m_vertexBuffer[i + 2] = (float)IControlPoints[i / 4].mData[2]; m_vertexBuffer[i + 3] = 1.0f;// IControlPoints[i / 4].mData[3]; } int* pIndices = pMesh->GetPolygonVertices(); m_indexCount = pMesh->GetPolygonVertexCount(); m_indexBuffer = new uint32[m_indexCount]; for (int i = 0; i < m_indexCount; ++i) { m_indexBuffer[i] = pIndices[i]; } FbxLayer* pLayer = pMesh->GetLayer(0); if (pLayer != NULL) { FbxLayerElementNormal* pNormal = pLayer->GetNormals(); m_normalCount = pNormal->mDirectArray->GetCount(); m_normalBuffer = new float[m_normalCount * 3]; for (int i = 0; i < m_normalCount * 3; i+=3) { m_normalBuffer[i] = (float)(*pNormal->mDirectArray)[i / 3][0]; m_normalBuffer[i + 1] = (float)(*pNormal->mDirectArray)[i / 3][1]; m_normalBuffer[i + 2] = (float)(*pNormal->mDirectArray)[i / 3][2]; //m_normalBuffer[i + 3] = (*pNormal->mDirectArray)[i / 4][3]; } FbxLayerElementUV* pUV = pLayer->GetUVs(); if (pUV->GetMappingMode() == FbxLayerElement::eByPolygonVertex) { if (pUV->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { m_uvCount = pUV->mIndexArray->GetCount(); m_uvBuffer = new float[m_uvCount * 2]; for (int i = 0; i < m_uvCount * 2; i+=2) { m_uvBuffer[i] = (float)(*pUV->mDirectArray)[(*pUV->mIndexArray)[i / 2]][0]; m_uvBuffer[i + 1] = (float)(*pUV->mDirectArray)[(*pUV->mIndexArray)[i / 2]][1]; } } else { m_uvCount = pUV->mDirectArray->GetCount(); m_uvBuffer = new float[m_uvCount * 2]; for (int i = 0; i < m_uvCount * 2; i += 2) { m_uvBuffer[i] = (float)(*pUV->mDirectArray)[i / 2][0]; m_uvBuffer[i + 1] = (float)(*pUV->mDirectArray)[i / 2][1]; } } } else { if (pUV->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { m_uvCount = pUV->mIndexArray->GetCount(); m_uvBuffer = new float[m_uvCount * 2]; for (int i = 0; i < m_uvCount * 2; i+=2) { m_uvBuffer[i] = (float)(*pUV->mDirectArray)[(*pUV->mIndexArray)[i / 2]][0]; m_uvBuffer[i + 1] = (float)(*pUV->mDirectArray)[(*pUV->mIndexArray)[i / 2]][1]; } } else { m_uvCount = pUV->mDirectArray->GetCount(); m_uvBuffer = new float[m_uvCount * 2]; for (int i = 0; i < m_uvCount * 2; i+=2) { m_uvBuffer[i] = (float)(*pUV->mDirectArray)[i / 2][0]; m_uvBuffer[i + 1] = (float)(*pUV->mDirectArray)[i / 2][1]; } } } } } }