//=============================================================================================================================== 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::LoadMaterials(FBXMeshData* fbxMeshData) { FbxNode* node = nullptr; FbxMesh* mesh = fbxMeshData->mMesh; int materialCount = 0; int polygonCount = mesh->GetPolygonCount(); if ((mesh != nullptr) && (mesh->GetNode() != nullptr)) { node = mesh->GetNode(); materialCount = node->GetMaterialCount(); } bool isAllSame = true; for (int i = 0; i < mesh->GetElementMaterialCount(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(i); if (materialElement->GetMappingMode() == FbxGeometryElement::eByPolygon) { isAllSame = false; break; } } //For eAllSame mapping type, just out the material and texture mapping info once if (isAllSame) { for (int i = 0; i < mesh->GetElementMaterialCount(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(i); if (materialElement->GetMappingMode() == FbxGeometryElement::eAllSame) { FbxSurfaceMaterial* material = mesh->GetNode()->GetMaterial(materialElement->GetIndexArray().GetAt(0)); fbxMeshData->mSurfaceMaterial = material; int materialId = materialElement->GetIndexArray().GetAt(0); if (materialId >= 0) { LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sDiffuse); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sBump); vector<string>& textureFiles = mMeshData->textureFiles; auto iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getDiffuseTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getDiffuseTextureFile()); } if (fbxMeshData->getNormalMapTextureFile().size() > 0) { iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getNormalMapTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getNormalMapTextureFile()); } } } } } } //For eByPolygon mapping type, just out the material and texture mapping info once else { int materialId = 0; int polygonId = 0; polygonCount = 0; vector<string>& textureFiles = mMeshData->textureFiles; vector<MaterialIdOffset>& materialIdOffsets = mMeshData->materialIdOffsets; for (int i = 0; i < materialIdOffsets.size(); i++) { FbxGeometryElementMaterial* materialElement = mesh->GetElementMaterial(0); FbxSurfaceMaterial* material = NULL; materialId = mMeshData->materialIdOffsets[i].material->materialId; material = mesh->GetNode()->GetMaterial(materialElement->GetIndexArray().GetAt(polygonId)); polygonCount = materialIdOffsets[i].polygonCount; fbxMeshData->mSurfaceMaterial = material; fbxMeshData->mMaterial = new Material(); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sDiffuse); LoadMaterialTexture(fbxMeshData, FbxSurfaceMaterial::sBump); materialIdOffsets[i].material = fbxMeshData->mMaterial; auto iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getDiffuseTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getDiffuseTextureFile()); } if (fbxMeshData->getNormalMapTextureFile().size() > 0) { iter = find(textureFiles.begin(), textureFiles.end(), fbxMeshData->getNormalMapTextureFile()); if (iter == textureFiles.end()) { textureFiles.push_back(fbxMeshData->getNormalMapTextureFile()); } } polygonId += polygonCount; } } }
void FbxLoader::ProcessMesh(FbxNode* node, Node& meshNode) { FbxMesh* currMesh = node->GetMesh(); if(!currMesh) return; FbxLayerElementTangent* tangents = nullptr; if(useNormalMap) { if(currMesh->GetElementTangentCount() < 1) { currMesh->GenerateTangentsDataForAllUVSets(); tangents = currMesh->GetElementTangent(); } } std::map<int, std::vector<Vertex>> subMeshes; int vertCounter = 0; const int polygonCount = currMesh->GetPolygonCount(); for(int i = 0; i < polygonCount; i++) { const int polySize = currMesh->GetPolygonSize(i); int nMaterials = node->GetMaterialCount(); auto elementMaterial = currMesh->GetElementMaterial(); int mi = 0; if(elementMaterial) mi = currMesh->GetElementMaterial()->GetIndexArray()[i]; for(int j = 2; j >= 0; --j) { int ctrlIndex = currMesh->GetPolygonVertex(i, j); auto& currCtrlPoint = meshNode.controlPoints[ctrlIndex]; FbxVector4 v4; auto& pos = currCtrlPoint.position * factor; currMesh->GetPolygonVertexNormal(i, j, v4); Vector3 normal = { (float)v4[0], (float)v4[1], (float)v4[2] }; Vector3 tangent = { 0, 0, 0 }; if(useNormalMap) { ReadTangent(tangents, ctrlIndex, vertCounter, v4); tangent = { (float)v4[0], (float)v4[1], (float)v4[2] }; } Vector2 uv; FbxStringList uvSetNames; currMesh->GetUVSetNames(uvSetNames); bool unmapped = false; // supports one uv set only if(uvSetNames.GetCount() > 0) { FbxVector2 UV; currMesh->GetPolygonVertexUV(i, j, uvSetNames[0], UV, unmapped); uv = { (float)UV[0], (float)UV[1] }; } if(axismode == eLeftHanded) { pos.x *= -1; uv.y = 1 - uv.y; normal.x *= -1; tangent.x *= -1; } Vector4 weights = { 0, 0, 0, 0 }; Byte4 indices = { 0, 0, 0, 0 }; int blendCount = (int)min(currCtrlPoint.blendWeigths.size(), 4); if(blendCount > 0) { meshNode.useSkinnedMesh = true; if(currCtrlPoint.blendWeigths.size() > 4) sort(currCtrlPoint.blendWeigths.begin(), currCtrlPoint.blendWeigths.end()); for(int i = 0; i < blendCount; i++) { weights[i] = currCtrlPoint.blendWeigths[i].weight; indices.m[i] = currCtrlPoint.blendWeigths[i].boneIndex; } } Vertex temp = { pos, uv, normal, tangent, indices, weights }; subMeshes[mi].push_back(temp); } ++vertCounter; } if(subMeshes.size() > 0) { int index = 0; meshNode.meshes.reserve(vertCounter); meshNode.vertIndices.reserve(vertCounter); meshNode.vertexCountOfSubMesh.reserve(subMeshes.size()); for(auto& pair : subMeshes) { auto& m = pair.second; for(int i = 0; i < m.size(); ++i) meshNode.vertIndices.emplace_back(index++); meshNode.vertexCountOfSubMesh.push_back((int)m.size()); meshNode.meshes.insert(meshNode.meshes.end(), m.begin(), m.end()); } } subMeshes.clear(); }
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 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); }