Material* FBXScene::GetMaterialLinkedWithPolygon(FbxMesh* pFBXMesh, int nLayerIndex, int nPolygonIndex, int nPolygonVertexIndex, int nVertexIndex) { if( nLayerIndex < 0 || nLayerIndex > pFBXMesh->GetLayerCount() ) return NULL; FbxNode* pNode = pFBXMesh->GetNode(); if( !pNode ) return NULL; FbxLayerElementMaterial* pFBXMaterial = pFBXMesh->GetLayer(nLayerIndex)->GetMaterials(); if( pFBXMaterial ) { int nMappingIndex = GetMappingIndex( pFBXMaterial->GetMappingMode(), nPolygonIndex, 0, nVertexIndex ); if( nMappingIndex < 0 ) return NULL; FbxLayerElement::EReferenceMode referenceMode = pFBXMaterial->GetReferenceMode(); if( referenceMode == FbxLayerElement::EReferenceMode::eDirect ) { if( nMappingIndex < pNode->GetMaterialCount() ) { return GetMaterial(pNode->GetMaterial(nMappingIndex)); } } else if( referenceMode == FbxLayerElement::EReferenceMode::eIndexToDirect ) { const FbxLayerElementArrayTemplate<int>& pMaterialIndexArray = pFBXMaterial->GetIndexArray(); if( nMappingIndex < pMaterialIndexArray.GetCount() ) { int nIndex = pMaterialIndexArray.GetAt(nMappingIndex); if( nIndex < pNode->GetMaterialCount() ) { return GetMaterial(pNode->GetMaterial(nIndex)); } } } } return NULL; }
// メッシュ情報処理(再帰関数) void GetMeshData(FbxNode *parent, VertexDataArray& outVertexData) { // メッシュだけ処理 int numKids = parent->GetChildCount(); for(int i = 0; i < numKids; i++) { FbxNode *child = parent->GetChild(i); // メッシュを見つけたら if(child->GetMesh()) { FbxMesh* pMesh = child->GetMesh();// static_cast<FbxMesh*>(child->GetNodeAttribute()); printf("メッシュ発見\n"); printf("名前:%s\n", pMesh->GetName()); printf("ポリゴン数:%d\n", pMesh->GetPolygonCount()); printf("マテリアル数:%d\n", pMesh->GetElementMaterialCount()); printf("コントロールポイント数(頂点座標):%d\n", pMesh->GetControlPointsCount()); printf("UV数:%d\n", pMesh->GetTextureUVCount()); FbxArray<FbxVector4> normals; pMesh->GetPolygonVertexNormals(normals); printf("法線数:%d\n", normals.GetCount()); // 頂点情報取得 GetFBXVertexData(pMesh, outVertexData); } // マテリアル int numMat = child->GetMaterialCount(); for(int j = 0; j < numMat; ++j) { FbxSurfaceMaterial* mat = child->GetMaterial(j); if(mat) { GetMatrialData(mat); } } if(numMat == 0) { printf("マテリアルなし\n"); } child->GetChild(0); // 更に子を処理 GetMeshData(child, outVertexData); } }
//------------------------------------------------------------------------------------------------------------------------------------------- void transferMaterials(FbxGeometry* fbxMesh, Mesh* mesh){ int numMaterials = 0; if (fbxMesh == NULL){ throw new Exception("fbxMesh can not be NULL !"); } FbxNode* fbxNode = NULL; fbxNode = fbxMesh->GetNode(); if (fbxNode){ numMaterials = fbxNode->GetMaterialCount(); } LOG_DEBUG << " Number of materials: " << numMaterials; if (numMaterials > 0) { FbxPropertyT<FbxDouble3> lKFbxDouble3; FbxPropertyT<FbxDouble> lKFbxDouble1; FbxColor theColor; for (int matId = 0; matId < numMaterials; matId++){ Material* material = new Material(); FbxSurfaceMaterial* fbxMaterial = fbxNode->GetMaterial(matId); // Get the implementation to see f it's a hardware shader const FbxImplementation* fbxImplementation = GetImplementation(fbxMaterial, FBXSDK_IMPLEMENTATION_HLSL); string fbxImplementationType = "HLSL"; if (fbxImplementation != NULL){ fbxImplementation = GetImplementation(fbxMaterial, FBXSDK_IMPLEMENTATION_CGFX); fbxImplementationType = "CFGX"; } if (fbxImplementation) { // Handle hardware shader // TODO: transfer material using hardware shader } else if (fbxMaterial->GetClassId().Is(FbxSurfacePhong::ClassId)) { // Handle phong shader // Transfer Ambient color lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->Ambient; material->Ambient = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Transfer Diffuse color lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->Diffuse; material->Diffuse = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Transfer Specular color lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->Specular; material->Specular = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Transfer Emissive color lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->Emissive; material->Emissive = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Transfer Transperency factor lKFbxDouble1 = ((FbxSurfacePhong*)fbxMaterial)->TransparencyFactor; material->Opacity = 1.0 - lKFbxDouble1.Get(); // Transfer Shininess lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->Shininess; material->Shininess = lKFbxDouble1.Get(); // Transfer Reflectivity lKFbxDouble3 = ((FbxSurfacePhong*)fbxMaterial)->ReflectionFactor; material->Reflectivity = lKFbxDouble1.Get(); } else if (fbxMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId)) { // Handle Lambert shader lKFbxDouble3 = ((FbxSurfaceLambert *)fbxMaterial)->Ambient; material->Ambient = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Display the Diffuse Color lKFbxDouble3 = ((FbxSurfaceLambert *)fbxMaterial)->Diffuse; material->Diffuse = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Display the Emissive lKFbxDouble3 = ((FbxSurfaceLambert *)fbxMaterial)->Emissive; material->Emissive = Vector4s(lKFbxDouble3.Get()[0], lKFbxDouble3.Get()[1], lKFbxDouble3.Get()[2], 1); // Display the Opacity lKFbxDouble1 = ((FbxSurfaceLambert *)fbxMaterial)->TransparencyFactor; material->Opacity = 1.0 - lKFbxDouble1.Get(); } else { LOG_WARNING << "Unknown type of Material !"; } FbxPropertyT<FbxString> fbxString; fbxString = fbxMaterial->ShadingModel; material->ShadingMode = fbxString.Get(); mesh->Materials.push_back(material); } } LOG_DEBUG << "Transfer materials successfully! "; }
void Tools::DisplayMaterial::DisplayMaterial( FbxGeometry *i_geometry ) { DisplayCommon::DisplayString( "\n\n--------------------\nMaterial\n--------------------" ); int materialCount = 0; FbxNode *node = NULL; if( i_geometry ) { node = i_geometry->GetNode(); if( node ) materialCount = node->GetMaterialCount(); } if( materialCount > 0 ) { FbxPropertyT<FbxDouble3> double3; FbxPropertyT<FbxDouble> double1; FbxColor theColor; for( int ctr = 0; ctr < materialCount; ctr++ ) { DisplayCommon::DisplayInt( " Material ", ctr ); FbxSurfaceMaterial *material = node->GetMaterial( ctr ); DisplayCommon::DisplayString( " Name: \"", (char *) material->GetName(), "\"" ); #ifdef DISPLAY_HARDWARE_SHADER_INFORMATION //Get the implementation to see if it's a hardware shader. // Note:: this cause memory leak const FbxImplementation* implementation = GetImplementation( material, FBXSDK_IMPLEMENTATION_HLSL ); FbxString implementationType = "HLSL"; if( !implementation ) { implementation = GetImplementation( material, FBXSDK_IMPLEMENTATION_CGFX ); implementationType = "CGFX"; } if( implementation ) { //Now we have a hardware shader, let's read it FBXSDK_printf( " Hardware Shader Type: %s\n", implemenationType.Buffer() ); DisplayCommon::DisplayString( " Hardware Shader Type: ", implemenationType ); const FbxBindingTable* rootTable = implementation->GetRootTable(); FbxString fileName = rootTable->DescAbsoluteURL.Get(); FbxString techniqueName = rootTable->DescTAG.Get(); const FbxBindingTable* table = implementation->GetRootTable(); size_t entryNum = table->GetEntryCount(); for( int i = 0; i < (int)entryNum; i++ ) { const FbxBindingTableEntry& entry = table->GetEntry( i ); const char *entrySrcType = entry.GetEntryType( true ); FbxProperty fbxProp; FbxString test = entry.GetSource(); FBXSDK_printf( " Entry: %s\n", test.Buffer() ); DisplayCommon::DisplayString( " Entry: %s\n", test ); if ( strcmp( FbxPropertyEntryView::sEntryType, entrySrcType ) == 0 ) { fbxProp = material->FindPropertyHierarchical(entry.GetSource()); if( !fbxProp.IsValid() ) { fbxProp = material->RootProperty.FindHierarchical( entry.GetSource() ); } } else if( strcmp( FbxConstantEntryView::sEntryType, entrySrcType ) == 0 ) { fbxProp = implementation->GetConstants().FindHierarchical( entry.GetSource() ); } if( fbxProp.IsValid() ) { if( fbxProp.GetSrcObjectCount<FbxTexture>() > 0 ) { //do what you want with the textures for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxFileTexture>(); j++ ) { FbxFileTexture *tex = fbxProp.GetSrcObject<FbxFileTexture>( j ); FBXSDK_printf( " File Texture: %s\n", tex->GetFileName() ); DisplayCommon::DisplayString( " File Texture: %s\n", tex->GetFileName() ); } for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxLayeredTexture>(); j++ ) { FbxLayeredTexture *tex = fbxProp.GetSrcObject<FbxLayeredTexture>( j ); FBXSDK_printf( " Layered Texture: %s\n", tex->GetName() ); DisplayCommon::DisplayString( " Layered Texture: %s\n", tex->GetName() ); } for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxProceduralTexture>(); j++ ) { FbxProceduralTexture *tex = fbxProp.GetSrcObject<FbxProceduralTexture>( j ); FBXSDK_printf( " Procedural Texture: %s\n", tex->GetName() ); DisplayCommon::DisplayString( " Procedural Texture: %s\n", tex->GetName() ); } } else { FbxDataType fbxType = fbxProp.GetPropertyDataType(); FbxString fbxName = fbxType.GetName(); if( FbxBoolDT == fbxType ) { DisplayCommon::DisplayBool( " Bool: ", fbxProp.Get<FbxBool>() ); } else if( FbxIntDT == fbxType || FbxEnumDT == fbxType ) { DisplayCommon::DisplayInt( " Int: ", fbxProp.Get<FbxInt>() ); } else if( FbxFloatDT == fbxType ) { DisplayCommon::DisplayDouble( " Float: ", fbxProp.Get<FbxFloat>() ); } else if( FbxDoubleDT == fbxType ) { DisplayCommon::DisplayDouble( " Double: ", fbxProp.Get<FbxDouble>() ); } else if( FbxStringDT == fbxType || FbxUrlDT == fbxType || FbxXRefUrlDT == fbxType ) { DisplayCommon::DisplayString( " String: ", fbxProp.Get<FbxString>().Buffer() ); } else if( FbxDouble2DT == fbxType ) { FbxDouble2 double2 = fbxProp.Get<FbxDouble2>(); FbxVector2 vector; vector[0] = double2[0]; vector[1] = double2[1]; DisplayCommon::Display2DVector( " 2D vector: ", vector ); } else if( (FbxDouble3DT == fbxType) || (FbxColor3DT == fbxType) ) { FbxDouble3 double3 = fbxProp.Get<FbxDouble3>(); FbxVector4 vector; vector[0] = double3[0]; vector[1] = double3[1]; vector[2] = double3[2]; DisplayCommon::Display3DVector( " 3D vector: ", vector ); } else if( (FbxDouble4DT == fbxType) || (FbxColor4DT == fbxType) ) { FbxDouble4 double4 = fbxProp.Get<FbxDouble4>(); FbxVector4 vector; vector[0] = double4[0]; vector[1] = double4[1]; vector[2] = double4[2]; vector[3] = double4[3]; DisplayCommon::Display4DVector( " 4D vector: ", vector ); } else if( FbxDouble4x4DT == fbxType ) { FbxDouble4x4 double44 = fbxProp.Get<FbxDouble4x4>(); for( int j = 0; j < 4; j++ ) { FbxVector4 vector; vector[0] = double44[j][0]; vector[1] = double44[j][1]; vector[2] = double44[j][2]; vector[3] = double44[j][3]; DisplayCommon::Display4DVector( " 4x4D vector: ", vector ); } } } } } } else #endif // #ifdef DISPLAY_HARDWARE_SHADER_INFORMATION if( material->GetClassId().Is(FbxSurfacePhong::ClassId) ) { // We found a Phong material. Display its properties. // Display the Ambient Color double3 = ((FbxSurfacePhong *) material)->Ambient; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Ambient: ", theColor ); // Display the Diffuse Color double3 = ((FbxSurfacePhong *) material)->Diffuse; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Diffuse: ", theColor ); // Display the Specular Color (unique to Phong materials) double3 = ((FbxSurfacePhong *) material)->Specular; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Specular: ", theColor ); // Display the Emissive Color double3 = ((FbxSurfacePhong *) material)->Emissive; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Emissive: ", theColor ); //Opacity is Transparency factor now double1 = ((FbxSurfacePhong *) material)->TransparencyFactor; DisplayCommon::DisplayDouble( " Opacity: ", 1.0-double1.Get() ); // Display the Shininess double1 = ((FbxSurfacePhong *) material)->Shininess; DisplayCommon::DisplayDouble( " Shininess: ", double1.Get() ); // Display the Reflectivity double1 = ((FbxSurfacePhong *) material)->ReflectionFactor; DisplayCommon::DisplayDouble( " Reflectivity: ", double1.Get() ); } else if( material->GetClassId().Is(FbxSurfaceLambert::ClassId) ) { // We found a Lambert material. Display its properties. // Display the Ambient Color double3 = ((FbxSurfaceLambert *)material)->Ambient; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Ambient: ", theColor ); // Display the Diffuse Color double3 = ((FbxSurfaceLambert *)material)->Diffuse; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Diffuse: ", theColor ); // Display the Emissive double3 = ((FbxSurfaceLambert *)material)->Emissive; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Emissive: ", theColor ); // Display the Opacity double1 = ((FbxSurfaceLambert *)material)->TransparencyFactor; DisplayCommon::DisplayDouble( " Opacity: ", 1.0-double1.Get() ); } else DisplayCommon::DisplayString( "Unknown type of Material" ); FbxPropertyT<FbxString> string; string = material->ShadingModel; DisplayCommon::DisplayString( " Shading Model: ", string.Get() ); } } }
void FBXImporter::LoadMaterials(FBXMeshData* fbxMeshData) { FbxNode* node = nullptr; FbxMesh* mesh = fbxMeshData->mMesh; int materialCount = 0; int polygonCount = mesh->GetPolygonCount(); if ((mesh != nullptr) && (mesh->GetNode() != nullptr)) { node = mesh->GetNode(); materialCount = node->GetMaterialCount(); } bool isAllSame = true; for (int i = 0; i < mesh->GetElementMaterialCount(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(i); if (materialElement->GetMappingMode() == FbxGeometryElement::eByPolygon) { isAllSame = false; break; } } //For eAllSame mapping type, just out the material and texture mapping info once if (isAllSame) { for (int i = 0; i < mesh->GetElementMaterialCount(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(i); if (materialElement->GetMappingMode() == FbxGeometryElement::eAllSame) { FbxSurfaceMaterial* material = mesh->GetNode()->GetMaterial(materialElement->GetIndexArray().GetAt(0)); fbxMeshData->mSurfaceMaterial = material; int materialId = materialElement->GetIndexArray().GetAt(0); if (materialId >= 0) { LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sDiffuse); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sBump); vector<string>& textureFiles = mMeshData->textureFiles; auto iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getDiffuseTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getDiffuseTextureFile()); } if (fbxMeshData->getNormalMapTextureFile().size() > 0) { iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getNormalMapTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getNormalMapTextureFile()); } } } } } } //For eByPolygon mapping type, just out the material and texture mapping info once else { int materialId = 0; int polygonId = 0; polygonCount = 0; vector<string>& textureFiles = mMeshData->textureFiles; vector<MaterialIdOffset>& materialIdOffsets = mMeshData->materialIdOffsets; for (int i = 0; i < materialIdOffsets.size(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(0); FbxSurfaceMaterial* material = NULL; materialId = mMeshData->materialIdOffsets[i].material->materialId; material = mesh->GetNode()->GetMaterial(materialElement->GetIndexArray().GetAt(polygonId)); polygonCount = materialIdOffsets[i].polygonCount; fbxMeshData->mSurfaceMaterial = material; fbxMeshData->mMaterial = new Material(); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sDiffuse); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sBump); materialIdOffsets[i].material = fbxMeshData->mMaterial; auto iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getDiffuseTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getDiffuseTextureFile()); } if (fbxMeshData->getNormalMapTextureFile().size() > 0) { iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getNormalMapTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getNormalMapTextureFile()); } } polygonId += polygonCount; } } }
/** * 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; }
//converts a FBX mesh to a CC mesh static ccMesh* FromFbxMesh(FbxMesh* fbxMesh, FileIOFilter::LoadParameters& parameters) { if (!fbxMesh) return 0; int polyCount = fbxMesh->GetPolygonCount(); //fbxMesh->GetLayer( unsigned triCount = 0; unsigned polyVertCount = 0; //different from vertCount (vertices can be counted multiple times here!) //as we can't load all polygons (yet ;) we already look if we can load any! { unsigned skipped = 0; for (int i=0; i<polyCount; ++i) { int pSize = fbxMesh->GetPolygonSize(i); if (pSize == 3) { ++triCount; polyVertCount += 3; } else if (pSize == 4) { triCount += 2; polyVertCount += 4; } else { ++skipped; } } if (triCount == 0) { ccLog::Warning(QString("[FBX] No triangle or quad found in mesh '%1'! (polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName())); return 0; } else if (skipped != 0) { ccLog::Warning(QString("[FBX] Some polygons in mesh '%1' were ignored (%2): polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()).arg(skipped)); return 0; } } int vertCount = fbxMesh->GetControlPointsCount(); if (vertCount <= 0) { ccLog::Warning(QString("[FBX] Mesh '%1' has no vetex or no polygon?!").arg(fbxMesh->GetName())); return 0; } ccPointCloud* vertices = new ccPointCloud("vertices"); ccMesh* mesh = new ccMesh(vertices); mesh->setName(fbxMesh->GetName()); mesh->addChild(vertices); vertices->setEnabled(false); if (!mesh->reserve(static_cast<unsigned>(triCount)) || !vertices->reserve(vertCount)) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1'!").arg(fbxMesh->GetName())); delete mesh; return 0; } //colors { for (int l=0; l<fbxMesh->GetElementVertexColorCount(); l++) { FbxGeometryElementVertexColor* vertColor = fbxMesh->GetElementVertexColor(l); //CC can only handle per-vertex colors if (vertColor->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (vertColor->GetReferenceMode() == FbxGeometryElement::eDirect || vertColor->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) { if (vertices->reserveTheRGBTable()) { switch (vertColor->GetReferenceMode()) { case FbxGeometryElement::eDirect: { for (int i=0; i<vertCount; ++i) { FbxColor c = vertColor->GetDirectArray().GetAt(i); vertices->addRGBColor( static_cast<colorType>(c.mRed * ccColor::MAX), static_cast<colorType>(c.mGreen * ccColor::MAX), static_cast<colorType>(c.mBlue * ccColor::MAX) ); } } break; case FbxGeometryElement::eIndexToDirect: { for (int i=0; i<vertCount; ++i) { int id = vertColor->GetIndexArray().GetAt(i); FbxColor c = vertColor->GetDirectArray().GetAt(id); vertices->addRGBColor( static_cast<colorType>(c.mRed * ccColor::MAX), static_cast<colorType>(c.mGreen * ccColor::MAX), static_cast<colorType>(c.mBlue * ccColor::MAX) ); } } break; default: assert(false); break; } vertices->showColors(true); mesh->showColors(true); break; //no need to look for other color fields (we won't be able to handle them! } else { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' colors!").arg(fbxMesh->GetName())); } } else { ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName())); } } else { ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName())); } } } //normals can be per vertices or per-triangle int perPointNormals = -1; int perVertexNormals = -1; int perPolygonNormals = -1; { for (int j=0; j<fbxMesh->GetElementNormalCount(); j++) { FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(j); switch(leNormals->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: perPointNormals = j; break; case FbxGeometryElement::eByPolygonVertex: perVertexNormals = j; break; case FbxGeometryElement::eByPolygon: perPolygonNormals = j; break; default: //not handled break; } } } //per-point normals if (perPointNormals >= 0) { FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(perPointNormals); FbxLayerElement::EReferenceMode refMode = leNormals->GetReferenceMode(); const FbxLayerElementArrayTemplate<FbxVector4>& normals = leNormals->GetDirectArray(); assert(normals.GetCount() == vertCount); if (normals.GetCount() != vertCount) { ccLog::Warning(QString("[FBX] Wrong number of normals on mesh '%1'!").arg(fbxMesh->GetName())); perPointNormals = -1; } else if (!vertices->reserveTheNormsTable()) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName())); perPointNormals = -1; } else { //import normals for (int i=0; i<vertCount; ++i) { int id = refMode != FbxGeometryElement::eDirect ? leNormals->GetIndexArray().GetAt(i) : i; FbxVector4 N = normals.GetAt(id); //convert to CC-structure CCVector3 Npc( static_cast<PointCoordinateType>(N.Buffer()[0]), static_cast<PointCoordinateType>(N.Buffer()[1]), static_cast<PointCoordinateType>(N.Buffer()[2]) ); vertices->addNorm(Npc); } vertices->showNormals(true); mesh->showNormals(true); //no need to import the other normals (if any) perVertexNormals = -1; perPolygonNormals = -1; } } //per-triangle normals NormsIndexesTableType* normsTable = 0; if (perVertexNormals >= 0 || perPolygonNormals >= 0) { normsTable = new NormsIndexesTableType(); if (!normsTable->reserve(polyVertCount) || !mesh->reservePerTriangleNormalIndexes()) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName())); normsTable->release(); normsTable = 0; } else { mesh->setTriNormsTable(normsTable); vertices->showNormals(true); mesh->showNormals(true); } } //materials ccMaterialSet* materials = 0; { FbxNode* lNode = fbxMesh->GetNode(); int lMaterialCount = lNode ? lNode->GetMaterialCount() : 0; for (int i=0; i<lMaterialCount; i++) { FbxSurfaceMaterial *lBaseMaterial = lNode->GetMaterial(i); bool isLambert = lBaseMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId); bool isPhong = lBaseMaterial->GetClassId().Is(FbxSurfacePhong::ClassId); if (isLambert || isPhong) { ccMaterial::Shared mat(new ccMaterial(lBaseMaterial->GetName())); FbxSurfaceLambert* lLambertMat = static_cast<FbxSurfaceLambert*>(lBaseMaterial); float ambient[4]; float diffuse[4]; float emission[4]; float specular[4]; FbxSurfacePhong* lPhongMat = isPhong ? static_cast<FbxSurfacePhong*>(lBaseMaterial) : 0; for (int k=0; k<3; ++k) { ambient[k] = static_cast<float>(lLambertMat->Ambient.Get()[k]); diffuse[k] = static_cast<float>(lLambertMat->Diffuse.Get()[k]); emission[k] = static_cast<float>(lLambertMat->Emissive.Get()[k]); if (lPhongMat) { specular[k] = static_cast<float>(lPhongMat->Specular.Get()[k]); } } mat->setAmbient(ambient); mat->setDiffuse(diffuse); mat->setEmission(emission); if (isPhong) { mat->setSpecular(specular); assert(lPhongMat); mat->setShininess(static_cast<float>(lPhongMat->Shininess)); } //import associated texture (if any) { int lTextureIndex; FBXSDK_FOR_EACH_TEXTURE(lTextureIndex) { FbxProperty lProperty = lBaseMaterial->FindProperty(FbxLayerElement::sTextureChannelNames[lTextureIndex]); if( lProperty.IsValid() ) { int lTextureCount = lProperty.GetSrcObjectCount<FbxTexture>(); FbxTexture* texture = 0; //we can handle only one texture per material! We'll take the non layered one by default (if any) for (int j = 0; j < lTextureCount; ++j) { //Here we have to check if it's layeredtextures, or just textures: FbxLayeredTexture *lLayeredTexture = lProperty.GetSrcObject<FbxLayeredTexture>(j); if (lLayeredTexture) { //we don't handle layered textures! /*int lNbTextures = lLayeredTexture->GetSrcObjectCount<FbxTexture>(); for (int k=0; k<lNbTextures; ++k) { FbxTexture* lTexture = lLayeredTexture->GetSrcObject<FbxTexture>(k); if(lTexture) { } } //*/ } else { //non-layered texture FbxTexture* lTexture = lProperty.GetSrcObject<FbxTexture>(j); if(lTexture) { //we take the first non layered texture by default texture = lTexture; break; } } } if (texture) { FbxFileTexture *lFileTexture = FbxCast<FbxFileTexture>(texture); if (lFileTexture) { const char* texAbsoluteFilename = lFileTexture->GetFileName(); ccLog::PrintDebug(QString("[FBX] Texture absolue filename: %1").arg(texAbsoluteFilename)); if (texAbsoluteFilename != 0 && texAbsoluteFilename[0] != 0) { if (!mat->loadAndSetTexture(texAbsoluteFilename)) { ccLog::Warning(QString("[FBX] Failed to load texture file: %1").arg(texAbsoluteFilename)); } } } } } } } if (!materials) { materials = new ccMaterialSet("materials"); mesh->addChild(materials); } materials->addMaterial(mat); } else { ccLog::Warning(QString("[FBX] Material '%1' has an unhandled type").arg(lBaseMaterial->GetName())); } }