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 Model::processMeshTextCoords(FbxMesh *mesh, Vertex *verts, int numVerts) { int matCount = mesh->GetElementMaterialCount(); FbxLayerElementMaterial *matElem = NULL; if (matCount) //only supporting 1 material layer max matElem = mesh->GetElementMaterial(0); int polCount = mesh->GetPolygonCount(); for (int polInd = 0; polInd < polCount; polInd++) { int textureId = 0; if (matElem) { textureId = matElem->GetIndexArray().GetAt(polInd); } for (unsigned polVert = 0; polVert < 3; polVert++) { int cornerIndex = mesh->GetPolygonVertex(polInd, polVert); FbxVector2 UV = FbxVector2(0, 0); FbxLayer *layer = mesh->GetLayer(0); FbxLayerElementUV *layerUV = layer->GetUVs(); FbxLayerElementTexture *layerTexture = layer->GetTextures(FbxLayerElement::eTextureDiffuse); if (layerUV) { int UVindex = 0; switch (layerUV->GetMappingMode()) { case FbxLayerElement::eByControlPoint: UVindex = cornerIndex; break; case FbxLayerElement::eByPolygonVertex: UVindex = mesh->GetTextureUVIndex(polInd, polVert, FbxLayerElement::eTextureDiffuse); break; case FbxLayerElement::eByPolygon: UVindex = polInd; break; } UV = layerUV->GetDirectArray().GetAt(UVindex); verts[cornerIndex].color.x = textureId; verts[cornerIndex].texture.x = UV[0]; verts[cornerIndex].texture.y = 1.f - UV[1]; } } } }
/** * 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 ParseMesh( FbxNode* pNode, FbxMesh* pFbxMesh, ExportFrame* pParentFrame, bool bSubDProcess, const CHAR* strSuffix ) { if( !g_pScene->Settings().bExportMeshes ) return; if( !pNode || !pFbxMesh ) return; const CHAR* strName = pFbxMesh->GetName(); if( !strName || strName[0] == '\0' ) strName = pParentFrame->GetName().SafeString(); if( !strSuffix ) { strSuffix = ""; } CHAR strDecoratedName[512]; sprintf_s( strDecoratedName, "%s_%s%s", g_pScene->Settings().strMeshNameDecoration, strName, strSuffix ); ExportMesh* pMesh = new ExportMesh( strDecoratedName ); pMesh->SetDCCObject( pFbxMesh ); bool bSmoothMesh = false; auto Smoothness = pFbxMesh->GetMeshSmoothness(); if( Smoothness != FbxMesh::eHull && g_pScene->Settings().bConvertMeshesToSubD ) { bSubDProcess = true; bSmoothMesh = true; } ExportLog::LogMsg( 2, "Parsing %s mesh \"%s\", renamed to \"%s\"", bSmoothMesh ? "smooth" : "poly", strName, strDecoratedName ); SkinData skindata; bool bSkinnedMesh = ParseMeshSkinning( pFbxMesh, &skindata ); if( bSkinnedMesh ) { DWORD dwBoneCount = skindata.GetBoneCount(); for( DWORD i = 0; i < dwBoneCount; ++i ) { pMesh->AddInfluence( skindata.InfluenceNodes[i]->GetName() ); } } bool bExportColors = g_pScene->Settings().bExportColors; pMesh->SetVertexColorCount( 0 ); // Vertex normals and tangent spaces if( !g_pScene->Settings().bExportNormals ) { pMesh->SetVertexNormalCount( 0 ); } else if( g_pScene->Settings().bComputeVertexTangentSpace ) { if( g_pScene->Settings().bExportBinormal ) pMesh->SetVertexNormalCount( 3 ); else pMesh->SetVertexNormalCount( 2 ); } else { pMesh->SetVertexNormalCount( 1 ); } DWORD dwLayerCount = pFbxMesh->GetLayerCount(); ExportLog::LogMsg( 4, "%u layers in FBX mesh", dwLayerCount ); if (!dwLayerCount || !pFbxMesh->GetLayer(0)->GetNormals()) { ExportLog::LogMsg( 4, "Generating normals..." ); pFbxMesh->InitNormals(); #if (FBXSDK_VERSION_MAJOR >= 2015) pFbxMesh->GenerateNormals(); #else pFbxMesh->ComputeVertexNormals(); #endif } DWORD dwVertexColorCount = 0; FbxLayerElementVertexColor* pVertexColorSet = nullptr; DWORD dwUVSetCount = 0; FbxLayerElementMaterial* pMaterialSet = nullptr; std::vector<FbxLayerElementUV*> VertexUVSets; for( DWORD dwLayerIndex = 0; dwLayerIndex < dwLayerCount; ++dwLayerIndex ) { if( pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors() && bExportColors ) { if( dwVertexColorCount == 0 ) { dwVertexColorCount++; pVertexColorSet = pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors(); } else { ExportLog::LogWarning( "Only one vertex color set is allowed; ignoring additional vertex color sets." ); } } if( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() ) { dwUVSetCount++; VertexUVSets.push_back( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() ); } if( pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials() ) { if( pMaterialSet ) { ExportLog::LogWarning( "Multiple material layers detected on mesh %s. Some will be ignored.", pMesh->GetName().SafeString() ); } pMaterialSet = pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials(); } } std::vector<ExportMaterial*> MaterialList; for( int dwMaterial = 0; dwMaterial < pNode->GetMaterialCount(); ++dwMaterial ) { auto pMat = pNode->GetMaterial( dwMaterial ); if ( !pMat ) continue; auto pMaterial = ParseMaterial( pMat ); MaterialList.push_back( pMaterial ); } ExportLog::LogMsg( 4, "Found %u UV sets", dwUVSetCount ); dwUVSetCount = std::min<DWORD>( dwUVSetCount, g_pScene->Settings().iMaxUVSetCount ); ExportLog::LogMsg( 4, "Using %u UV sets", dwUVSetCount ); pMesh->SetVertexColorCount( dwVertexColorCount ); pMesh->SetVertexUVCount( dwUVSetCount ); // TODO: Does FBX only support 2D texture coordinates? pMesh->SetVertexUVDimension( 2 ); DWORD dwMeshOptimizationFlags = 0; if( g_pScene->Settings().bCompressVertexData ) dwMeshOptimizationFlags |= ExportMesh::COMPRESS_VERTEX_DATA; DWORD dwPolyCount = pFbxMesh->GetPolygonCount(); // Assume that polys are usually quads. g_MeshTriangleAllocator.SetSizeHint( dwPolyCount * 2 ); DWORD dwVertexCount = pFbxMesh->GetControlPointsCount(); auto pVertexPositions = pFbxMesh->GetControlPoints(); if( bSkinnedMesh ) { assert( skindata.dwVertexCount == dwVertexCount ); } ExportLog::LogMsg( 4, "%u vertices, %u polygons", dwVertexCount, dwPolyCount ); DWORD dwNonConformingSubDPolys = 0; // Compute total transformation FbxAMatrix vertMatrix; FbxAMatrix normMatrix; { auto trans = pNode->GetGeometricTranslation( FbxNode::eSourcePivot ); auto rot = pNode->GetGeometricRotation( FbxNode::eSourcePivot ); auto scale = pNode->GetGeometricScaling( FbxNode::eSourcePivot ); FbxAMatrix geom; geom.SetT( trans ); geom.SetR( rot ); geom.SetS( scale ); if ( g_pScene->Settings().bExportAnimations || !g_pScene->Settings().bApplyGlobalTrans ) { vertMatrix = geom; } else { auto global = pNode->EvaluateGlobalTransform(); vertMatrix = global * geom; } // Calculate the normal transform matrix (inverse-transpose) normMatrix = vertMatrix; normMatrix = normMatrix.Inverse(); normMatrix = normMatrix.Transpose(); } const bool bInvertTexVCoord = g_pScene->Settings().bInvertTexVCoord; // Loop over polygons. DWORD basePolyIndex = 0; for( DWORD dwPolyIndex = 0; dwPolyIndex < dwPolyCount; ++dwPolyIndex ) { // Triangulate each polygon into one or more triangles. DWORD dwPolySize = pFbxMesh->GetPolygonSize( dwPolyIndex ); assert( dwPolySize >= 3 ); DWORD dwTriangleCount = dwPolySize - 2; assert( dwTriangleCount > 0 ); if( dwPolySize > 4 ) { ++dwNonConformingSubDPolys; } DWORD dwMaterialIndex = 0; if( pMaterialSet ) { switch( pMaterialSet->GetMappingMode() ) { case FbxLayerElement::eByPolygon: switch( pMaterialSet->GetReferenceMode() ) { case FbxLayerElement::eDirect: dwMaterialIndex = dwPolyIndex; break; case FbxLayerElement::eIndex: case FbxLayerElement::eIndexToDirect: dwMaterialIndex = pMaterialSet->GetIndexArray().GetAt( dwPolyIndex ); break; } } } DWORD dwCornerIndices[3]; // Loop over triangles in the polygon. for( DWORD dwTriangleIndex = 0; dwTriangleIndex < dwTriangleCount; ++dwTriangleIndex ) { dwCornerIndices[0] = pFbxMesh->GetPolygonVertex( dwPolyIndex, 0 ); dwCornerIndices[1] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 1 ); dwCornerIndices[2] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 2 ); //ExportLog::LogMsg( 4, "Poly %d Triangle %d: %d %d %d", dwPolyIndex, dwTriangleIndex, dwCornerIndices[0], dwCornerIndices[1], dwCornerIndices[2] ); FbxVector4 vNormals[3]; ZeroMemory( vNormals, 3 * sizeof(FbxVector4) ); INT iPolyIndex = static_cast<INT>( dwPolyIndex ); INT iVertIndex[3] = { 0, static_cast<INT>( dwTriangleIndex + 1 ), static_cast<INT>( dwTriangleIndex + 2 ) }; pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[0], vNormals[0] ); pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[1], vNormals[1] ); pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[2], vNormals[2] ); // Build the raw triangle. auto pTriangle = g_MeshTriangleAllocator.GetNewTriangle(); // Store polygon index pTriangle->PolygonIndex = static_cast<INT>( dwPolyIndex ); // Store material subset index pTriangle->SubsetIndex = dwMaterialIndex; for( DWORD dwCornerIndex = 0; dwCornerIndex < 3; ++dwCornerIndex ) { const DWORD& dwDCCIndex = dwCornerIndices[dwCornerIndex]; // Store DCC vertex index (this helps the mesh reduction/VB generation code) pTriangle->Vertex[dwCornerIndex].DCCVertexIndex = dwDCCIndex; // Store vertex position auto finalPos = vertMatrix.MultT( pVertexPositions[dwDCCIndex] ); pTriangle->Vertex[dwCornerIndex].Position.x = (float)finalPos.mData[0]; pTriangle->Vertex[dwCornerIndex].Position.y = (float)finalPos.mData[1]; pTriangle->Vertex[dwCornerIndex].Position.z = (float)finalPos.mData[2]; // Store vertex normal auto finalNorm = vNormals[dwCornerIndex]; finalNorm.mData[3] = 0.0; finalNorm = normMatrix.MultT( finalNorm ); finalNorm.Normalize(); pTriangle->Vertex[dwCornerIndex].Normal.x = (float)finalNorm.mData[0]; pTriangle->Vertex[dwCornerIndex].Normal.y = (float)finalNorm.mData[1]; pTriangle->Vertex[dwCornerIndex].Normal.z = (float)finalNorm.mData[2]; // Store UV sets for( DWORD dwUVIndex = 0; dwUVIndex < dwUVSetCount; ++dwUVIndex ) { // Crack apart the FBX dereferencing system for UV coordinates FbxLayerElementUV* pUVSet = VertexUVSets[dwUVIndex]; FbxVector2 Value( 0, 0 ); switch( pUVSet->GetMappingMode() ) { case FbxLayerElement::eByControlPoint: switch (pUVSet->GetReferenceMode()) { case FbxLayerElement::eDirect: Value = pUVSet->GetDirectArray().GetAt(dwDCCIndex); break; case FbxLayerElement::eIndex: case FbxLayerElement::eIndexToDirect: { int iUVIndex = pUVSet->GetIndexArray().GetAt(dwDCCIndex); Value = pUVSet->GetDirectArray().GetAt(iUVIndex); } break; } break; case FbxLayerElement::eByPolygonVertex: switch (pUVSet->GetReferenceMode()) { case FbxLayerElement::eDirect: Value = pUVSet->GetDirectArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] ); break; case FbxLayerElement::eIndex: case FbxLayerElement::eIndexToDirect: { int iUVIndex = pUVSet->GetIndexArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] ); #ifdef _DEBUG if (!dwUVIndex) { // Warning: pFbxMesh->GetTextureUVIndex only works for the first layer of the mesh int iUVIndex2 = pFbxMesh->GetTextureUVIndex(iPolyIndex, iVertIndex[dwCornerIndex]); assert(iUVIndex == iUVIndex2); } #endif Value = pUVSet->GetDirectArray().GetAt( iUVIndex ); } break; } break; } // Store a single UV set pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].x = (float)Value.mData[0]; if( bInvertTexVCoord ) { pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = 1.0f - (float) Value.mData[1]; } else { pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = (float)Value.mData[1]; } } // Store vertex color set if( dwVertexColorCount > 0 && pVertexColorSet ) { // Crack apart the FBX dereferencing system for Color coordinates FbxColor Value( 1, 1, 1, 1 ); switch( pVertexColorSet->GetMappingMode() ) { case FbxLayerElement::eByControlPoint: switch( pVertexColorSet->GetReferenceMode() ) { case FbxLayerElement::eDirect: Value = pVertexColorSet->GetDirectArray().GetAt( dwDCCIndex ); break; case FbxLayerElement::eIndex: case FbxLayerElement::eIndexToDirect: { int iColorIndex = pVertexColorSet->GetIndexArray().GetAt(dwDCCIndex); Value = pVertexColorSet->GetDirectArray().GetAt(iColorIndex); } break; } break; case FbxLayerElement::eByPolygonVertex: switch( pVertexColorSet->GetReferenceMode() ) { case FbxLayerElement::eDirect: Value = pVertexColorSet->GetDirectArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] ); break; case FbxLayerElement::eIndex: case FbxLayerElement::eIndexToDirect: { int iColorIndex = pVertexColorSet->GetIndexArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] ); Value = pVertexColorSet->GetDirectArray().GetAt(iColorIndex); } break; } break; } // Store a single vertex color set pTriangle->Vertex[dwCornerIndex].Color.x = (float)Value.mRed; pTriangle->Vertex[dwCornerIndex].Color.y = (float)Value.mGreen; pTriangle->Vertex[dwCornerIndex].Color.z = (float)Value.mBlue; pTriangle->Vertex[dwCornerIndex].Color.w = (float)Value.mAlpha; } // Store skin weights if( bSkinnedMesh ) { memcpy( &pTriangle->Vertex[dwCornerIndex].BoneIndices, skindata.GetIndices( dwDCCIndex ), sizeof(PackedVector::XMUBYTE4) ); memcpy( &pTriangle->Vertex[dwCornerIndex].BoneWeights, skindata.GetWeights( dwDCCIndex ), sizeof(XMFLOAT4) ); } } // Add raw triangle to the mesh. pMesh->AddRawTriangle( pTriangle ); } basePolyIndex += dwPolySize; } if( bSubDProcess ) { dwMeshOptimizationFlags |= ExportMesh::FORCE_SUBD_CONVERSION; } if ( g_pScene->Settings().bCleanMeshes ) { dwMeshOptimizationFlags |= ExportMesh::CLEAN_MESHES; } if ( g_pScene->Settings().bOptimizeVCache ) { dwMeshOptimizationFlags |= ExportMesh::CLEAN_MESHES | ExportMesh::VCACHE_OPT; } pMesh->Optimize( dwMeshOptimizationFlags ); ExportModel* pModel = new ExportModel( pMesh ); size_t dwMaterialCount = MaterialList.size(); if( !pMesh->GetSubDMesh() ) { for( size_t dwSubset = 0; dwSubset < dwMaterialCount; ++dwSubset ) { auto pMaterial = MaterialList[dwSubset]; auto pSubset = pMesh->GetSubset( dwSubset ); CHAR strUniqueSubsetName[100]; sprintf_s( strUniqueSubsetName, "subset%Iu_%s", dwSubset, pMaterial->GetName().SafeString() ); pSubset->SetName( strUniqueSubsetName ); pModel->SetSubsetBinding( pSubset->GetName(), pMaterial ); } } else { auto pSubDMesh = pMesh->GetSubDMesh(); size_t dwSubsetCount = pSubDMesh->GetSubsetCount(); for( size_t dwSubset = 0; dwSubset < dwSubsetCount; ++dwSubset ) { auto pSubset = pSubDMesh->GetSubset( dwSubset ); assert( pSubset != nullptr ); assert( pSubset->iOriginalMeshSubset < static_cast<INT>( dwMaterialCount ) ); auto pMaterial = MaterialList[pSubset->iOriginalMeshSubset]; CHAR strUniqueSubsetName[100]; sprintf_s( strUniqueSubsetName, "subset%Iu_%s", dwSubset, pMaterial->GetName().SafeString() ); pSubset->Name = strUniqueSubsetName; pModel->SetSubsetBinding( pSubset->Name, pMaterial, true ); } } if( bSubDProcess && ( dwNonConformingSubDPolys > 0 ) ) { ExportLog::LogWarning( "Encountered %u polygons with 5 or more sides in mesh \"%s\", which were subdivided into quad and triangle patches. Mesh appearance may have been affected.", dwNonConformingSubDPolys, pMesh->GetName().SafeString() ); } // update statistics if( pMesh->GetSubDMesh() ) { g_pScene->Statistics().SubDMeshesProcessed++; g_pScene->Statistics().SubDQuadsProcessed += pMesh->GetSubDMesh()->GetQuadPatchCount(); g_pScene->Statistics().SubDTrisProcessed += pMesh->GetSubDMesh()->GetTrianglePatchCount(); } else { g_pScene->Statistics().TrisExported += pMesh->GetIB()->GetIndexCount() / 3; g_pScene->Statistics().VertsExported += pMesh->GetVB()->GetVertexCount(); g_pScene->Statistics().MeshesExported++; } pParentFrame->AddModel( pModel ); g_pScene->AddMesh( pMesh ); }