UINT Converter::getMaterialIndex(FbxMesh *m) { int triangleCount = m->GetPolygonCount(); FbxLayerElementArrayTemplate<int> *indices; if (m->GetElementMaterial()) { indices = &(m->GetElementMaterial()->GetIndexArray()); if (indices) { switch (m->GetElementMaterial()->GetMappingMode()) { case FbxGeometryElement::eByPolygon: if (indices->GetCount() == triangleCount) for (int i = 0; i < triangleCount; ++i) { return indices->GetAt(i); } break; case FbxGeometryElement::eAllSame: for (int i = 0; i < triangleCount; ++i) { return indices->GetAt(0); } break; default: throw std::exception("Material index mapping mode error."); } } } return 0; }
bool countUVandCPusage(vector<int> &cntUV, vector<int> &cntCP, FbxMesh* mesh) { for (int i = 0; i < mesh->mControlPoints.GetCount(); i++) cntCP.push_back(0); FbxLayerElementArrayTemplate<FbxVector2>* uvlayer; if (mesh->GetTextureUV(&uvlayer) == false) { return false; } for (int i = 0; i < uvlayer->GetCount(); i++) { cntUV.push_back(0); } for (int i = 0; i < mesh->GetPolygonCount(); i++) { for (int j = 0; j < mesh->GetPolygonSize(i); j++) { cntUV[mesh->GetTextureUVIndex(i, j)]++; cntCP[mesh->GetMeshEdgeIndexForPolygon(i, j)]++; } } return true; }
void GenerateLOD::Init_Buffer(fbxsdk::FbxMesh *pMesh, Model &model) { model.SetVertexCount(static_cast<int>(ControlP->size())); model.SetPolygonCount(static_cast<int>(Triangles->size())); // Create the VertexBuffer model.CreateVertextBuffer(); IDirect3DVertexBuffer9 *g_pVB = model.GetVertexBuffer(); CUSTOMVERTEX *pVertices; g_pVB->Lock(0, 0, (void **)&pVertices, 0); FbxLayerElementArrayTemplate<FbxVector2> *pUVarray = NULL; bool hasUV = pMesh->GetTextureUV(&pUVarray); if (!hasUV) { printf("Has No Textures!\n"); } WORD count = 0; std::unordered_map<int, WORD> RemainPoints; FbxVector4 *pControlPoints = pMesh->GetControlPoints(); for (std::unordered_map<int, Point>::iterator it = (*ControlP).begin(); it != (*ControlP).end(); ++it) { const FbxVector4 &P = pControlPoints[it->first]; pVertices[count].x = static_cast<FLOAT>(P[0]); pVertices[count].y = static_cast<FLOAT>(P[1]); pVertices[count].z = static_cast<FLOAT>(P[2]); // uv coordinate pVertices[count].tu = static_cast<FLOAT>((pUVarray->GetAt(*it->second.uvSet.begin()))[0]); pVertices[count].tv = static_cast<FLOAT>((pUVarray->GetAt(*it->second.uvSet.begin()))[1]); RemainPoints[it->first] = count; ++count; } g_pVB->Unlock(); // Create the IndexBuffer model.CreateIndexBuffer(); IDirect3DIndexBuffer9 *g_pIB = model.GetIndexBuffer(); WORD *index; int cnt = 0; g_pIB->Lock(0, 0, (void **)&index, 0); for (std::unordered_map<int, Face>::iterator it = (*Triangles).begin(); it != (*Triangles).end(); ++it) { index[cnt++] = RemainPoints[it->second.points[0]]; index[cnt++] = RemainPoints[it->second.points[1]]; index[cnt++] = RemainPoints[it->second.points[2]]; } g_pIB->Unlock(); }
//=============================================================================================================================== void FBXLoader::AssociateMaterialToMesh(FbxNode* inNode) { FbxLayerElementArrayTemplate<int>* materialIndices; FbxGeometryElement::EMappingMode materialMappingMode = FbxGeometryElement::eNone; FbxMesh* mesh = inNode->GetMesh(); if (mesh->GetElementMaterial()) { materialIndices = &(mesh->GetElementMaterial()->GetIndexArray()); materialMappingMode = mesh->GetElementMaterial()->GetMappingMode(); FBXSubsets* subset = mSubsets[iCurrentSubset]; if (materialIndices) { switch (materialMappingMode) { case FbxGeometryElement::eByPolygon: { if (materialIndices->GetCount() == subset->mPolygonCount) { for (uint32 i = 0; i < subset->mPolygonCount; ++i) { uint32 materialIndex = materialIndices->GetAt(i); //subset->mTriangles[i].materialIndex = materialIndex; subset->mMaterialIndex = materialIndex; } } } break; case FbxGeometryElement::eAllSame: { uint32 materialIndex = materialIndices->GetAt(0); for (uint32 i = 0; i < subset->mPolygonCount; ++i) { //subset->mTriangles[i].materialIndex = materialIndex; subset->mMaterialIndex = materialIndex; } } break; default: throw std::exception("Invalid mapping mode for material\n"); } } } }
void FBXImporter::ConnectMaterialsToMesh(FbxMesh* mesh, int triangleCount) { // Get the material index list of current mesh. FbxLayerElementArrayTemplate<int>* materialIndices; FbxGeometryElement::EMappingMode materialMappingMode = FbxGeometryElement::eNone; if (mesh->GetElementMaterial() != nullptr) { // Get the material indices. materialIndices = &mesh->GetElementMaterial()->GetIndexArray(); materialMappingMode = mesh->GetElementMaterial()->GetMappingMode(); switch (materialMappingMode) { // 单mesh多材质的情况,我们需要按照三角形数量来遍历材质ID。 case FbxLayerElement::eByPolygon: isByPolygon = true; isAllSame = false; if (materialIndices->GetCount() == triangleCount) { int materialId = materialIndices->GetAt(0); int polygonCount = 0; vector<MaterialIdOffset>& offsets = mMeshData->materialIdOffsets; MaterialIdOffset offset; offset.material = new Material(); for (int triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) { int materialIndex = materialIndices->GetAt(triangleIndex); // 比较当前materialId和上次循环的materialId, // 如果相同的话说明我们在处理拥有同一个materialId的三角形集合, // 我们只需要增加三角形计数,保存materialId。 if (materialId == materialIndex) { offset.polygonCount++; offset.material->materialId = materialIndex; // 如果已经遍历最后一个三角形,保存材质偏移信息。n if (triangleIndex == triangleCount - 1) { offsets.push_back(offset); } } // 如果当前materialId和上次循环的不同,说明开始了新的三角形集合 // 那么我们就将旧的集合保存到容器,开始处理新集合。 else { offsets.push_back(offset); offset.material = new Material(); offset.material->materialId = materialIndex; offset.polygonCount = 0; offset.polygonCount++; } materialId = materialIndex; } } break; case FbxLayerElement::eAllSame: { isAllSame = true; isByPolygon = false; int materialIndex = materialIndices->GetAt(0); MaterialIdOffset offset; offset.material = new Material(); vector<MaterialIdOffset>& offsets = mMeshData->materialIdOffsets; offset.material->materialId = materialIndex; offset.polygonCount = triangleCount; offsets.push_back(offset); } break; default: break; } } }
int Mesh::GetMaterialId(int polygon) { FbxLayerElementArrayTemplate<int> *materials = nullptr; m_nativeMesh->GetMaterialIndices(&materials); return materials->GetAt(polygon); }
//ур╣╫ак bool VBOMesh::Initialize(const FbxMesh *pMesh) { if (!pMesh->GetNode()) return false; const int lPolygonCount = pMesh->GetPolygonCount(); // Count the polygon count of each material FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL; FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone; if (pMesh->GetElementMaterial()) { lMaterialIndice = &pMesh->GetElementMaterial()->GetIndexArray(); lMaterialMappingMode = pMesh->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); if (mSubMeshes.GetCount() < lMaterialIndex + 1) { mSubMeshes.Resize(lMaterialIndex + 1); } if (mSubMeshes[lMaterialIndex] == NULL) { mSubMeshes[lMaterialIndex] = new SubMesh; } 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 < mSubMeshes.GetCount(); i++) { if (mSubMeshes[i] == NULL) mSubMeshes[i] = new SubMesh; } // Record the offset (how many vertex) const int lMaterialCount = mSubMeshes.GetCount(); int lOffset = 0; for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex) { mSubMeshes[lIndex]->IndexOffset = lOffset; lOffset += mSubMeshes[lIndex]->TriangleCount * 3; // This will be used as counter in the following procedures, reset to zero mSubMeshes[lIndex]->TriangleCount = 0; } FBX_ASSERT(lOffset == lPolygonCount * 3); } } } // All faces will use the same material. if (mSubMeshes.GetCount() == 0) { mSubMeshes.Resize(1); mSubMeshes[0] = new SubMesh(); } // 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. mHasNormal = pMesh->GetElementNormalCount() > 0; mHasUV = pMesh->GetElementUVCount() > 0; FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone; FbxGeometryElement::EMappingMode lUVMappingMode = FbxGeometryElement::eNone; if (mHasNormal) { lNormalMappingMode = pMesh->GetElementNormal(0)->GetMappingMode(); if (lNormalMappingMode == FbxGeometryElement::eNone) { mHasNormal = false; } if (mHasNormal && lNormalMappingMode != FbxGeometryElement::eByControlPoint) { mAllByControlPoint = false; } } if (mHasUV) { lUVMappingMode = pMesh->GetElementUV(0)->GetMappingMode(); if (lUVMappingMode == FbxGeometryElement::eNone) { mHasUV = false; } if (mHasUV && lUVMappingMode != FbxGeometryElement::eByControlPoint) { mAllByControlPoint = false; } } // Allocate the array memory, by control point or by polygon vertex. int lPolygonVertexCount = pMesh->GetControlPointsCount(); if (!mAllByControlPoint) { lPolygonVertexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; } float * lVertices = new float[lPolygonVertexCount * VERTEX_STRIDE]; unsigned int * lIndices = new unsigned int[lPolygonCount * TRIANGLE_VERTEX_COUNT]; float * lNormals = NULL; if (mHasNormal) { lNormals = new float[lPolygonVertexCount * NORMAL_STRIDE]; } float * lUVs = NULL; FbxStringList lUVNames; pMesh->GetUVSetNames(lUVNames); const char * lUVName = NULL; if (mHasUV && lUVNames.GetCount()) { lUVs = new float[lPolygonVertexCount * UV_STRIDE]; lUVName = lUVNames[0]; } // Populate the array with vertex attribute, if by control point. const FbxVector4 * lControlPoints = pMesh->GetControlPoints(); FbxVector4 lCurrentVertex; FbxVector4 lCurrentNormal; FbxVector2 lCurrentUV; if (mAllByControlPoint) { const FbxGeometryElementNormal * lNormalElement = NULL; const FbxGeometryElementUV * lUVElement = NULL; if (mHasNormal) { lNormalElement = pMesh->GetElementNormal(0); } if (mHasUV) { lUVElement = pMesh->GetElementUV(0); } for (int lIndex = 0; lIndex < lPolygonVertexCount; ++lIndex) { // Save the vertex position. lCurrentVertex = lControlPoints[lIndex]; lVertices[lIndex * VERTEX_STRIDE] = static_cast<float>(lCurrentVertex[0]); lVertices[lIndex * VERTEX_STRIDE + 1] = static_cast<float>(lCurrentVertex[1]); lVertices[lIndex * VERTEX_STRIDE + 2] = static_cast<float>(lCurrentVertex[2]); lVertices[lIndex * VERTEX_STRIDE + 3] = 1; // Save the normal. if (mHasNormal) { int lNormalIndex = lIndex; if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex); lNormals[lIndex * NORMAL_STRIDE] = static_cast<float>(lCurrentNormal[0]); lNormals[lIndex * NORMAL_STRIDE + 1] = static_cast<float>(lCurrentNormal[1]); lNormals[lIndex * NORMAL_STRIDE + 2] = static_cast<float>(lCurrentNormal[2]); } // Save the UV. if (mHasUV) { int lUVIndex = lIndex; if (lUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lUVIndex = lUVElement->GetIndexArray().GetAt(lIndex); } lCurrentUV = lUVElement->GetDirectArray().GetAt(lUVIndex); lUVs[lIndex * UV_STRIDE] = static_cast<float>(lCurrentUV[0]); lUVs[lIndex * UV_STRIDE + 1] = static_cast<float>(lCurrentUV[1]); } } } 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 = mSubMeshes[lMaterialIndex]->IndexOffset + mSubMeshes[lMaterialIndex]->TriangleCount * 3; for (int lVerticeIndex = 0; lVerticeIndex < TRIANGLE_VERTEX_COUNT; ++lVerticeIndex) { const int lControlPointIndex = pMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex); if (mAllByControlPoint) { lIndices[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lControlPointIndex); } // Populate the array with vertex attribute, if by polygon vertex. else { lIndices[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount); lCurrentVertex = lControlPoints[lControlPointIndex]; lVertices[lVertexCount * VERTEX_STRIDE] = static_cast<float>(lCurrentVertex[0]); lVertices[lVertexCount * VERTEX_STRIDE + 1] = static_cast<float>(lCurrentVertex[1]); lVertices[lVertexCount * VERTEX_STRIDE + 2] = static_cast<float>(lCurrentVertex[2]); lVertices[lVertexCount * VERTEX_STRIDE + 3] = 1; if (mHasNormal) { pMesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); lNormals[lVertexCount * NORMAL_STRIDE] = static_cast<float>(lCurrentNormal[0]); lNormals[lVertexCount * NORMAL_STRIDE + 1] = static_cast<float>(lCurrentNormal[1]); lNormals[lVertexCount * NORMAL_STRIDE + 2] = static_cast<float>(lCurrentNormal[2]); } if (mHasUV) { bool lUnmappedUV; pMesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName, lCurrentUV, lUnmappedUV); lUVs[lVertexCount * UV_STRIDE] = static_cast<float>(lCurrentUV[0]); lUVs[lVertexCount * UV_STRIDE + 1] = static_cast<float>(lCurrentUV[1]); } } ++lVertexCount; } mSubMeshes[lMaterialIndex]->TriangleCount += 1; } // Create VBOs glGenBuffers(VBO_COUNT, mVBONames); // Save vertex attributes into GPU glBindBuffer(GL_ARRAY_BUFFER, mVBONames[VERTEX_VBO]); glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * VERTEX_STRIDE * sizeof(float), lVertices, GL_STATIC_DRAW); delete[] lVertices; if (mHasNormal) { glBindBuffer(GL_ARRAY_BUFFER, mVBONames[NORMAL_VBO]); glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * NORMAL_STRIDE * sizeof(float), lNormals, GL_STATIC_DRAW); delete[] lNormals; } if (mHasUV) { glBindBuffer(GL_ARRAY_BUFFER, mVBONames[UV_VBO]); glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * UV_STRIDE * sizeof(float), lUVs, GL_STATIC_DRAW); delete[] lUVs; } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBONames[INDEX_VBO]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, lPolygonCount * TRIANGLE_VERTEX_COUNT * sizeof(unsigned int), lIndices, GL_STATIC_DRAW); delete[] lIndices; return true; }
//-------------------------------------------------------------- void ofxFBXMesh::setFBXMesh( FbxMesh* lMesh ) { fbxMesh = lMesh; // name = lMesh->GetName(); mesh.clear(); // from ViewScene Example included with the FBX SDK // if (!lMesh->GetNode()) { ofLogError("ofxFBXMesh") << " error setFBXMesh, lMesh->GetNode failed" << endl; return; } const int lPolygonCount = lMesh->GetPolygonCount(); // Count the polygon count of each material FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL; FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone; if (lMesh->GetElementMaterial()) { lMaterialIndice = &lMesh->GetElementMaterial()->GetIndexArray(); lMaterialMappingMode = lMesh->GetElementMaterial()->GetMappingMode(); if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount); if (lMaterialIndice->GetCount() == lPolygonCount) { // make sure the vector is setup and we have the proper amount of materials ready // for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); if(lMaterialIndex >= 0) { if (subMeshes.size() < lMaterialIndex + 1) { subMeshes.resize(lMaterialIndex + 1); } } } // Count the faces of each material for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); // cout << "lMaterialIndex = " << lMaterialIndex << " submesh.size = " << subMeshes.size() << endl; if(lMaterialIndex >= 0 ) { subMeshes[lMaterialIndex].triangleCount += 1; } } // Record the offset (how many vertex) const int lMaterialCount = subMeshes.size(); int lOffset = 0; for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex) { subMeshes[lIndex].indexOffset = lOffset; lOffset += subMeshes[lIndex].triangleCount * 3; // subMeshes[lIndex].totalIndices = subMeshes[lIndex].triangleCount * 3; // cout << "polygon: " << lIndex << " totalIndices = " << subMeshes[lIndex].totalIndices << endl; // This will be used as counter in the following procedures, reset to zero subMeshes[lIndex].triangleCount = 0; } FBX_ASSERT(lOffset == lPolygonCount * 3); // what? } } } if(subMeshes.size() == 0) { subMeshes.resize(1); } // TODO: Account for if all mapping modes are not by control point // bool bHasNormals = lMesh->GetElementNormalCount() > 0; bool bMapNormalsByControlPoint = true; bool bHasUvs = lMesh->GetElementUVCount() > 0; bool bMapUvsByControlPoint = true; // are the normals mapped by control point or by polygon? FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone; if(bHasNormals) { lNormalMappingMode = lMesh->GetElementNormal(0)->GetMappingMode(); if (lNormalMappingMode == FbxGeometryElement::eNone) { bHasNormals = false; } if (bHasNormals && lNormalMappingMode != FbxGeometryElement::eByControlPoint) { bMapNormalsByControlPoint = false; } } FbxGeometryElement::EMappingMode lUVMappingMode = FbxGeometryElement::eNone; if (bHasUvs) { lUVMappingMode = lMesh->GetElementUV(0)->GetMappingMode(); if (lUVMappingMode == FbxGeometryElement::eNone) { bHasUvs = false; } if (bHasUvs && lUVMappingMode != FbxGeometryElement::eByControlPoint) { bMapUvsByControlPoint = false; } } bAllMappedByControlPoint = (bMapNormalsByControlPoint && bMapUvsByControlPoint); // if(lMaterialMappingMode == FbxGeometryElement::eAllSame) { // // } int lPolygonVertexCount = lMesh->GetControlPointsCount(); if( bAllMappedByControlPoint ) { const FbxVector4 * lControlPoints = lMesh->GetControlPoints(); for(int i = 0; i < lMesh->GetControlPointsCount(); i++ ) { mesh.addVertex( ofVec3f( lControlPoints[i][0], lControlPoints[i][1], lControlPoints[i][2] ) ); } for(int i = 0; i < lMesh->GetPolygonCount(); i++ ) { for (int lVerticeIndex = 0; lVerticeIndex < 3; ++lVerticeIndex) { const int lControlPointIndex = lMesh->GetPolygonVertex(i, lVerticeIndex); mesh.addIndex( lControlPointIndex ); } } if(subMeshes.size() == 1) { subMeshes[0].totalIndices = mesh.getNumIndices(); } // normals if(bHasNormals) { ofMesh normalsMesh; //cout << "ofxFBXMesh :: we have normals for " << getName() << endl; if(bMapNormalsByControlPoint) { //cout << "ofxFBXMesh :: normals by control point for " << getName() << endl; const FbxGeometryElementNormal * lNormalElement = lMesh->GetElementNormal(0); for(int i = 0; i < lMesh->GetControlPointsCount(); i++ ) { int lNormalIndex = i; if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lNormalIndex = lNormalElement->GetIndexArray().GetAt(i); } FbxVector4 lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex); normalsMesh.addNormal( ofVec3f(lCurrentNormal[0], lCurrentNormal[1], lCurrentNormal[2]) ); } mesh.addNormals( normalsMesh.getNormals() ); } } // textures // if(bHasUvs) { //cout << "ofxFBXMesh :: we have tex coords for " << getName() << endl; if(bMapUvsByControlPoint) { //cout << "ofxFBXMesh :: tex coords by control point " << getName() << endl; const FbxGeometryElementUV * lUVElement = lMesh->GetElementUV(0); for(int i = 0; i < lMesh->GetControlPointsCount(); i++ ) { int lUVIndex = i; if (lUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lUVIndex = lUVElement->GetIndexArray().GetAt(i); } FbxVector2 lCurrentUV = lUVElement->GetDirectArray().GetAt(lUVIndex); mesh.addTexCoord( ofVec2f(lCurrentUV[0], lCurrentUV[1]) ); } } } } else { // cout << "--- " << getName() << " mapped by polygons ---------------" << endl; // cout << "numSubMeshes = " << subMeshes.size() << " polygon count = " << lPolygonCount << " control points = " << fbxMesh->GetControlPointsCount() << endl; // if(lMaterialMappingMode == FbxGeometryElement::eNone) { // cout << "Material mapping mode = none" << endl; // } else if (lMaterialMappingMode == FbxGeometryElement::eByControlPoint) { // cout << "Material mapping mode = eByControlPoint" << endl; // } else if(lMaterialMappingMode == FbxGeometryElement::eByPolygonVertex) { // cout << "Material mapping mode = eByPolygonVertex" << endl; // } else if(lMaterialMappingMode == FbxGeometryElement::eByPolygon) { // cout << "Material mapping mode = eByPolygon" << endl; // } else if(lMaterialMappingMode == FbxGeometryElement::eByEdge) { // cout << "Material mapping mode = eByEdge" << endl; // } else if(lMaterialMappingMode == FbxGeometryElement::eAllSame) { // cout << "Material mapping mode = eAllSame" << endl; // } // // if(lMaterialIndice) { // cout << "lMaterialIndice size = " << lMaterialIndice->GetCount() << endl; // } else { // cout << "did not get the lMaterialIndice" << endl; // } const FbxVector4 * lControlPoints = fbxMesh->GetControlPoints(); mesh.getVertices().resize( lPolygonCount * 3 ); mesh.getIndices().resize( lPolygonCount * 3 ); if(bHasNormals) { mesh.getNormals().resize( lPolygonCount * 3 ); } // cout << "Polygon vertex count = " << fbxMesh->GetPolygonVertexCount() << endl; const char * lUVName = NULL; FbxStringList lUVNames; fbxMesh->GetUVSetNames(lUVNames); if(bHasUvs && lUVNames.GetCount() ) { mesh.getTexCoords().resize( lPolygonCount * 3 ); lUVName = lUVNames[0]; } for(int i = 0; i < lUVNames.GetCount(); i++ ) { // cout << "lUVName = " << lUVNames[0] << endl; } FbxVector4 lCurrentVertex; FbxVector4 lCurrentNormal; FbxVector2 lCurrentUV; const FbxGeometryElementUV * lUVElement = lMesh->GetElementUV(0); 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); if(lMaterialIndex < 0) { lMaterialIndex = 0; } } // Where should I save the vertex attribute index, according to the material const int lIndexOffset = subMeshes[lMaterialIndex].indexOffset + subMeshes[lMaterialIndex].triangleCount * 3; // const int lIndexOffset = fbxMesh->GetPolygonVertexIndex(lPolygonIndex); for (int lVerticeIndex = 0; lVerticeIndex < 3; ++lVerticeIndex) { const int lControlPointIndex = fbxMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex); // Populate the array with vertex attribute, if by polygon vertex. mesh.getIndices()[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount); lCurrentVertex = lControlPoints[ lControlPointIndex ]; mesh.getVertices()[lVertexCount].set( lCurrentVertex[0], lCurrentVertex[1], lCurrentVertex[2] ); if (bHasNormals) { if(fbxMesh->GetPolygonVertexNormal( lPolygonIndex, lVerticeIndex, lCurrentNormal )) { int normalIndex = lVertexCount; mesh.getNormals()[normalIndex].set( lCurrentNormal[0], lCurrentNormal[1], lCurrentNormal[2] ); } } if (bHasUvs) { bool lUnmappedUV; fbxMesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName, lCurrentUV, lUnmappedUV); int tcoordIndex = lVertexCount; mesh.getTexCoords()[ tcoordIndex ].set( lCurrentUV[0], lCurrentUV[1] ); } ++lVertexCount; } subMeshes[lMaterialIndex].triangleCount += 1; subMeshes[lMaterialIndex].totalIndices += 3; // cout << "materialIndex = " << lMaterialIndex << endl; } } // All faces will use the same material. // if ( subMeshes.size() == 1) { // // meshMaterials.resize(1); //// subMeshes[0].totalIndices = mesh.getNumIndices(); // } for(int i = 0; i < subMeshes.size(); i++ ) { // cout << i << " submesh totalindicies = " << subMeshes[i].totalIndices << " total verts = " << mesh.getNumVertices() << " polygonos = " << lPolygonCount << endl; } // cout << "--------------------------------------- " << endl << endl; veebs.setMesh( mesh, GL_STREAM_DRAW ); original = mesh; }
bool Mesh::init(FbxMesh* pFbxMesh) { uint32_t normalCount = pFbxMesh->GetElementNormalCount(); uint32_t uvCount = pFbxMesh->GetElementUVCount(); FbxGeometryElement::EMappingMode normalMappingMode = normalCount ? pFbxMesh->GetElementNormal(0)->GetMappingMode() : FbxGeometryElement::eNone; FbxGeometryElement::EMappingMode uvMappingModel = uvCount ? pFbxMesh->GetElementUV(0)->GetMappingMode() : FbxGeometryElement::eNone; bool hasNormal = normalMappingMode != FbxGeometryElement::eNone; bool hasUV = uvMappingModel != FbxGeometryElement::eNone; bool byControlPoint = hasNormal && normalMappingMode == FbxGeometryElement::eByControlPoint && hasUV && uvMappingModel == FbxGeometryElement::eByControlPoint; uint32_t polygonCount = pFbxMesh->GetPolygonCount(); uint32_t controlPointCount = byControlPoint ? pFbxMesh->GetControlPointsCount() : polygonCount * TRIANGLE_VERTEX_COUNT; this->vertices.resize(controlPointCount * VERTEX_STRIDE); this->indices.resize(polygonCount * TRIANGLE_VERTEX_COUNT); if (hasNormal) this->normals.resize(controlPointCount * NORMAL_STRIDE); FbxStringList uvNames; pFbxMesh->GetUVSetNames(uvNames); const char* pUVName = nullptr; if (hasUV) { this->uvs.resize(controlPointCount * UV_STRIDE); pUVName = uvNames[0]; } /* Vertex Attributes */ const FbxVector4* pControlPoints = pFbxMesh->GetControlPoints(); FbxVector4 currentVertex; FbxVector4 currentNormal; FbxVector2 currentUV; if (byControlPoint) { const FbxGeometryElementNormal* pNormalElement = nullptr; const FbxGeometryElementUV* pUVElement = nullptr; if (hasNormal) pNormalElement = pFbxMesh->GetElementNormal(0); if (hasUV) pUVElement = pFbxMesh->GetElementUV(0); for (uint32_t i = 0; i < controlPointCount; ++i) { currentVertex = pControlPoints[i]; this->vertices[i * VERTEX_STRIDE] = static_cast<float>(currentVertex[0]); this->vertices[i * VERTEX_STRIDE + 1] = static_cast<float>(currentVertex[1]); this->vertices[i * VERTEX_STRIDE + 2] = static_cast<float>(currentVertex[2]); this->vertices[i * VERTEX_STRIDE + 3] = 1.0f; if (hasNormal) { int normalIndex = i; if (pNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { normalIndex = pNormalElement->GetIndexArray().GetAt(i); } currentNormal = pNormalElement->GetDirectArray().GetAt(normalIndex); this->normals[i * NORMAL_STRIDE] = static_cast<float>(currentNormal[0]); this->normals[i * NORMAL_STRIDE + 1] = static_cast<float>(currentNormal[1]); this->normals[i * NORMAL_STRIDE + 2] = static_cast<float>(currentNormal[2]); } if (hasUV) { int uvIndex = i; if (pUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { uvIndex = pUVElement->GetIndexArray().GetAt(i); } currentUV = pUVElement->GetDirectArray().GetAt(uvIndex); this->uvs[i * UV_STRIDE] = static_cast<float>(currentUV[0]); this->uvs[i * UV_STRIDE + 1] = static_cast<float>(currentUV[1]); } } } // end of byControlPoint /* Slice the mesh according to materials */ FbxLayerElementArrayTemplate<int>* pMaterialIndices = nullptr; FbxGeometryElement::EMappingMode materialMappingMode = FbxGeometryElement::eNone; if (pFbxMesh->GetElementMaterial()) { pMaterialIndices = &pFbxMesh->GetElementMaterial()->GetIndexArray(); materialMappingMode = pFbxMesh->GetElementMaterial()->GetMappingMode(); if (pMaterialIndices && materialMappingMode == FbxGeometryElement::eByPolygon) { FBX_ASSERT(pMaterialIndices->GetCount() == polygonCount); for (uint32_t i = 0; i < polygonCount; ++i) { const uint32_t materialIndex = pMaterialIndices->GetAt(i); if (materialIndex >= slices.size()) // we meet a new material { slices.emplace_back(0, 0); } slices[materialIndex].triangleCount += 1; } int offset = 0; for (uint32_t i = 0; i < slices.size(); ++i) { slices[i].indexOffset = offset; offset += slices[i].triangleCount * 3; // this will be reused during per-Polygon processing slices[i].triangleCount = 0; } FBX_ASSERT(offset == polygonCount * 3); } } // There is only one material. if (slices.size() == 0) { slices.emplace_back(0, 0); } /* Indices */ for (uint32_t vertexCount = 0, i = 0; i < polygonCount; ++i) { int materialIndex = 0; if (pMaterialIndices && materialMappingMode == FbxGeometryElement::eByPolygon) { materialIndex = pMaterialIndices->GetAt(i); } const int indexOffset = slices[materialIndex].indexOffset + slices[materialIndex].triangleCount * 3; for (int v = 0; v < TRIANGLE_VERTEX_COUNT; ++v) { const int controlPointIndex = pFbxMesh->GetPolygonVertex(i, v); if (byControlPoint) { this->indices[indexOffset + v] = static_cast<unsigned int>(controlPointIndex); } else { this->indices[indexOffset + v] = static_cast<unsigned int>(vertexCount); currentVertex = pControlPoints[controlPointIndex]; this->vertices[vertexCount * VERTEX_STRIDE] = static_cast<float>(currentVertex[0]); this->vertices[vertexCount * VERTEX_STRIDE + 1] = static_cast<float>(currentVertex[1]); this->vertices[vertexCount * VERTEX_STRIDE + 2] = static_cast<float>(currentVertex[2]); this->vertices[vertexCount * VERTEX_STRIDE + 3] = 1.0f; if (hasNormal) { pFbxMesh->GetPolygonVertexNormal(i, v, currentNormal); this->normals[vertexCount * NORMAL_STRIDE] = static_cast<float>(currentNormal[0]); this->normals[vertexCount * NORMAL_STRIDE + 1] = static_cast<float>(currentNormal[1]); this->normals[vertexCount * NORMAL_STRIDE + 2] = static_cast<float>(currentNormal[2]); } if (hasUV) { bool bUnmappedUV; pFbxMesh->GetPolygonVertexUV(i, v, pUVName, currentUV, bUnmappedUV); this->uvs[vertexCount * UV_STRIDE] = static_cast<float>(currentUV[0]); this->uvs[vertexCount * UV_STRIDE] = static_cast<float>(currentUV[1]); } } ++vertexCount; } slices[materialIndex].triangleCount += 1; } return true; }
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; }
Submesh *FBX::buildSubmeshFromFBX(FbxMesh *lMesh, int material_index, bool single_material) { int lPolygonCount=lMesh->GetPolygonCount(); FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL; bool add=false; if (!single_material) { FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone; if (lMesh->GetElementMaterial()) { lMaterialIndice = &lMesh->GetElementMaterial()->GetIndexArray(); lMaterialMappingMode = lMesh->GetElementMaterial()->GetMappingMode(); if (!lMaterialIndice) printf("Mesh has no material index element.\n"); if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { if (lMaterialIndice->GetCount() == lPolygonCount) { add = true; } } } } else add = true; if (add) { vector<Vertex *> new_vertices; vector<Vector3> new_faces; int control_points_count=lMesh->GetControlPointsCount(); FbxVector4 *control_points=lMesh->GetControlPoints(); int vertex_index = 0; for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { if (lMaterialIndice) { const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); if (lMaterialIndex != material_index) continue; } int polygon_size=lMesh->GetPolygonSize(lPolygonIndex); if (polygon_size == 3) { Vector3 face; for (int j=0; j<polygon_size; j++) { Vertex *vertex=new Vertex(); int control_point_index=lMesh->GetPolygonVertex(lPolygonIndex, j); FbxVector4 control_point=control_points[control_point_index]; vertex->setPosition(Vector3(control_point[0], control_point[2], -control_point[1])); // Get Normal for Vertex FbxVector4 normal; lMesh->GetPolygonVertexNormal(lPolygonIndex, j, normal); vertex->setNormal(Vector3(normal[0], normal[2], -normal[1])); // Get UVs for Vertex FbxStringList uv_sets; lMesh->GetUVSetNames(uv_sets); for (int set=0; set<uv_sets.GetCount(); set++) { if (set >= 4) break; FbxVector2 uv; bool no_uv; lMesh->GetPolygonVertexUV(lPolygonIndex, j, uv_sets[set].Buffer(), uv, no_uv); vertex->setUV(Vector2(uv[0], 1.0 - uv[1]), set); } // Get Vertex Color for Vertex FbxColor vtx_c(1.0, 1.0, 1.0, 1.0); for (int l = 0; l < lMesh->GetElementVertexColorCount(); l++) { FbxGeometryElementVertexColor* leVtxc = lMesh->GetElementVertexColor(l); if (leVtxc->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (leVtxc->GetReferenceMode() == FbxGeometryElement::eDirect) { vtx_c = leVtxc->GetDirectArray().GetAt(control_point_index); } else if (leVtxc->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) { int id = leVtxc->GetIndexArray().GetAt(control_point_index); vtx_c = leVtxc->GetDirectArray().GetAt(id); } } else if (leVtxc->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { if (leVtxc->GetReferenceMode() == FbxGeometryElement::eDirect) { vtx_c = leVtxc->GetDirectArray().GetAt(vertex_index); } else if (leVtxc->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) { int id = leVtxc->GetIndexArray().GetAt(vertex_index); vtx_c = leVtxc->GetDirectArray().GetAt(id); } } } vertex->setColor(Color(vtx_c.mRed, vtx_c.mGreen, vtx_c.mBlue, vtx_c.mAlpha)); if (j == 0) face.x=new_vertices.size(); if (j == 1) face.y=new_vertices.size(); if (j == 2) face.z=new_vertices.size(); new_vertices.push_back(vertex); vertex_index++; } new_faces.push_back(face); } else printf("Unsupported polygon size %d.\n", polygon_size); } printf("Building submesh with %d vertices and %d faces\n", new_vertices.size(), new_faces.size()); if ((new_vertices.size() >= 3) && new_faces.size()) { Submesh *submesh=new Submesh(); submesh->build(new_vertices, new_faces); submesh->addBone(0); VertexFormat *vertex_format=new VertexFormat(LIBGENS_VERTEX_FORMAT_PC); submesh->setVertexFormat(vertex_format); return submesh; } } return NULL; }
FBXMesh::Builder::MeshMetaData::MeshMetaData(FbxMesh const* mesh, unsigned int vaoOffset) : mesh(mesh), vaoOffset(vaoOffset), hasNormals(false), hasUvs(false) { if (!mesh->GetNode()) return; const int lPolygonCount = mesh->GetPolygonCount(); // Count the polygon count of each material -> split up in submeshes 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); if (subMeshMetaData.size() < lMaterialIndex + 1) { subMeshMetaData.resize(lMaterialIndex + 1); } subMeshMetaData[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 < subMeshMetaData.size(); i++) //{ // if (subMeshMetaData[i] == NULL) // mSubMeshes[i] = new SubMesh; //} // Record the offset (how many vertex) const int lMaterialCount = (int)subMeshMetaData.size(); int lOffset = 0; for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex) { subMeshMetaData[lIndex].indexOffset = lOffset; lOffset += subMeshMetaData[lIndex].triangleCount * 3; // This will be used as counter in the following procedures, reset to zero subMeshMetaData[lIndex].triangleCount = 0; } FBX_ASSERT(lOffset == lPolygonCount * 3); } } } // All faces will use the same material. if (subMeshMetaData.size() == 0) { subMeshMetaData.resize(1); } hasNormals = mesh->GetElementNormalCount() > 0; hasUvs = mesh->GetElementUVCount() > 0; allByControlPoint = true; // Congregate all the data of a mesh to be cached. // If normal or UV is by polygon vertex, record all vertex attributes by polygon vertex. FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone; FbxGeometryElement::EMappingMode lUVMappingMode = FbxGeometryElement::eNone; if (hasNormals) { lNormalMappingMode = mesh->GetElementNormal(0)->GetMappingMode(); if (lNormalMappingMode == FbxGeometryElement::eNone) { hasNormals = false; } if (hasNormals && lNormalMappingMode != FbxGeometryElement::eByControlPoint) { allByControlPoint = false; } } if (hasUvs) { lUVMappingMode = mesh->GetElementUV(0)->GetMappingMode(); if (lUVMappingMode == FbxGeometryElement::eNone) { hasUvs = false; } if (hasUvs && lUVMappingMode != FbxGeometryElement::eByControlPoint) { allByControlPoint = false; } } // Allocate the array memory, by control point or by polygon vertex. int lPolygonVertexCount = mesh->GetControlPointsCount(); if (!allByControlPoint) { lPolygonVertexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; } vertices.resize(lPolygonVertexCount); indices.resize(lPolygonCount * TRIANGLE_VERTEX_COUNT); float * lNormals = NULL; if (hasNormals) { normals.resize(lPolygonVertexCount); } float * lUVs = NULL; FbxStringList lUVNames; mesh->GetUVSetNames(lUVNames); const char * lUVName = NULL; if (hasUvs && lUVNames.GetCount()) { uvs.resize(lPolygonVertexCount); lUVName = lUVNames[0]; } // Populate the array with vertex attribute, if by control point. const FbxVector4 * lControlPoints = mesh->GetControlPoints(); FbxVector4 lCurrentVertex; FbxVector4 lCurrentNormal; FbxVector2 lCurrentUV; if (allByControlPoint) { const FbxGeometryElementNormal * lNormalElement = NULL; const FbxGeometryElementUV * lUVElement = NULL; if (hasNormals) { lNormalElement = mesh->GetElementNormal(0); } if (hasUvs) { lUVElement = mesh->GetElementUV(0); } for (int lIndex = 0; lIndex < lPolygonVertexCount; ++lIndex) { // Save the vertex position. lCurrentVertex = lControlPoints[lIndex]; vertices[lIndex] = glm::vec3(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2])); modelSpaceAABB.merge(vertices[lIndex]); // Save the normal. if (hasNormals) { int lNormalIndex = lIndex; if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex); normals[lIndex] = glm::vec3(static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); } // Save the UV. if (hasUvs) { int lUVIndex = lIndex; if (lUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lUVIndex = lUVElement->GetIndexArray().GetAt(lIndex); } lCurrentUV = lUVElement->GetDirectArray().GetAt(lUVIndex); uvs[lIndex] = glm::vec2(static_cast<float>(lCurrentUV[0]), static_cast<float>(lCurrentUV[1])); } } } 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 = subMeshMetaData[lMaterialIndex].indexOffset + subMeshMetaData[lMaterialIndex].triangleCount * 3; for (int lVerticeIndex = 0; lVerticeIndex < TRIANGLE_VERTEX_COUNT; ++lVerticeIndex) { const int lControlPointIndex = mesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex); if (allByControlPoint) { indices[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lControlPointIndex); } // Populate the array with vertex attribute, if by polygon vertex. else { indices[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount); lCurrentVertex = lControlPoints[lControlPointIndex]; vertices[lVertexCount] = glm::vec3(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2])); modelSpaceAABB.merge(vertices[lVertexCount]); if (hasNormals) { mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); normals[lVertexCount] = glm::vec3(static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); } if (hasUvs) { bool lUnmappedUV; mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName, lCurrentUV, lUnmappedUV); uvs[lVertexCount] = glm::vec2(static_cast<float>(lCurrentUV[0]), static_cast<float>(lCurrentUV[1])); } } ++lVertexCount; } subMeshMetaData[lMaterialIndex].triangleCount += 1; } }