FbxVector4 FBXScene::GetTangent(FbxMesh* pFBXMesh, int nLayerIndex, int nPolygonIndex, int nPolygonVertexIndex, int nVertexIndex) { FbxVector4 vTangent(0,0,0,0); int nLayerCount = pFBXMesh->GetLayerCount(); if( nLayerIndex < nLayerCount )//for( int i = 0; i < nLayerCount; ++i ) { FbxLayer* pFBXLayer = pFBXMesh->GetLayer(nLayerIndex); if( pFBXLayer ) { FbxLayerElementTangent* pTangents = pFBXLayer->GetTangents(); if( pTangents ) { const FbxLayerElementArrayTemplate<FbxVector4>& pTangentArray = pTangents->GetDirectArray(); if( nVertexIndex < pTangentArray.GetCount() ) { vTangent = pTangentArray.GetAt(nVertexIndex); vTangent.Normalize(); } } } } return vTangent; }
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]; } } } }
FbxVector4 FBXScene::GetNormal(FbxMesh* pFBXMesh, int nLayerIndex, int nPolygonIndex, int nPolygonVertexIndex, int nVertexIndex) { FbxVector4 vNormal(0, 0, 0, 0); int nLayerCount = pFBXMesh->GetLayerCount(); if( nLayerIndex < nLayerCount )//for( int i = 0; i < nLayerCount; ++i ) { FbxLayer* pFBXLayer = pFBXMesh->GetLayer(nLayerIndex); if( pFBXLayer ) { FbxLayerElementNormal* pNormals = pFBXLayer->GetNormals(); if( pNormals ) { int nIdx = 0; if( pNormals->GetReferenceMode( ) == FbxLayerElement::EReferenceMode::eDirect ) { nIdx = nVertexIndex; } if( pNormals->GetReferenceMode( ) == FbxLayerElement::EReferenceMode::eIndexToDirect ) { nIdx = pNormals->GetIndexArray( ).GetAt( nVertexIndex ); } const FbxLayerElementArrayTemplate<FbxVector4>& pNormalArray = pNormals->GetDirectArray(); if( nIdx < pNormalArray.GetCount() ) { vNormal = pNormalArray.GetAt(nIdx); vNormal.Normalize(); } } } } return vNormal; }
BTHFBX_VEC2 FBXScene::GetTexCoord(FbxMesh* pFBXMesh, int nLayerIndex, int nPolygonIndex, int nPolygonVertexIndex, int nVertexIndex) { int nLayerCount = pFBXMesh->GetLayerCount(); if( nLayerIndex < nLayerCount )//for( int i = 0; i < nLayerCount; ++i ) { FbxLayer* pFBXLayer = pFBXMesh->GetLayer(nLayerIndex); if( pFBXLayer ) { FbxLayerElementUV* pUVs = pFBXLayer->GetUVs(FbxLayerElement::EType::eTextureDiffuse); if( pUVs ) { FbxLayerElement::EMappingMode mappingMode = pUVs->GetMappingMode(); FbxLayerElement::EReferenceMode referenceMode = pUVs->GetReferenceMode(); const FbxLayerElementArrayTemplate<FbxVector2>& pUVArray = pUVs->GetDirectArray(); const FbxLayerElementArrayTemplate<int>& pUVIndexArray = pUVs->GetIndexArray(); switch(mappingMode) { case FbxLayerElement::eByControlPoint: { int nMappingIndex = nVertexIndex; switch(referenceMode) { case FbxLayerElement::eDirect: if( nMappingIndex < pUVArray.GetCount() ) { return FBXTexCoordToD3DTexCoord( KFbxVector2ToBTHFBX_VEC2( pUVArray.GetAt(nMappingIndex) ) ); } break; case FbxLayerElement::eIndexToDirect: if( nMappingIndex < pUVIndexArray.GetCount() ) { int nIndex = pUVIndexArray.GetAt(nMappingIndex); if( nIndex < pUVArray.GetCount() ) { return FBXTexCoordToD3DTexCoord( KFbxVector2ToBTHFBX_VEC2( pUVArray.GetAt(nIndex) ) ); } } break; }; } break; case FbxLayerElement::eByPolygonVertex: { int nMappingIndex = pFBXMesh->GetTextureUVIndex(nPolygonIndex, nPolygonVertexIndex, FbxLayerElement::eTextureDiffuse); switch(referenceMode) { case FbxLayerElement::EReferenceMode::eDirect: case FbxLayerElement::EReferenceMode::eIndexToDirect: //I have no idea why the index array is not used in this case. if( nMappingIndex < pUVArray.GetCount() ) { return FBXTexCoordToD3DTexCoord( KFbxVector2ToBTHFBX_VEC2( pUVArray.GetAt(nMappingIndex) ) ); } break; }; } break; }; } } } return BTHFBX_VEC2(); }
/** * 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; }
/** * メッシュ情報を読み込む * * @param mesh メッシュ情報 */ void FbxFileLoader::load_mesh( FbxMesh* mesh ) { if ( ! mesh ) { return; } if ( ! get_model()->get_mesh() ) { get_model()->set_mesh( create_mesh() ); } VertexIndexMap vertex_index_map; VertexList vertex_list; Mesh::PositionList position_list; Mesh::VertexWeightList vertex_weight_list; // load_mesh_vertex() for ( int n = 0; n < mesh->GetControlPointsCount(); n++ ) { FbxVector4 v = mesh->GetControlPointAt( n ); position_list.push_back( Mesh::Position( static_cast< float >( v[ 0 ] ), static_cast< float >( v[ 1 ] ), static_cast< float >( v[ 2 ] ) ) ); } // load_mesh_vertex_weight() { int skin_count = mesh->GetDeformerCount( FbxDeformer::eSkin ); if ( skin_count > 0 ) { assert( skin_count == 1 ); vertex_weight_list.resize( position_list.size() ); FbxSkin* skin = FbxCast< FbxSkin >( mesh->GetDeformer( 0, FbxDeformer::eSkin ) ); load_mesh_vertex_weight( skin, vertex_weight_list ); } } FbxLayerElementSmoothing* smoothing = 0; // load_mesh_smoothing_info() { FbxLayer* layer = mesh->GetLayer( 0 ); smoothing = layer->GetSmoothing(); } if ( ! smoothing ) { COMMON_THROW_EXCEPTION_MESSAGE( "this FBX format is not supported. ( no smoothing info )" ); } // load_mesh_plygon() FbxLayerElementArrayTemplate< int >* material_indices; mesh->GetMaterialIndices( & material_indices ); for ( int n = 0; n < mesh->GetPolygonCount(); n++ ) { Mesh::VertexGroup* vertex_group = get_model()->get_mesh()->get_vertex_group_at( material_indices->GetAt( n ) ); bool is_smooth = smoothing->GetDirectArray().GetAt( n ) != 0; FbxVector4 polygon_normal( 0.f, 0.f, 0.f ); if ( ! is_smooth ) { // ポリゴンの法線を計算する Mesh::Position p1( position_list.at( mesh->GetPolygonVertex( n, 0 ) ) ); Mesh::Position p2( position_list.at( mesh->GetPolygonVertex( n, 1 ) ) ); Mesh::Position p3( position_list.at( mesh->GetPolygonVertex( n, 2 ) ) ); FbxVector4 a = FbxVector4( p1.x(), p1.y(), p1.z() ); FbxVector4 b = FbxVector4( p2.x(), p2.y(), p2.z() ); FbxVector4 c = FbxVector4( p3.x(), p3.y(), p3.z() ); FbxVector4 ab( b - a ); FbxVector4 bc( c - b ); polygon_normal = ab.CrossProduct( bc ); polygon_normal.Normalize(); } for ( int m = 0; m < mesh->GetPolygonSize( n ); m++ ) { int position_index = mesh->GetPolygonVertex( n, m ); Mesh::Vertex v; v.Position = Mesh::Position( position_list.at( position_index ) ); FbxVector2 uv_vector; bool unmapped; if ( mesh->GetPolygonVertexUV( n, m, "UVMap", uv_vector, unmapped) ) { v.TexCoord = Mesh::TexCoord( static_cast< float >( uv_vector[ 0 ] ), 1.f - static_cast< float >( uv_vector[ 1 ] ) ); } if ( is_smooth ) { FbxVector4 normal_vector; // 頂点の法線 if ( mesh->GetPolygonVertexNormal( n, m, normal_vector ) ) { v.Normal = Mesh::Normal( static_cast< float >( normal_vector[ 0 ] ), static_cast< float >( normal_vector[ 1 ] ), static_cast< float >( normal_vector[ 2 ] ) ); } } else { // ポリゴンの法線 v.Normal = Mesh::Normal( static_cast< float >( polygon_normal[ 0 ] ), static_cast< float >( polygon_normal[ 1 ] ), static_cast< float >( polygon_normal[ 2 ] ) ); } // 頂点の一覧に追加 { VertexIndexMap::iterator i = vertex_index_map.find( v ); if ( i != vertex_index_map.end() ) { vertex_group->add_index( i->second ); } else { Mesh::Index vertex_index = static_cast< Mesh::Index >( get_model()->get_mesh()->get_vertex_count() ); get_model()->get_mesh()->add_vertex( v ); if ( ! vertex_weight_list.empty() ) { get_model()->get_mesh()->add_vertex_weight( vertex_weight_list.at( position_index ) ); } vertex_group->add_index( vertex_index ); vertex_index_map[ v ] = vertex_index; } } } } }
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]; } } } } } }