reMesh* reFBXAsset::importMesh(FbxNode* fbxNode) { qDebug() << "import mesh for" << fbxNode->GetName(); reMesh* mesh = new reMesh; FbxMesh* fmesh = (FbxMesh*) fbxNode->GetNodeAttribute(); FbxVector4* controlPoints = fmesh->GetControlPoints(); for (int i=0; i<fmesh->GetPolygonCount(); i++) { reFace* face = new reFace; for (int j=0; j<fmesh->GetPolygonSize(i); j++) { int vi = fmesh->GetPolygonVertex(i, j); reVertex vertex; vertex.pos = reVec3(controlPoints[vi][0], controlPoints[vi][1], controlPoints[vi][2]); FbxVector4 fNormal; fmesh->GetPolygonVertexNormal(i, j, fNormal); vertex.uv = getUV(fmesh, vi, i, j); vertex.normal = reVec3(fNormal[0], fNormal[1], fNormal[2]); face->vertices.push_back(vertex); } reMaterial* mat = getMaterial(fmesh, i, mesh->materialSet); mesh->addFace(face,mat ? mat->id: -1); } reMeshAsset* meshAsset = new reMeshAsset(meshes); meshAsset->mesh = mesh; meshes->children.push_back(meshAsset); meshAsset->setPath((dataDir().toStdString() + "/" + fbxNode->GetName() + ".mesh").c_str()); mesh->save(dataDir().toStdString() + "/" + fbxNode->GetName() + ".mesh"); return mesh; }
JNIEXPORT jfloatArray JNICALL Java_de_tesis_dynaware_javafx_graphics_importers_fbx_JFbxLib_getMeshVertices(JNIEnv *env, jobject obj, jint attributeIndex) { // Check FBX file has been opened. if (!isOpen()) { throwFileClosedException(env); } // Check attribute index bounds for safety. if (!checkAttributeBounds(attributeIndex)) { throwArrayOutOfBoundsException(env); } // Check attribute type for safety. if (!isValidType(attributeIndex, FbxNodeAttribute::EType::eMesh)) { return NULL; } FbxMesh* mesh = (FbxMesh*)currentNode->GetNodeAttributeByIndex(attributeIndex); FbxVector4 *controlPoints = mesh->GetControlPoints(); const int controlPointsCount = mesh->GetControlPointsCount(); jfloatArray vertices = env->NewFloatArray(3*controlPointsCount); // Check memory could be allocated. if (vertices == NULL) { throwOutOfMemoryError(env); } for (int i=0; i<controlPointsCount; i++) { jfloat vertex[3]; vertex[0] = controlPoints[i][0]; vertex[1] = controlPoints[i][1]; vertex[2] = controlPoints[i][2]; env->SetFloatArrayRegion(vertices, 3*i, 3, vertex); } return vertices; }
FbxNode* ILDLMesh::CreateMesh( FbxScene* pScene, const char* pName ) { int nVerts = (int)m_vertex_list.size(); FbxMesh* lMesh = FbxMesh::Create(pScene,pName); lMesh->InitControlPoints( nVerts ); FbxVector4* lControlPoints = lMesh->GetControlPoints(); FbxGeometryElementNormal* lGeometryElementNormal= lMesh->CreateElementNormal(); lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); int vi = 0, glidx = 0; for( ILDLVertexIter i = m_vertex_list.begin(); i != m_vertex_list.end(); ++i, vi++ ) { ILDLVertexPtr vp = (*i); vp->m_glIdx = glidx; vec3 coords = vp->getCoords(); lControlPoints[vi] = FbxVector4( coords[0], coords[1], coords[2] ); vec3 normal = vp->getNormal(); lGeometryElementNormal->GetDirectArray().Add( FbxVector4( normal[0], normal[1], normal[2] ) ); glidx++; } for( ILDLFaceIter i = m_face_list.begin(); i != m_face_list.end(); ++i ) { ILDLFacePtr fp = *i; ILDLFaceVertexPtr fvp = fp->front(); lMesh->BeginPolygon(-1, -1, -1, false); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); fvp = fvp->next(); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); fvp = fvp->next(); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); lMesh->EndPolygon (); } FbxNode* lNode = FbxNode::Create(pScene,pName); lNode->SetNodeAttribute(lMesh); return lNode; }
void Parser::bake_meshes_recursive(FbxNode * node, FbxAnimLayer * animation_layer) { FbxPose * pose = NULL; FbxTime current_time; FbxAMatrix parent_global_position; FbxAMatrix global_position = get_global_position(node, current_time, pose, &parent_global_position); FbxNodeAttribute* node_attribute = node->GetNodeAttribute(); if(node_attribute) { if(node_attribute->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh * mesh = node->GetMesh(); FbxAMatrix geometry_offset = get_geometry(node); FbxAMatrix global_offset_position = global_position * geometry_offset; FbxVector4* control_points = mesh->GetControlPoints(); bake_global_positions(control_points, mesh->GetControlPointsCount(), global_offset_position); if(mesh && !mesh->GetUserDataPtr()) { VBOMesh * mesh_cache = new VBOMesh; if(mesh_cache->initialize(mesh)) { bake_mesh_deformations(mesh, mesh_cache, current_time, animation_layer, global_offset_position, pose); meshes->push_back(mesh_cache); } } } } const int node_child_count = node->GetChildCount(); for(int node_child_index = 0; node_child_index < node_child_count; ++node_child_index) { bake_meshes_recursive(node->GetChild(node_child_index), animation_layer); } }
/** * 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 CC mesh to an FBX mesh static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene) { if (!mesh) return 0; FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName())); ccGenericPointCloud* cloud = mesh->getAssociatedCloud(); if (!cloud) return 0; unsigned vertCount = cloud->size(); unsigned faceCount = mesh->size(); // Create control points. { lMesh->InitControlPoints(vertCount); FbxVector4* lControlPoints = lMesh->GetControlPoints(); for (unsigned i=0; i<vertCount; ++i) { const CCVector3* P = cloud->getPoint(i); lControlPoints[i] = FbxVector4(P->x,P->y,P->z); } } ccMesh* asCCMesh = 0; if (mesh->isA(CC_MESH)) asCCMesh = static_cast<ccMesh*>(mesh); // normals if (mesh->hasNormals()) { FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal(); if (mesh->hasTriNormals()) { // We want to have one normal per vertex of each polygon, // so we set the mapping mode to eByPolygonVertex. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect); lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3); if (asCCMesh) { NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable(); assert(triNorms); for (unsigned i=0; i<triNorms->currentSize(); ++i) { const PointCoordinateType* N = ccNormalVectors::GetNormal(triNorms->getValue(i)); FbxVector4 Nfbx(N[0],N[1],N[2]); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } for (unsigned j=0; j<faceCount; ++j) { int i1,i2,i3; asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3); } } else { for (unsigned j=0; j<faceCount; ++j) { //we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices CCVector3 Na,Nb,Nc; lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z)); mesh->getTriangleNormals(j,Na,Nb,Nc); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2); } } } else { // We want to have one normal for each vertex (or control point), // so we set the mapping mode to eByControlPoint. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); // The first method is to set the actual normal value // for every control point. lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const PointCoordinateType* N = cloud->getPointNormal(i); FbxVector4 Nfbx(N[0],N[1],N[2]); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } } } else { ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } // colors if (cloud->hasColors()) { FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor(); lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const colorType* C = cloud->getPointColor(i); FbxColor col( FbxDouble3( static_cast<double>(C[0])/MAX_COLOR_COMP, static_cast<double>(C[1])/MAX_COLOR_COMP, static_cast<double>(C[2])/MAX_COLOR_COMP ) ); lGeometryElementVertexColor->GetDirectArray().Add(col); } } // Set material mapping. //FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); //lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon); //lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); // Create polygons. Assign material indices. { for (unsigned j=0; j<faceCount; ++j) { const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j); lMesh->BeginPolygon(static_cast<int>(j)); lMesh->AddPolygon(tsi->i1); lMesh->AddPolygon(tsi->i2); lMesh->AddPolygon(tsi->i3); lMesh->EndPolygon(); } } FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName())); lNode->SetNodeAttribute(lMesh); //CreateMaterials(pScene, lMesh); return lNode; }
HRESULT CStaticMesh::Load_StaticMesh(const char* szFilePath,const char* szFileName, FbxManager* _pFBXManager, FbxIOSettings* _pIOsettings, FbxScene* _pFBXScene, FbxImporter* _pImporter) { HRESULT hr = E_FAIL; vector<UINT> vecIndeces; string strFullPath; strFullPath.clear(); strFullPath = szFilePath; strFullPath += szFileName;//경로에 파일이름 추가 if (!(_pImporter->Initialize(strFullPath.c_str(), -1, _pFBXManager->GetIOSettings()))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Init Failed"); if (!(_pImporter->Import(_pFBXScene))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Import Failed"); FbxGeometryConverter clsConverter(_pFBXManager); clsConverter.Triangulate(_pFBXScene, false); FbxNode* pRootNode = _pFBXScene->GetRootNode(); if (!pRootNode) return E_FAIL; vector<VTXTEX> vecVTXTEX; for (int i = 0; i < pRootNode->GetChildCount(); ++i) { FbxNode* pChildNode = pRootNode->GetChild(i); if (pChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pChildNode->GetNodeAttribute(); // 임폴트 하려는 메쉬의 데이터 D3DXVECTOR3 vPos; D3DXVECTOR2 vOutUV; D3DXVECTOR3 vOutNormal; FbxVector4* mControlPoints = pMesh->GetControlPoints(); int iVTXCounter = 0; for (int j = 0; j < pMesh->GetPolygonCount(); j++) // 폴리곤의 인덱스 { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); FbxGeometryElementUV* VtxUV = pMesh->GetElementUV(0); FbxGeometryElementNormal* VtxNormal = pMesh->GetElementNormal(0); for (int k = 0; k < iNumVertices; k++) // 폴리곤을 구성하는 버텍스의 인덱스 { //정점 데이터 얻는곳 int iControlPointIndex = pMesh->GetPolygonVertex(j, k); // 컨트롤 포인트 = 하나의 버텍스 int iTextureUVIndex = pMesh->GetTextureUVIndex(j, k); // Control = Vertex //int iNormalIndex = pMesh->GetPolygonVertexIndex(j, k); ++iVTXCounter; vPos.x = (float)mControlPoints[iControlPointIndex].mData[0]; vPos.y = -(float)mControlPoints[iControlPointIndex].mData[1]; vPos.z = (float)mControlPoints[iControlPointIndex].mData[2]; //uv 얻기 switch (VtxUV->GetMappingMode()) // UV값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxUV->GetIndexArray().GetAt(iControlPointIndex); vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } case FbxGeometryElement::eIndexToDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } //노멀얻기 switch (VtxNormal->GetMappingMode()) // 노멀값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[2]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iControlPointIndex); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } VTXTEX vtxtex; vtxtex.vPos = vPos; vtxtex.vNormal = vOutNormal; vtxtex.vTexUV = vOutUV; vecVTXTEX.push_back(vtxtex); //int index = VtxUV->GetIndexArray().GetAt(iTextureUVIndex); vecIndeces.push_back(VtxUV->GetIndexArray().GetAt(iTextureUVIndex)); } } } unsigned int n = vecVTXTEX.size(); VTXTEX* pVTXTex = new VTXTEX[n]; for (unsigned int i = 0; i < vecVTXTEX.size(); ++i) { pVTXTex[i].vPos = vecVTXTEX[i].vPos; pVTXTex[i].vNormal = vecVTXTEX[i].vNormal; pVTXTex[i].vTexUV = vecVTXTEX[i].vTexUV; } m_iVertices = vecVTXTEX.size(); m_iVertexStrides = sizeof(VTXTEX); m_iVertexOffsets = 0; MakeVertexNormal((BYTE*)pVTXTex, NULL); D3D11_BUFFER_DESC tBufferDesc; ZeroMemory(&tBufferDesc, sizeof(D3D11_BUFFER_DESC)); tBufferDesc.Usage = D3D11_USAGE_DEFAULT; tBufferDesc.ByteWidth = m_iVertexStrides * m_iVertices; tBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; tBufferDesc.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA tData; ZeroMemory(&tData, sizeof(D3D11_SUBRESOURCE_DATA)); tData.pSysMem = pVTXTex; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&tBufferDesc, &tData, &m_VertexBuffer); ::Safe_Delete(pVTXTex); if (FAILED(hr)) return E_FAIL; D3D11_BUFFER_DESC cbd; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.ByteWidth = sizeof(ConstantBuffer); cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.CPUAccessFlags = 0; cbd.MiscFlags = 0; cbd.StructureByteStride = 0; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&cbd, NULL, &m_ConstantBuffer); if (FAILED(hr)) { MessageBox(NULL, L"System Message", L"Constant Buffer Error", MB_OK); return hr; } return S_OK; }
void MeshImporter::LoadNodeMesh(FbxNode* node, ID3D11Device3* device, ID3D11DeviceContext3* context) { unsigned int numPolygons = 0; unsigned int numVertices = 0; unsigned int numIndices = 0; unsigned int numPolygonVert = 0; if (node->GetNodeAttribute() != NULL && node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh) { //PrintNode(node); // Create meshes FbxMesh* fbxMesh = node->GetMesh(); numPolygons = fbxMesh->GetPolygonCount(); numIndices = fbxMesh->GetPolygonVertexCount(); numVertices = fbxMesh->GetControlPointsCount(); // Do not use indexed drawing method numVertices = numIndices; vector<Vertex> vertices(numVertices); vector<unsigned int> indices(numIndices); numPolygonVert = 3; //assert(numPolygonVert == 3); FbxVector4* controlPoints = fbxMesh->GetControlPoints(); int* indices_array = fbxMesh->GetPolygonVertices(); // Need to be changed for optimization for (unsigned int i = 0; i < numIndices; i++) { indices[i] = indices_array[i]; vertices[i].pos.x = (float)fbxMesh->GetControlPointAt(indices[i]).mData[0] / 10000.0f; vertices[i].pos.y = (float)fbxMesh->GetControlPointAt(indices[i]).mData[1] / 10000.0f; vertices[i].pos.z = (float)fbxMesh->GetControlPointAt(indices[i]).mData[2] / 10000.0f; } // For indexed drawing /*for (unsigned int i = 0; i < numVertices; i++) { vertices[i].pos.x = (float)controlPoints[i].mData[0];// / 25.0f; vertices[i].pos.y = (float)controlPoints[i].mData[1];// / 25.0f; vertices[i].pos.z = (float)controlPoints[i].mData[2];// / 25.0f; }*/ LoadUV(fbxMesh, &vertices[0], &indices[0]); // Set to be clockwise, must be done after reading uvs and normals for (auto it = vertices.begin(); it != vertices.end(); it += 3) { std::swap(*it, *(it + 2)); } //OutputDebugStringA(("\n number of polygons: " + to_string(numPolygons) + " \n").c_str()); //OutputDebugStringA(("\n number of indices: " + to_string(numIndices) + " \n").c_str()); //OutputDebugStringA(("\n number of vertices: " + to_string(vertices.size()) + " \n").c_str()); ModelObj::MeshEntry mesh; mesh.vertices = vertices; mesh.indices = indices; mesh.numVertices = numVertices; mesh.numIndices = numIndices; LoadMaterials(node, &mesh, device, context); model->entries.push_back(mesh); } for (int i = 0; i < node->GetChildCount(); i++) { LoadNodeMesh(node->GetChild(i), device, context); } }
HRESULT FBXLoader::loadFBXFile(char* filePath, VertexBuffer** vBuf, IndexBuffer** iBuf, Renderer* renderer, bool centerShift) { if (g_pFbxSdkManager == nullptr) { g_pFbxSdkManager = FbxManager::Create(); FbxIOSettings* pIOsettings = FbxIOSettings::Create(g_pFbxSdkManager, IOSROOT); g_pFbxSdkManager->SetIOSettings(pIOsettings); } this->shiftCenter = centerShift; FbxImporter* pImporter = FbxImporter::Create(g_pFbxSdkManager, ""); FbxScene* pFbxScene = FbxScene::Create(g_pFbxSdkManager, ""); bool bSuccess = pImporter->Initialize(filePath, -1, g_pFbxSdkManager->GetIOSettings()); if (!bSuccess) return E_FAIL; bSuccess = pImporter->Import(pFbxScene); if (!bSuccess) return E_FAIL; FbxAxisSystem sceneAxisSystem = pFbxScene->GetGlobalSettings().GetAxisSystem(); FbxAxisSystem DirectXAxisSystem(FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eLeftHanded); if (sceneAxisSystem != DirectXAxisSystem) { DirectXAxisSystem.ConvertScene(pFbxScene); } pImporter->Destroy(); FbxNode* pFbxRootNode = pFbxScene->GetRootNode(); if (pFbxRootNode) { // Check if the getChildCount is > 1 TODO int test = pFbxRootNode->GetChildCount(); for (int i = 0; i < pFbxRootNode->GetChildCount(); i++) { FbxNode* pFbxChildNode = pFbxRootNode->GetChild(i); if (pFbxChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pFbxChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pFbxChildNode->GetNodeAttribute(); int numControlPoints = pMesh->GetControlPointsCount(); bool initial = true; float xMin, yMin, zMin; float xMax, yMax, zMax; float xIn, yIn, zIn; float xCenter, yCenter, zCenter; if (this->shiftCenter){ for (int c = 0; c < numControlPoints; c++) { xIn = (float)pMesh->GetControlPointAt(c).mData[0]; yIn = (float)pMesh->GetControlPointAt(c).mData[1]; zIn = (float)pMesh->GetControlPointAt(c).mData[2]; if (initial) { xMin = xIn; yMin = yIn; zMin = zIn; xMax = xIn; yMax = yIn; zMax = zIn; initial = false; } else { if (xIn < xMin) { xMin = xIn; } if (yIn < yMin) { yMin = yIn; } if (zIn < zMin) { zMin = zIn; } if (xIn > xMax) { xMax = xIn; } if (yIn > yMax) { yMax = yIn; } if (zIn > zMax) { zMax = zIn; } } } xCenter = (xMin + xMax) / 2.0f; yCenter = (yMin + yMax) / 2.0f; zCenter = (zMin + zMax) / 2.0f; } else { xCenter = 0; yCenter = 0; zCenter = 0; } FbxVector4* pVertices = pMesh->GetControlPoints(); int vertexCount = pMesh->GetPolygonVertexCount(); //Vertex vertex; Vertex* vertexArray = new Vertex[vertexCount]; //Vertex vertexArray[2592]; int numIndices = vertexCount; unsigned int* indexArray = new unsigned int[numIndices]; FbxVector4 fbxNorm(0, 0, 0, 0); FbxVector2 fbxUV(0, 0); bool isMapped; int vertexIndex = 0; // Loop iterates through the polygons and fills the vertex and index arrays for the buffers for (int j = 0; j < pMesh->GetPolygonCount(); j++) { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); //1st vertex int controlIndex = pMesh->GetPolygonVertex(j, 2); pMesh->GetPolygonVertexUV(j, 2, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 2, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //2nd vertex controlIndex = pMesh->GetPolygonVertex(j, 1); pMesh->GetPolygonVertexUV(j, 1, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 1, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //3rd vertex controlIndex = pMesh->GetPolygonVertex(j, 0); pMesh->GetPolygonVertexUV(j, 0, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 0, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; } // Generate vertex and index buffers from the vertex and index arrays *vBuf = renderer->createVertexBuffer(vertexArray, vertexCount); *iBuf = renderer->createIndexBuffer(indexArray, numIndices); delete[] vertexArray; delete[] indexArray; } } return S_OK; }
//-------------------------------------------------------------------------- void SaveMesh(FbxNode* pNode, const VeDirectoryPtr& spDest) noexcept { Mesh kMesh; FbxMesh* pMesh = (FbxMesh*)pNode->GetNodeAttribute(); kMesh.m_kName = pNode->GetName(); kMesh.m_stFaces = pMesh->GetPolygonCount(); kMesh.m_stVerts = kMesh.m_stFaces * 3; kMesh.m_kIndices.resize(kMesh.m_stVerts); kMesh.m_kPosition.resize(kMesh.m_stVerts); kMesh.m_kNormals.resize(pMesh->GetElementNormalCount()); for (auto& v : kMesh.m_kNormals) { v.resize(kMesh.m_stVerts); } kMesh.m_kTexcoords.resize(pMesh->GetElementUVCount()); for (auto& v : kMesh.m_kTexcoords) { v.resize(kMesh.m_stVerts); } kMesh.m_kColors.resize(pMesh->GetElementVertexColorCount()); for (auto& v : kMesh.m_kColors) { v.resize(kMesh.m_stVerts); } int element_mat = -1; for (int i(0); i < pMesh->GetElementMaterialCount(); ++i) { FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(i); if (lMaterialElement->GetMappingMode() == FbxGeometryElement::eByPolygon) { element_mat = i; break; } } if (element_mat >= 0) { kMesh.m_kAttributes.resize(kMesh.m_stFaces); } FbxVector4* lControlPoints = pMesh->GetControlPoints(); for (int i(0); i < (int)(kMesh.m_stFaces); ++i) { int lPolygonSize = pMesh->GetPolygonSize(i); VE_ASSERT_ALWAYS(lPolygonSize == 3); for (int j(0); j < lPolygonSize; ++j) { uint32_t u32Index = i * 3 + j; kMesh.m_kIndices[u32Index] = u32Index; int lControlPointIndex = pMesh->GetPolygonVertex(i, j); auto& pos = kMesh.m_kPosition[u32Index]; pos.x = (float)lControlPoints[lControlPointIndex][0]; pos.y = (float)lControlPoints[lControlPointIndex][1]; pos.z = (float)lControlPoints[lControlPointIndex][2]; for (int k(0); k < (int)(kMesh.m_kColors.size()); ++k) { FbxColor c; FbxGeometryElementVertexColor* leVtxc = pMesh->GetElementVertexColor(k); switch (leVtxc->GetMappingMode()) { default: break; case FbxGeometryElement::eByControlPoint: switch (leVtxc->GetReferenceMode()) { case FbxGeometryElement::eDirect: c = leVtxc->GetDirectArray().GetAt(lControlPointIndex); break; case FbxGeometryElement::eIndexToDirect: { int id = leVtxc->GetIndexArray().GetAt(lControlPointIndex); c = leVtxc->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } break; case FbxGeometryElement::eByPolygonVertex: { switch (leVtxc->GetReferenceMode()) { case FbxGeometryElement::eDirect: c = leVtxc->GetDirectArray().GetAt(u32Index); break; case FbxGeometryElement::eIndexToDirect: { int id = leVtxc->GetIndexArray().GetAt(u32Index); c = leVtxc->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } } break; case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs case FbxGeometryElement::eAllSame: // doesn't make much sense for UVs case FbxGeometryElement::eNone: // doesn't make much sense for UVs break; } auto& color = kMesh.m_kColors[k][u32Index]; color.x = (float)c[0]; color.y = (float)c[1]; color.z = (float)c[2]; color.w = (float)c[3]; } for (int k(0); k < (int)(kMesh.m_kTexcoords.size()); ++k) { FbxVector2 uv; FbxGeometryElementUV* leUV = pMesh->GetElementUV(k); switch (leUV->GetMappingMode()) { default: break; case FbxGeometryElement::eByControlPoint: switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: uv = leUV->GetDirectArray().GetAt(lControlPointIndex); break; case FbxGeometryElement::eIndexToDirect: { int id = leUV->GetIndexArray().GetAt(lControlPointIndex); uv = leUV->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } break; case FbxGeometryElement::eByPolygonVertex: { int lTextureUVIndex = pMesh->GetTextureUVIndex(i, j); switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: { uv = leUV->GetDirectArray().GetAt(lTextureUVIndex); } break; default: break; // other reference modes not shown here! } } break; case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs case FbxGeometryElement::eAllSame: // doesn't make much sense for UVs case FbxGeometryElement::eNone: // doesn't make much sense for UVs break; } auto& texcoord = kMesh.m_kTexcoords[k][u32Index]; texcoord.x = (float)uv[0]; texcoord.y = (float)uv[1]; } for (int k(0); k < (int)(kMesh.m_kNormals.size()); ++k) { FbxVector4 n; FbxGeometryElementNormal* leNormal = pMesh->GetElementNormal(k); if (leNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { switch (leNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: n = leNormal->GetDirectArray().GetAt(u32Index); break; case FbxGeometryElement::eIndexToDirect: { int id = leNormal->GetIndexArray().GetAt(u32Index); n = leNormal->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } } auto& normal = kMesh.m_kNormals[k][u32Index]; normal.x = (float)n[0]; normal.y = (float)n[1]; normal.z = (float)n[2]; } if (element_mat >= 0) { FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(element_mat); FbxSurfaceMaterial* lMaterial = NULL; int lMatId = -1; lMaterial = pMesh->GetNode()->GetMaterial(lMaterialElement->GetIndexArray().GetAt(i)); lMatId = lMaterialElement->GetIndexArray().GetAt(i); kMesh.m_kAttributes[i] = lMatId; } } } kMesh.Process(); kMesh.Save(spDest); }
Model* FbxModelLoader::LoadModel(const char* fileName) { Model* model = nullptr; if (!m_importer->Initialize(fileName, -1, m_manager->GetIOSettings())) { return nullptr; } FbxScene* lScene = FbxScene::Create(m_manager, "myscene"); m_importer->Import(lScene); FbxNode* lRootNode = lScene->GetRootNode(); if (lRootNode) { if (lRootNode->GetChildCount() > 0) { FbxNode* lNode = lRootNode->GetChild(0); FbxMesh* lMesh = lNode->GetMesh(); if (!lMesh) return nullptr; std::ofstream file; file.open("DataFromFbxVector.txt"); char* buffer = new char[1024]; sprintf_s(buffer, 1024, "Number of children in Root: %d\n\n\n\n", lRootNode->GetChildCount()); file << buffer; if (lMesh->IsTriangleMesh()) file << "It's a triangle mesh!"; else file << "It's NOT a triangle mesh!"; FbxVector4* vertexArray = lMesh->GetControlPoints(); for (int i = 0; i < lMesh->GetControlPointsCount(); i++) { sprintf(buffer, "(%f, %f, %f)\n", vertexArray[i].mData[0], vertexArray[i].mData[1], vertexArray[i].mData[2]); file << buffer; } delete buffer; file.close(); Polygon* polygons = new Polygon[lMesh->GetPolygonCount()]; int polygonCount = lMesh->GetPolygonCount(); int index = 0; buffer = new char[1024]; file.open("DataFromPolygons.txt"); for (int i = 0; i < lMesh->GetPolygonCount(); i++) { index = lMesh->GetPolygonVertex(i, 0); sprintf(buffer, "\n\nPolygon #%d\nPolygon Vertex Index #%d: ", i, index); file << buffer; polygons[i].vertex1.x = (float)vertexArray[index].mData[0]; polygons[i].vertex1.y = (float)vertexArray[index].mData[1]; polygons[i].vertex1.z = (float)vertexArray[index].mData[2]; sprintf(buffer, "(%f, %f, %f)\n", polygons[i].vertex1.x, polygons[i].vertex1.y, polygons[i].vertex1.z); file << buffer; index = lMesh->GetPolygonVertex(i, 1); sprintf(buffer, "Polygon Vertex Index #%d: ", index); file << buffer; polygons[i].vertex2.x = (float)vertexArray[index].mData[0]; polygons[i].vertex2.y = (float)vertexArray[index].mData[1]; polygons[i].vertex2.z = (float)vertexArray[index].mData[2]; sprintf(buffer, "(%f, %f, %f)\n", polygons[i].vertex2.x, polygons[i].vertex2.y, polygons[i].vertex2.z); file << buffer; index = lMesh->GetPolygonVertex(i, 2); sprintf(buffer, "Polygon Vertex Index #%d: ", index); file << buffer; polygons[i].vertex3.x = (float)vertexArray[index].mData[0]; polygons[i].vertex3.y = (float)vertexArray[index].mData[1]; polygons[i].vertex3.z = (float)vertexArray[index].mData[2]; sprintf(buffer, "(%f, %f, %f)\n", polygons[i].vertex3.x, polygons[i].vertex3.y, polygons[i].vertex3.z); file << buffer; } file.close(); delete buffer; model = new Model(); model->Vertices = new DirectX::XMFLOAT3[polygonCount * 3]; model->NumVertices = polygonCount * 3; file.open("DataFromPolygonToModelTransfer.txt"); buffer = new char[1024]; for (int i = 0; i < lMesh->GetPolygonCount() * 3; i += 3) { model->Vertices[i] = polygons[i/3].vertex1; model->Vertices[i+1] = polygons[i/3].vertex2; model->Vertices[i+2] = polygons[i/3].vertex3; sprintf_s(buffer, 1024, "Polygon #%d:\n(%f, %f, %f)\n(%f, %f, %f)\n(%f, %f, %f)\n\n" , i / 3 , model->Vertices[i].x, model->Vertices[i].y, model->Vertices[i].z , model->Vertices[i+1].x, model->Vertices[i+1].y, model->Vertices[i+1].z , model->Vertices[i+2].x, model->Vertices[i+2].y, model->Vertices[i+2].z); file << buffer; } delete buffer; file.close(); // delete [] polygons; } else return nullptr; } else return nullptr; return model; }
// Converts a CC mesh to an FBX mesh static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene, QString filename, size_t meshIndex) { if (!mesh) return 0; FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName())); FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName())); lNode->SetNodeAttribute(lMesh); ccGenericPointCloud* cloud = mesh->getAssociatedCloud(); if (!cloud) return 0; unsigned vertCount = cloud->size(); unsigned faceCount = mesh->size(); // Create control points. { lMesh->InitControlPoints(vertCount); FbxVector4* lControlPoints = lMesh->GetControlPoints(); for (unsigned i=0; i<vertCount; ++i) { const CCVector3* P = cloud->getPoint(i); lControlPoints[i] = FbxVector4(P->x,P->y,P->z); //lControlPoints[i] = FbxVector4(P->x,P->z,-P->y); //DGM: see loadFile (Y and Z are inverted) } } ccMesh* asCCMesh = 0; if (mesh->isA(CC_TYPES::MESH)) asCCMesh = static_cast<ccMesh*>(mesh); // normals if (mesh->hasNormals()) { FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal(); if (mesh->hasTriNormals()) { // We want to have one normal per vertex of each polygon, // so we set the mapping mode to eByPolygonVertex. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect); lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3); if (asCCMesh) { NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable(); assert(triNorms); for (unsigned i=0; i<triNorms->currentSize(); ++i) { const CCVector3& N = ccNormalVectors::GetNormal(triNorms->getValue(i)); FbxVector4 Nfbx(N.x,N.y,N.z); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } for (unsigned j=0; j<faceCount; ++j) { int i1,i2,i3; asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3); } } else { for (unsigned j=0; j<faceCount; ++j) { //we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices CCVector3 Na,Nb,Nc; lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z)); mesh->getTriangleNormals(j,Na,Nb,Nc); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2); } } } else { // We want to have one normal for each vertex (or control point), // so we set the mapping mode to eByControlPoint. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); // The first method is to set the actual normal value // for every control point. lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const CCVector3& N = cloud->getPointNormal(i); FbxVector4 Nfbx(N.x,N.y,N.z); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } } } else { ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } // Set material mapping. bool hasMaterial = false; if (asCCMesh && asCCMesh->hasMaterials()) { const ccMaterialSet* matSet = asCCMesh->getMaterialSet(); size_t matCount = matSet->size(); //check if we have textures bool hasTextures = asCCMesh->hasTextures(); if (hasTextures) { //check that we actually have materials with textures as well! hasTextures = false; for (size_t i=0; i<matCount; ++i) { ccMaterial::CShared mat = matSet->at(i); if (mat->hasTexture()) { hasTextures = true; break; } } } static const char gDiffuseElementName[] = "DiffuseUV"; // Create UV for Diffuse channel if (hasTextures) { FbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV(gDiffuseElementName); assert(lUVDiffuseElement != 0); lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); //fill Direct Array const TextureCoordsContainer* texCoords = asCCMesh->getTexCoordinatesTable(); assert(texCoords); if (texCoords) { unsigned count = texCoords->currentSize(); lUVDiffuseElement->GetDirectArray().SetCount(static_cast<int>(count)); for (unsigned i=0; i<count; ++i) { const float* uv = texCoords->getValue(i); lUVDiffuseElement->GetDirectArray().SetAt(i,FbxVector2(uv[0],uv[1])); } } //fill Indexes Array assert(asCCMesh->hasPerTriangleTexCoordIndexes()); if (asCCMesh->hasPerTriangleTexCoordIndexes()) { unsigned triCount = asCCMesh->size(); lUVDiffuseElement->GetIndexArray().SetCount(static_cast<int>(3*triCount)); for (unsigned j=0; j<triCount; ++j) { int t1=0, t2=0, t3=0; asCCMesh->getTriangleTexCoordinatesIndexes(j, t1, t2, t3); lUVDiffuseElement->GetIndexArray().SetAt(j*3+0,t1); lUVDiffuseElement->GetIndexArray().SetAt(j*3+1,t2); lUVDiffuseElement->GetIndexArray().SetAt(j*3+2,t3); } } } //Textures used in this file QMap<QString,QString> texFilenames; //directory to save textures (if any) QFileInfo info(filename); QString textDirName = info.baseName() + QString(".fbm"); QDir baseDir = info.absoluteDir(); QDir texDir = QDir(baseDir.absolutePath() + QString("/") + textDirName); for (size_t i=0; i<matCount; ++i) { ccMaterial::CShared mat = matSet->at(i); FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, qPrintable(mat->getName())); const ccColor::Rgbaf& emission = mat->getEmission(); const ccColor::Rgbaf& ambient = mat->getAmbient(); const ccColor::Rgbaf& diffuse = mat->getDiffuseFront(); const ccColor::Rgbaf& specular = mat->getDiffuseFront(); lMaterial->Emissive.Set(FbxDouble3(emission.r,emission.g,emission.b)); lMaterial->Ambient .Set(FbxDouble3( ambient.r, ambient.g, ambient.b)); lMaterial->Diffuse .Set(FbxDouble3( diffuse.r, diffuse.g, diffuse.b)); lMaterial->Specular.Set(FbxDouble3(specular.r,specular.g,specular.b)); lMaterial->Shininess = mat->getShininessFront(); lMaterial->ShadingModel.Set("Phong"); if (hasTextures && mat->hasTexture()) { QString texFilename = mat->getTextureFilename(); //texture has not already been processed if (!texFilenames.contains(texFilename)) { //if necessary, we (try to) create a subfolder to store textures if (!texDir.exists()) { texDir = baseDir; if (texDir.mkdir(textDirName)) { texDir.cd(textDirName); } else { textDirName = QString(); ccLog::Warning("[FBX] Failed to create subfolder '%1' to store texture files (files will be stored next to the .fbx file)"); } } QFileInfo fileInfo(texFilename); QString baseTexName = fileInfo.fileName(); //add extension QString extension = QFileInfo(texFilename).suffix(); if (fileInfo.suffix().isEmpty()) baseTexName += QString(".png"); QString absoluteFilename = texDir.absolutePath() + QString("/") + baseTexName; ccLog::PrintDebug(QString("[FBX] Material '%1' texture: %2").arg(mat->getName()).arg(absoluteFilename)); texFilenames[texFilename] = absoluteFilename; } //mat.texture.save(absoluteFilename); // Set texture properties. FbxFileTexture* lTexture = FbxFileTexture::Create(pScene,"DiffuseTexture"); assert(!texFilenames[texFilename].isEmpty()); lTexture->SetFileName(qPrintable(texFilenames[texFilename])); lTexture->SetTextureUse(FbxTexture::eStandard); lTexture->SetMappingType(FbxTexture::eUV); lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); lTexture->SetSwapUV(false); lTexture->SetTranslation(0.0, 0.0); lTexture->SetScale(1.0, 1.0); lTexture->SetRotation(0.0, 0.0); lTexture->UVSet.Set(FbxString(gDiffuseElementName)); // Connect texture to the proper UV // don't forget to connect the texture to the corresponding property of the material lMaterial->Diffuse.ConnectSrcObject(lTexture); } int matIndex = lNode->AddMaterial(lMaterial); assert(matIndex == static_cast<int>(i)); } //don't forget to save the texture files { for (QMap<QString,QString>::ConstIterator it = texFilenames.begin(); it != texFilenames.end(); ++it) { const QImage image = ccMaterial::GetTexture(it.key()); image.mirrored().save(it.value()); } texFilenames.clear(); //don't need this anymore! } // Create 'triangle to material index' mapping { FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon); lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); } hasMaterial = true; } // colors if (cloud->hasColors()) { FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor(); lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect); lGeometryElementVertexColor->GetDirectArray().SetCount(vertCount); for (unsigned i=0; i<vertCount; ++i) { const colorType* C = cloud->getPointColor(i); FbxColor col( static_cast<double>(C[0])/ccColor::MAX, static_cast<double>(C[1])/ccColor::MAX, static_cast<double>(C[2])/ccColor::MAX ); lGeometryElementVertexColor->GetDirectArray().SetAt(i,col); } if (!hasMaterial) { //it seems that we have to create a fake material in order for the colors to be displayed (in Unity and FBX Review at least)! FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, "ColorMaterial"); lMaterial->Emissive.Set(FbxDouble3(0,0,0)); lMaterial->Ambient.Set(FbxDouble3(0,0,0)); lMaterial->Diffuse.Set(FbxDouble3(1,1,1)); lMaterial->Specular.Set(FbxDouble3(0,0,0)); lMaterial->Shininess = 0; lMaterial->ShadingModel.Set("Phong"); FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); lMaterialElement->SetMappingMode(FbxGeometryElement::eAllSame); lMaterialElement->SetReferenceMode(FbxGeometryElement::eDirect); lNode->AddMaterial(lMaterial); } } // Create polygons { for (unsigned j=0; j<faceCount; ++j) { const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j); int matIndex = hasMaterial ? asCCMesh->getTriangleMtlIndex(j) : -1; lMesh->BeginPolygon(matIndex); lMesh->AddPolygon(tsi->i1); lMesh->AddPolygon(tsi->i2); lMesh->AddPolygon(tsi->i3); lMesh->EndPolygon(); } } return lNode; }
FBXLoader::FBXLoader(const char *filename) { m_error = true; if (m_fbx_sdk_manager == nullptr) { m_fbx_sdk_manager = FbxManager::Create(); m_fbx_sdk_manager->SetIOSettings(FbxIOSettings::Create(m_fbx_sdk_manager, IOSROOT)); } FbxImporter *importer = FbxImporter::Create(m_fbx_sdk_manager, ""); FbxScene *scene = FbxScene::Create(m_fbx_sdk_manager, ""); if (!importer->Initialize(filename, -1, m_fbx_sdk_manager->GetIOSettings())) return; if (!importer->Import(scene)) return; importer->Destroy(); FbxNode *root_node = scene->GetRootNode(); if (root_node) { for (int i = 0; i < root_node->GetChildCount(); i++) { FbxNode *child_node = root_node->GetChild(i); if (child_node->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType type = child_node->GetNodeAttribute()->GetAttributeType(); if (type != FbxNodeAttribute::eMesh) continue; FbxMesh *mesh = (FbxMesh *) child_node->GetNodeAttribute(); FbxVector4 *vertices = mesh->GetControlPoints(); for (int j = 0; j < mesh->GetPolygonCount(); j++) { int num_verts = mesh->GetPolygonSize(j); assert(num_verts == 3); DirectX::XMFLOAT3 vertex[3]; FbxVector4 polygon_normal(0, 0, 0); for (int k = 0; k < num_verts; k++) { int control_point_idx = mesh->GetPolygonVertex(j, k); FbxVector4 vertex_normal; mesh->GetPolygonVertexNormal(j, k, vertex_normal); polygon_normal += vertex_normal; vertex[k].x = (float) vertices[control_point_idx].mData[0]; vertex[k].y = (float) vertices[control_point_idx].mData[1]; vertex[k].z = (float) vertices[control_point_idx].mData[2]; } if (IsClockwise(vertex, num_verts, polygon_normal)) { for (int i = 0; i < num_verts; i++) m_vertices.push_back(ToD3DCoordinateSystem(vertex[i])); } else { for (int i = 0; i < num_verts; i++) m_vertices.push_back(ToD3DCoordinateSystem(vertex[num_verts - 1 - i])); } } } } for (size_t i = 0; i < m_vertices.size(); i++) m_indices.push_back(i); m_error = false; }
bool FillData(ModelData* someData,FbxNode* aNode, AnimationData* aAnimation) { FbxMesh* mesh = aNode->GetMesh(); if (mesh == nullptr || !aNode) return false; const int lPolygonCount = mesh->GetPolygonCount(); // Count the polygon count of each material FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL; FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone; if (mesh->GetElementMaterial()) { lMaterialIndice = &mesh->GetElementMaterial()->GetIndexArray(); lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode(); if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount); if (lMaterialIndice->GetCount() == lPolygonCount) { // Count the faces of each material for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); lMaterialIndex; /*if (someData->mSubMeshes[lMaterialIndex] == NULL) { someData->mSubMeshes[lMaterialIndex] = new ModelData::SubMesh; } someData->mSubMeshes[lMaterialIndex]->TriangleCount += 1;*/ } // Make sure we have no "holes" (NULL) in the mSubMeshes table. This can happen // if, in the loop above, we resized the mSubMeshes by more than one slot. /*for (int i = 0; i < someData->mSubMeshes.Count(); i++) { if (someData->mSubMeshes[i] == NULL) someData->mSubMeshes[i] = new ModelData::SubMesh; }*/ // Record the offset (how many vertex) const int lMaterialCount = someData->mSubMeshes.Size(); lMaterialCount; int lOffset = 0; /*for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex) { someData->mSubMeshes[lIndex]->IndexOffset = lOffset; lOffset += someData->mSubMeshes[lIndex]->TriangleCount * 3; // This will be used as counter in the following procedures, reset to zero someData->mSubMeshes[lIndex]->TriangleCount = 0; }*/ FBX_ASSERT(lOffset == lPolygonCount * 3); } } } // All faces will use the same material. if (someData->mSubMeshes.Size() == 0) { if (someData->mSubMeshes.GetCapacity() == 0) { someData->mSubMeshes.Init(1); } someData->mSubMeshes.RemoveAll(); someData->mSubMeshes.AddEmptyObject(); someData->mSubMeshes[0] = new ModelData::SubMesh(); } bool hasNormalMap = false; const int lMaterialCount = aNode->GetMaterialCount(); for (int lMaterialIndex = 0; lMaterialIndex < lMaterialCount; ++lMaterialIndex) { FbxSurfaceMaterial * lMaterial = aNode->GetMaterial(lMaterialIndex); if (lMaterial && !lMaterial->GetUserDataPtr()) { TextureInfo diffuseInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sDiffuse,FbxSurfaceMaterial::sDiffuseFactor,diffuseInfo.myFileName); diffuseInfo.myType = DIFFUSE; if(diffuseInfo.myFileName.empty() == false) { someData->myTextures.push_back(diffuseInfo); } TextureInfo normalInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sNormalMap,FbxSurfaceMaterial::sBumpFactor,normalInfo.myFileName); hasNormalMap = normalInfo.myFileName.empty() == false; normalInfo.myType = NORMALMAP; if(normalInfo.myFileName.empty() == false) { someData->myTextures.push_back(normalInfo); hasNormalMap = true; } TextureInfo roughnessInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sSpecular,FbxSurfaceMaterial::sSpecularFactor,roughnessInfo.myFileName); roughnessInfo.myType = ROUGHNESS; if(roughnessInfo.myFileName.empty() == false) { someData->myTextures.push_back(roughnessInfo); } TextureInfo substanceInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sReflection,FbxSurfaceMaterial::sReflectionFactor,substanceInfo.myFileName); substanceInfo.myType = SUBSTANCE; if(substanceInfo.myFileName.empty() == false) { someData->myTextures.push_back(substanceInfo); } TextureInfo ambientInfo; GetMaterialProperty(lMaterial, FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor, ambientInfo.myFileName); ambientInfo.myType = AO; if (substanceInfo.myFileName.empty() == false) { someData->myTextures.push_back(ambientInfo); } } } // Congregate all the data of a mesh to be cached in VBOs. // If normal or UV is by polygon vertex, record all vertex attributes by polygon vertex.' someData->mHasNormal = mesh->GetElementNormalCount() > 0; someData->mHasUV = mesh->GetElementUVCount() > 0; someData->myHasBiNormal = mesh->GetElementBinormalCount() > 0; FbxSkin * lSkinDeformer = (FbxSkin *)mesh->GetDeformer(0, FbxDeformer::eSkin); someData->myHasSkinweights = lSkinDeformer != nullptr; if(hasNormalMap && someData->myHasBiNormal == false) { mesh->GenerateTangentsDataForAllUVSets(); someData->myHasBiNormal = mesh->GetElementBinormalCount() > 0; } someData->myHasTangents = mesh->GetElementTangentCount() > 0; FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone; FbxGeometryElement::EMappingMode lUVMappingMode = FbxGeometryElement::eNone; if (someData->mHasNormal) { lNormalMappingMode = mesh->GetElementNormal(0)->GetMappingMode(); if (lNormalMappingMode == FbxGeometryElement::eNone) { someData->mHasNormal = false; } if (someData->mHasNormal && lNormalMappingMode != FbxGeometryElement::eByControlPoint) { someData->mAllByControlPoint = false; } } if (someData->mHasUV) { lUVMappingMode = mesh->GetElementUV(0)->GetMappingMode(); if (lUVMappingMode == FbxGeometryElement::eNone) { someData->mHasUV = false; } if (someData->mHasUV && lUVMappingMode != FbxGeometryElement::eByControlPoint) { someData->mAllByControlPoint = false; } } // Allocate the array memory, by control point or by polygon vertex. int lPolygonVertexCount = mesh->GetControlPointsCount(); //if (!someData->my) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_POS; newLayout.mySize = VERTEX_STRIDE; newLayout.myOffset = 0; someData->myLayout.Add(newLayout); lPolygonVertexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; } int stride = VERTEX_STRIDE; size_t size = lPolygonVertexCount * VERTEX_STRIDE; //float * lVertices = new float[lPolygonVertexCount * VERTEX_STRIDE]; unsigned int * lIndices = new unsigned int[lPolygonCount * TRIANGLE_VERTEX_COUNT]; someData->myIndexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; //float * lNormals = NULL; if (someData->mHasNormal) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_NORMAL; newLayout.mySize = NORMAL_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += NORMAL_STRIDE; size += lPolygonVertexCount * NORMAL_STRIDE; //lNormals = new float[lPolygonVertexCount * NORMAL_STRIDE]; } //float * lUVs = NULL; FbxStringList lUVNames; mesh->GetUVSetNames(lUVNames); const char * lUVName = NULL; if (someData->mHasUV && lUVNames.GetCount()) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_UV; newLayout.mySize = UV_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += UV_STRIDE; size += lPolygonVertexCount * UV_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; lUVName = lUVNames[0]; } if (someData->myHasBiNormal) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_BINORMAL; newLayout.mySize = BINORMAL_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += BINORMAL_STRIDE; size += lPolygonVertexCount * BINORMAL_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } if (someData->myHasTangents) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_TANGENT; newLayout.mySize = TANGENT_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += TANGENT_STRIDE; size += lPolygonVertexCount * TANGENT_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } if (someData->myHasSkinweights) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_SKINWEIGHTS; newLayout.mySize = SKINWEIGHT_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += SKINWEIGHT_STRIDE; size += lPolygonVertexCount * SKINWEIGHT_STRIDE; newLayout.myType = ModelData::VERTEX_BONEID; newLayout.mySize = BONEID_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += BONEID_STRIDE; size += lPolygonVertexCount * BONEID_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } float * lVertices = new float[size]; FbxAMatrix globalPos; FbxVector4* weights = nullptr; FbxVectorTemplate4<int>* bones = nullptr; FbxTime time = static_cast<FbxTime>(0.0f); if(someData->myHasSkinweights) { weights = new FbxVector4[mesh->GetControlPointsCount()]; bones = new FbxVectorTemplate4<int>[mesh->GetControlPointsCount()]; ComputeLinearDeformation(globalPos,mesh,weights,bones,aAnimation); } const FbxGeometryElementBinormal * lBiNormalElement = NULL; const FbxGeometryElementTangent * lTangentElement = NULL; if (someData->myHasBiNormal) { lBiNormalElement = mesh->GetElementBinormal(0); } if (someData->myHasTangents) { lTangentElement = mesh->GetElementTangent(0); } // Populate the array with vertex attribute, if by control point. const FbxVector4 * lControlPoints = mesh->GetControlPoints(); FbxVector4 lCurrentVertex; FbxVector4 lCurrentNormal; FbxVector4 lCurrentBiNormal; FbxVector4 lCurrentTangent; FbxVector2 lCurrentUV; if (someData->mAllByControlPoint) { const FbxGeometryElementNormal * lNormalElement = NULL; const FbxGeometryElementUV * lUVElement = NULL; if (someData->mHasNormal) { lNormalElement = mesh->GetElementNormal(0); } if (someData->mHasUV) { lUVElement = mesh->GetElementUV(0); } for (int lIndex = 0; lIndex < lPolygonVertexCount; ++lIndex) { int currentIndex = lIndex * stride; int addedSize = VERTEX_STRIDE; // Save the vertex position. lCurrentVertex = lControlPoints[lIndex]; CU::Vector4f position(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2]), 1); CU::Matrix44f fixMatrix; fixMatrix = CU::Matrix44<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1,0,0)); position = position*fixMatrix; lVertices[currentIndex] = position.x; lVertices[currentIndex + 1] = position.y; lVertices[currentIndex + 2] = position.z; lVertices[currentIndex + 3] = 1; // Save the normal. if (someData->mHasNormal) { int lNormalIndex = lIndex; if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex); CU::Vector3f normal( static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += NORMAL_STRIDE; } // Save the UV. if (someData->mHasUV) { int lUVIndex = lIndex; if (lUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lUVIndex = lUVElement->GetIndexArray().GetAt(lIndex); } lCurrentUV = lUVElement->GetDirectArray().GetAt(lUVIndex); lVertices[currentIndex + addedSize] = static_cast<float>(lCurrentUV[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(lCurrentUV[1])*-1.0f; addedSize += 2; } if (someData->myHasBiNormal) { int lBinormIndexIndex = lIndex; if (lBiNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lBiNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentBiNormal = lBiNormalElement->GetDirectArray().GetAt(lBinormIndexIndex); //mesh->GetElementBinormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); //lCurrentNormal = lCurrentNormal CU::Vector3f normal( static_cast<float>(lCurrentBiNormal[0]), static_cast<float>(lCurrentBiNormal[1]), static_cast<float>(lCurrentBiNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += BINORMAL_STRIDE; } if (someData->myHasTangents) { int lBinormIndexIndex = lIndex; if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lTangentElement->GetIndexArray().GetAt(lIndex); } lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lBinormIndexIndex); //lCurrentNormal = lCurrentNormal CU::Vector3f normal( static_cast<float>(lCurrentTangent[0]), static_cast<float>(lCurrentTangent[1]), static_cast<float>(lCurrentTangent[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += TANGENT_STRIDE; } if(someData->myHasSkinweights) { FbxVector4 currentWeights = weights[lIndex]; //currentWeights.Normalize(); lVertices[currentIndex + addedSize] = static_cast<float>(currentWeights[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentWeights[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentWeights[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentWeights[3]); addedSize += SKINWEIGHT_STRIDE; FbxVectorTemplate4<int> currentBones = bones[lIndex]; lVertices[currentIndex + addedSize] = static_cast<float>(currentBones[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentBones[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentBones[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentBones[3]); addedSize += BONEID_STRIDE; } } } int lVertexCount = 0; for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { // The material for current face. int lMaterialIndex = 0; if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); } // Where should I save the vertex attribute index, according to the material const int lIndexOffset = someData->mSubMeshes[lMaterialIndex]->IndexOffset + someData->mSubMeshes[lMaterialIndex]->TriangleCount * 3; for (int lVerticeIndex = TRIANGLE_VERTEX_COUNT-1; lVerticeIndex > -1; --lVerticeIndex) { const int lControlPointIndex = mesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex); int vertexIndex = lIndexOffset + (TRIANGLE_VERTEX_COUNT-1) - lVerticeIndex; if (someData->mAllByControlPoint) { lIndices[vertexIndex] = static_cast<unsigned int>(lControlPointIndex); } // Populate the array with vertex attribute, if by polygon vertex. else { lIndices[vertexIndex] = static_cast<unsigned int>(lVertexCount); lCurrentVertex = lControlPoints[lControlPointIndex]; int addedSize = VERTEX_STRIDE; int currentIndex = lVertexCount * stride; CU::Vector4f position(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2]), 1); //fixMatrix CU::Matrix44f fixMatrix; fixMatrix = CU::Matrix44<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); position = position*fixMatrix; lVertices[currentIndex] = position.x; lVertices[currentIndex + 1] = position.y; lVertices[currentIndex + 2] = position.z; lVertices[currentIndex + 3] = 0; if (someData->mHasNormal) { mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); CU::Vector3f normal( static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += NORMAL_STRIDE; } if (someData->mHasUV) { bool lUnmappedUV; mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName, lCurrentUV, lUnmappedUV); lVertices[currentIndex + addedSize] = static_cast<float>(lCurrentUV[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(lCurrentUV[1])*-1.0f; addedSize += UV_STRIDE; } if (someData->myHasBiNormal) { int lBinormIndexIndex = lVerticeIndex; if (lBiNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lBiNormalElement->GetIndexArray().GetAt(lVerticeIndex); } lCurrentBiNormal = lBiNormalElement->GetDirectArray().GetAt(lBinormIndexIndex); CU::Vector3f normal( static_cast<float>(lCurrentBiNormal[0]), static_cast<float>(lCurrentBiNormal[1]), static_cast<float>(lCurrentBiNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += BINORMAL_STRIDE; } if (someData->myHasTangents) { int lBinormIndexIndex = lVerticeIndex; if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lTangentElement->GetIndexArray().GetAt(lVerticeIndex); } lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lBinormIndexIndex); mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); CU::Vector3f normal( static_cast<float>(lCurrentTangent[0]), static_cast<float>(lCurrentTangent[1]), static_cast<float>(lCurrentTangent[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += TANGENT_STRIDE; } if(someData->myHasSkinweights) { FbxVector4 currentWeights = weights[lControlPointIndex]; FbxVectorTemplate4<int> currentBones = bones[lControlPointIndex]; for(int l = 0;l < 4;++l) { if(currentBones[l] == -1) { currentWeights[l] = 0.0f; } } currentWeights.Normalize(); lVertices[currentIndex + addedSize] = static_cast<float>(currentWeights[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentWeights[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentWeights[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentWeights[3]); addedSize += SKINWEIGHT_STRIDE; lVertices[currentIndex + addedSize] = *(float*)¤tBones[0]; lVertices[currentIndex + addedSize + 1] = *(float*)¤tBones[1]; lVertices[currentIndex + addedSize + 2] = *(float*)¤tBones[2]; lVertices[currentIndex + addedSize + 3] = *(float*)¤tBones[3]; addedSize += BONEID_STRIDE; } } ++lVertexCount; } someData->mSubMeshes[lMaterialIndex]->TriangleCount += 1; } someData->myVertexCount = lVertexCount; someData->myVertexStride = stride; someData->myVertexBuffer = lVertices; someData->myIndicies = lIndices; if(weights) { delete [] weights; delete [] bones; } return true; }
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); } }
void MeshImporter::LoadNodeMesh(FbxNode* node, ID3D11Device3* device, ID3D11DeviceContext3* context) { unsigned int numPolygons = 0; unsigned int numVertices = 0; unsigned int numIndices = 0; unsigned int numPolygonVert = 0; if (node->GetNodeAttribute() != NULL && node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh) { //PrintNode(node); // Create meshes FbxMesh* fbxMesh = node->GetMesh(); numPolygons = fbxMesh->GetPolygonCount(); numIndices = fbxMesh->GetPolygonVertexCount(); numVertices = fbxMesh->GetControlPointsCount(); // Do not use indexed drawing method numVertices = numIndices; vector<Vertex> vertices(numVertices); vector<unsigned int> indices(numIndices); numPolygonVert = 3; //assert(numPolygonVert == 3); FbxVector4* controlPoints = fbxMesh->GetControlPoints(); int* indices_array = fbxMesh->GetPolygonVertices(); // Need to be changed for optimization for (unsigned int i = 0; i < numIndices; i++) { indices[i] = indices_array[i]; vertices[i].pos.x = (float)fbxMesh->GetControlPointAt(indices[i]).mData[0];// / 1000.0f; vertices[i].pos.y = (float)fbxMesh->GetControlPointAt(indices[i]).mData[1];// / 1000.0f; vertices[i].pos.z = (float)fbxMesh->GetControlPointAt(indices[i]).mData[2];// / 1000.0f; } // For indexed drawing /*for (unsigned int i = 0; i < numVertices; i++) { vertices[i].pos.x = (float)controlPoints[i].mData[0]; vertices[i].pos.y = (float)controlPoints[i].mData[1]; vertices[i].pos.z = (float)controlPoints[i].mData[2]; }*/ LoadUV(fbxMesh, &vertices[0], &indices[0]); //OutputDebugStringA(("\n number of polygons: " + to_string(numPolygons) + " \n").c_str()); //OutputDebugStringA(("\n number of indices: " + to_string(numIndices) + " \n").c_str()); //OutputDebugStringA(("\n number of vertices: " + to_string(vertices.size()) + " \n").c_str()); // Read mesh base transform matrix FbxAMatrix fbxGlobalMeshBaseMatrix = node->EvaluateGlobalTransform().Inverse().Transpose(); XMFLOAT4X4 globalMeshBaseMatrix; for (int r = 0; r < 4; r++) { //PrintTab("Global mesh base mat: " + to_string(fbxGlobalMeshBaseMatrix.mData[r][0])); for (int c = 0; c < 4; c++) { globalMeshBaseMatrix.m[r][c] = (float)fbxGlobalMeshBaseMatrix.mData[r][c]; } } // To be considered when importing Maya fbx model //FbxAMatrix geoMatrix = GetTransformMatrix(node); //ConvertFbxAMatrixToDXMatrix(&globalMeshBaseMatrix, fbxGlobalMeshBaseMatrix); MeshEntry mesh; mesh.vertices = vertices; mesh.indices = indices; mesh.numVertices = numVertices; mesh.numIndices = numIndices; mesh.fbxNode = node; mesh.globalMeshBaseMatrix = globalMeshBaseMatrix; // Load materials and textures LoadMaterials(node, &mesh, device, context); // Load weights LoadWeight(fbxMesh, &mesh); // Set to be clockwise, must be done after reading uvs, normals, weights and etc for (auto it = mesh.vertices.begin(); it != mesh.vertices.end(); it += 3) { swap(*it, *(it + 2)); } model->entries.push_back(mesh); } int numChild = node->GetChildCount(); for (int i = 0; i < numChild; i++) { LoadNodeMesh(node->GetChild(i), device, context); } }
void FBXScene::ProcessMesh(FbxNode* pNode) { FbxMesh* pFBXMesh = pNode->GetMesh(); if( !pFBXMesh ) return; if ( pFBXMesh->GetPolygonVertexCount() != pFBXMesh->GetPolygonCount() * 3 ) { FbxGeometryConverter GeometryConverter(pNode->GetFbxManager()); if( !GeometryConverter.TriangulateInPlace( pNode ) ) { return; } pFBXMesh = pNode->GetMesh(); } pFBXMesh->InitNormals(); pFBXMesh->ComputeVertexNormals(true); pFBXMesh->GenerateTangentsDataForAllUVSets(); int nVertexCount = pFBXMesh->GetControlPointsCount(); if( nVertexCount <= 0 ) return; std::vector<BoneWeights> boneWeights(nVertexCount); ProcessBoneWeights(pFBXMesh, boneWeights); Model* pModel = new Model(pNode->GetName(), m_Models.GetCount(), false); FbxVector4* aControlPoints = pFBXMesh->GetControlPoints(); for( int pi = 0; pi < pFBXMesh->GetPolygonCount(); ++pi ) // Whole for-loop takes some time too, investigate further. { // Material Material* pMaterial = NULL; for( unsigned int pvi = 0; pvi < 3; ++pvi ) { int nVertexIndex = pFBXMesh->GetPolygonVertex(pi, pvi); if( nVertexIndex < 0 || nVertexIndex >= nVertexCount ) continue; // Material if( pMaterial == NULL ) pMaterial = GetMaterialLinkedWithPolygon(pFBXMesh, 0, pi, 0, nVertexIndex); // Position FbxVector4 fbxPosition = aControlPoints[nVertexIndex]; // Normals And Tangents FbxVector4 fbxNormal, fbxTangent; fbxNormal = GetNormal(pFBXMesh, 0, pi, pvi, nVertexIndex); fbxTangent = GetTangent(pFBXMesh, 0, pi, pvi, nVertexIndex); // Add Vertex pModel->AddVertex(pMaterial, FbxVector4ToBTHFBX_VEC3(fbxPosition), FbxVector4ToBTHFBX_VEC3(fbxNormal), FbxVector4ToBTHFBX_VEC3(fbxTangent), GetTexCoord(pFBXMesh, 0, pi, pvi, nVertexIndex), boneWeights[nVertexIndex]); // Update Bounding Box UpdateBoundingBoxDataFromVertex(FbxVector4ToBTHFBX_VEC3(fbxPosition)); } } // Geometric Offset pModel->SetGeometricOffset2(GetGeometricOffset2(pNode)); // Insert Model m_Models.Add(pModel->GetName(), pModel); }
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]; } } } } } }