bool hasUvTextures(FbxMesh* fbxMesh) { FbxStringList uvSetNames; fbxMesh->GetUVSetNames(uvSetNames); return (uvSetNames.GetCount() > 0); }
// 頂点データ獲得 void GetFBXVertexData(FbxMesh* pMesh) { // 頂点座標と法線ベクトル獲得 std::vector<FbxVector4> positions, normals; FbxVector4 normal; // メモ:GetPolygonCount = 面数、GetPolygonSize = 頂点数 for(int i = 0; i < pMesh->GetPolygonCount(); i++) { for(int j = 0; j < pMesh->GetPolygonSize(i); j++) { // 頂点座標 positions.push_back(pMesh->GetControlPointAt(pMesh->GetPolygonVertex(i, j))); // 法線ベクトル pMesh->GetPolygonVertexNormal(i, j, normal); normals.push_back(normal); } } printf("頂点座標\n"); for(unsigned int i = 0; i < positions.size(); ++i) { printf("[%d]:X = %f Y = %f Z = %f W = %f\n", i, positions[i].mData[0], positions[i].mData[1], positions[i].mData[2], positions[i].mData[2]); } puts(""); printf("法線ベクトル\n"); for(unsigned i = 0; i < normals.size(); ++i) { printf("[%d]:X = %f Y = %f Z = %f W = %f\n", i, normals[i].mData[0], normals[i].mData[1], normals[i].mData[2], normals[i].mData[2]); } puts(""); // UVセットの名前配列獲得 FbxStringList uvSetNames; pMesh->GetUVSetNames(uvSetNames); printf("UVSet数 = %d\n", uvSetNames.GetCount()); bool unmapped = false; int UVCount = 0; for(int i = 0; i < uvSetNames.GetCount(); ++i) { printf("UVSet名[%d] = %s\n", i, uvSetNames.GetStringAt(i)); for(int j = 0; j < pMesh->GetPolygonCount(); ++j) { for(int k = 0; k < pMesh->GetPolygonSize(j); ++k) { FbxVector2 UV; pMesh->GetPolygonVertexUV(j, k, uvSetNames.GetStringAt(i), UV, unmapped); printf("[%d]:U = %f V = %f\n", UVCount++, UV.mData[0], UV.mData[1]); } } puts(""); } }
void CFBXLoader::CopyVertexData(FbxMesh* pMesh, FBX_MESH_NODE* meshNode) { if(!pMesh) return ; int lPolygonCount = pMesh->GetPolygonCount(); FbxVector4 pos, nor; meshNode->elements.numPosition = 1; meshNode->elements.numNormal = 1; unsigned int indx = 0; for(int i=0;i<lPolygonCount;i++) { // ポリゴン内の頂点数(一応、三角形化してるので3点のはずだがチェック) int lPolygonsize = pMesh->GetPolygonSize(i); for(int pol=0;pol<lPolygonsize;pol++) { int index = pMesh->GetPolygonVertex(i, pol); meshNode->indexArray.push_back(indx); pos = pMesh->GetControlPointAt(index); pMesh->GetPolygonVertexNormal(i,pol,nor); meshNode->m_positionArray.push_back( pos ); meshNode->m_normalArray.push_back( nor ); ++indx; } } // UV処理(UVは2つ以上ある場合があるので別処理) FbxStringList uvsetName; pMesh->GetUVSetNames(uvsetName); int numUVSet = uvsetName.GetCount(); meshNode->elements.numUVSet = numUVSet; bool unmapped = false; for(int uv=0;uv<numUVSet;uv++) { meshNode->uvsetID[uvsetName.GetStringAt(uv)] = uv; for(int i=0;i<lPolygonCount;i++) { int lPolygonsize = pMesh->GetPolygonSize(i); for(int pol=0;pol<lPolygonsize;pol++) { FbxString name = uvsetName.GetStringAt(uv); FbxVector2 texCoord; pMesh->GetPolygonVertexUV( i, pol, name, texCoord, unmapped); meshNode->m_texcoordArray.push_back(texCoord); } } } }
// 頂点データ獲得 void GetFBXVertexData(FbxMesh* pMesh, VertexDataArray& outVertexData) { // 頂点座標と法線ベクトル獲得 std::vector<FbxVector4> positions, normals; FbxVector4 normal; // メモ:GetPolygonCount = 面数、GetPolygonSize = 頂点数 for(int i = 0; i < pMesh->GetPolygonCount(); i++) { for(int j = 0; j < pMesh->GetPolygonSize(i); j++) { // 頂点座標 positions.push_back(pMesh->GetControlPointAt(pMesh->GetPolygonVertex(i, j))); // 法線ベクトル pMesh->GetPolygonVertexNormal(i, j, normal); normals.push_back(normal); } } // 配列初期化 outVertexData.resize(positions.size()); // 頂点座標と法線情報を格納 for(size_t i = 0; i < outVertexData.size(); ++i) { fbxsdk::FbxVector4& pos = positions[i]; fbxsdk::FbxVector4& normal = normals[i]; outVertexData[i].pos = DirectX::XMFLOAT3(pos.mData[0], pos.mData[1] , pos.mData[2]); outVertexData[i].normal = DirectX::XMFLOAT4(normal.mData[0], normal.mData[1], normal.mData[2], normal.mData[3]); } // UVセットの名前配列獲得 FbxStringList uvSetNames; pMesh->GetUVSetNames(uvSetNames); bool unmapped = false; int UVCount = 0; for(int i = 0; i < uvSetNames.GetCount(); ++i) { for(int j = 0; j < pMesh->GetPolygonCount(); ++j) { for(int k = 0; k < pMesh->GetPolygonSize(j); ++k) { FbxVector2 UV; pMesh->GetPolygonVertexUV(j, k, uvSetNames.GetStringAt(i), UV, unmapped); if(outVertexData.size() > UVCount) { outVertexData[UVCount].uv = DirectX::XMFLOAT2(UV.mData[0], UV.mData[1]); } UVCount++; } } } }
BabylonMesh::BabylonMesh(BabylonNode* node) : BabylonAbstractMesh(node), _isEnabled(true), _isVisible(true), _billboardMode(0), _visibility(1), _skeletonId(-1), _pickable(true), _hasVertexAlpha(false), _checkCollision(false), _receiveShadows(false), _infiniteDistance(false), _autoAnimate(false), _autoAnimateFrom(0), _autoAnimateTo(0), _autoAnimateLoop(false), _showBoundingBox(false), _showSubMeshesBoundingBox(false), _applyFog(false), _alphaIndex(0) { pivotMatrix.SetIdentity(); auto fbxNode = node->fbxNode(); std::string ansiName = fbxNode->GetName(); name(std::wstring(ansiName.begin(), ansiName.end())); id(getNodeId(fbxNode)); auto parent = fbxNode->GetParent(); if (parent) { parentId(getNodeId(parent)); } pivotMatrix = ConvertToBabylonCoordinateSystem( GetGeometryTransformation(fbxNode)); auto animStack = fbxNode->GetScene()->GetSrcObject<FbxAnimStack>(0); FbxString animStackName = animStack->GetName(); FbxTakeInfo* takeInfo = fbxNode->GetScene()->GetTakeInfo(animStackName); auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode; auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate(); auto startFrame = takeInfo->mLocalTimeSpan.GetStart().GetFrameCount(animTimeMode); auto endFrame = takeInfo->mLocalTimeSpan.GetStop().GetFrameCount(animTimeMode); auto animLengthInFrame = endFrame - startFrame + 1; _visibility = static_cast<float>(node->fbxNode()->Visibility.Get()); auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true); auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true); auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true); auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true); auto mesh = fbxNode->GetMesh(); _isVisible = fbxNode->Show.Get(); auto rotCurveNode = fbxNode->LclRotation.GetCurveNode(); auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode(); auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode(); auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode(); if (rotCurveNode || translateCurveNode || scalingCurveNode) { for (auto ix = 0; ix < animLengthInFrame; ix++) { FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); babylon_animation_key<babylon_vector3> poskey; babylon_animation_key<babylon_vector4> rotkey; babylon_animation_key<babylon_vector3> scalekey; poskey.frame = ix; rotkey.frame = ix; scalekey.frame = ix; auto currTransform = node->GetLocal(currTime); poskey.values = currTransform.translation(); rotkey.values = currTransform.rotationQuaternion(); scalekey.values = currTransform.scaling(); posAnim->appendKey(poskey); rotAnim->appendKey(rotkey); scaleAnim->appendKey(scalekey); } } if (visibilityCurveNode) { for (auto ix = 0; ix < animLengthInFrame; ix++) { FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); babylon_animation_key<float> visibilityKey; visibilityKey.frame = ix; visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime)); visibilityAnim->appendKey(visibilityKey); } } if (!posAnim->isConstant()){ animations.push_back(posAnim); } if (!rotAnim->isConstant()){ animations.push_back(rotAnim); } if (!scaleAnim->isConstant()){ animations.push_back(scaleAnim); } if (!visibilityAnim->isConstant()) { animations.push_back(visibilityAnim); } if (!mesh) { return; } if (mesh->GetPolygonCount() == 0){ return; } _receiveShadows = mesh->ReceiveShadow.Get(); FbxGeometryConverter conv(mesh->GetFbxManager()); conv.ComputePolygonSmoothingFromEdgeSmoothing(mesh); if (!mesh->IsTriangleMesh()) { mesh = (FbxMesh*) conv.Triangulate(mesh, true); } mesh->RemoveBadPolygons(); mesh->GenerateNormals(); FbxStringList uvSetNameList; mesh->GetUVSetNames(uvSetNameList); std::vector<std::string> uniqueUVSets; int uvCount = uvSetNameList.GetCount(); for (int i = 0; i < uvCount; ++i) { std::string value = uvSetNameList.GetStringAt(i); if (std::find(uniqueUVSets.begin(), uniqueUVSets.end(), value) == uniqueUVSets.end()) { uniqueUVSets.push_back(value); } } uvsets = uniqueUVSets; bool hasUv = uniqueUVSets.size() > 0; bool hasUv2 = uniqueUVSets.size() > 1; bool hasUv3 = uniqueUVSets.size() > 2; bool hasUv4 = uniqueUVSets.size() > 3; bool hasUv5 = uniqueUVSets.size() > 4; bool hasUv6 = uniqueUVSets.size() > 5; std::string uvSetName; std::string uv2SetName; std::string uv3SetName; std::string uv4SetName; std::string uv5SetName; std::string uv6SetName; if (hasUv) { uvSetName = uniqueUVSets[0]; } if (hasUv2) { uv2SetName = uniqueUVSets[1]; } if (hasUv3) { uv3SetName = uniqueUVSets[2]; } if (hasUv4) { uv4SetName = uniqueUVSets[3]; } if (hasUv5) { uv5SetName = uniqueUVSets[4]; } if (hasUv6) { uv6SetName = uniqueUVSets[5]; } auto colors = mesh->GetElementVertexColor(); FbxLayerElement::EMappingMode colorMappingMode; FbxLayerElement::EReferenceMode colorReferenceMode; if (colors) { colorMappingMode = colors->GetMappingMode(); colorReferenceMode = colors->GetReferenceMode(); } auto normals = mesh->GetElementNormal(); FbxGeometryElementUV* uvs = nullptr; FbxGeometryElementUV* uvs2 = nullptr; FbxGeometryElementUV* uvs3 = nullptr; FbxGeometryElementUV* uvs4 = nullptr; FbxGeometryElementUV* uvs5 = nullptr; FbxGeometryElementUV* uvs6 = nullptr; FbxLayerElement::EMappingMode uvsMappingMode; FbxLayerElement::EReferenceMode uvsReferenceMode; FbxLayerElement::EMappingMode uvs2MappingMode; FbxLayerElement::EReferenceMode uvs2ReferenceMode; FbxLayerElement::EMappingMode uvs3MappingMode; FbxLayerElement::EReferenceMode uvs3ReferenceMode; FbxLayerElement::EMappingMode uvs4MappingMode; FbxLayerElement::EReferenceMode uvs4ReferenceMode; FbxLayerElement::EMappingMode uvs5MappingMode; FbxLayerElement::EReferenceMode uvs5ReferenceMode; FbxLayerElement::EMappingMode uvs6MappingMode; FbxLayerElement::EReferenceMode uvs6ReferenceMode; if (hasUv) { uvs = mesh->GetElementUV(uvSetName.c_str()); uvsMappingMode = uvs->GetMappingMode(); uvsReferenceMode = uvs->GetReferenceMode(); } if (hasUv2) { uvs2 = mesh->GetElementUV(uv2SetName.c_str()); uvs2MappingMode = uvs2->GetMappingMode(); uvs2ReferenceMode = uvs2->GetReferenceMode(); } if (hasUv3) { uvs3 = mesh->GetElementUV(uv3SetName.c_str()); uvs3MappingMode = uvs3->GetMappingMode(); uvs3ReferenceMode = uvs3->GetReferenceMode(); } if (hasUv4) { uvs4 = mesh->GetElementUV(uv4SetName.c_str()); uvs4MappingMode = uvs4->GetMappingMode(); uvs4ReferenceMode = uvs4->GetReferenceMode(); } if (hasUv5) { uvs5 = mesh->GetElementUV(uv5SetName.c_str()); uvs5MappingMode = uvs5->GetMappingMode(); uvs5ReferenceMode = uvs5->GetReferenceMode(); } if (hasUv6) { uvs6 = mesh->GetElementUV(uv6SetName.c_str()); uvs6MappingMode = uvs6->GetMappingMode(); uvs6ReferenceMode = uvs6->GetReferenceMode(); } auto normalMappingMode = normals->GetMappingMode(); auto normalReferenceMode = normals->GetReferenceMode(); std::vector<SubmeshData> submeshes; auto materialCount = node->fbxNode()->GetMaterialCount(); if (materialCount == 0) { materialCount = 1; } submeshes.resize(materialCount); auto baseLayer = mesh->GetLayer(0); auto materials = baseLayer->GetMaterials(); FbxLayerElement::EMappingMode materialMappingMode = materials ? materials->GetMappingMode() : FbxLayerElement::eByPolygon; // extract deformers SkinInfo skinInfo(fbxNode); if (skinInfo.hasSkin()){ associatedSkeleton = std::make_shared<BabylonSkeleton>(); skinInfo.buildBabylonSkeleton(*associatedSkeleton); } auto triangleCount = mesh->GetPolygonCount(); for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) { int materialIndex = 0; if (materialCount > 0 && materials) { switch (materialMappingMode) { case FbxLayerElement::eAllSame: materialIndex = materials->GetIndexArray().GetAt(0); break; case FbxLayerElement::eByPolygon: materialIndex = materials->GetIndexArray().GetAt(triangleIndex); } } auto& submesh = submeshes[materialIndex]; triangle t; for (int cornerIndex = 0; cornerIndex < 3; ++cornerIndex) { auto controlPointIndex = mesh->GetPolygonVertex(triangleIndex, cornerIndex); auto vertexIndex = triangleIndex * 3 + cornerIndex; auto position = mesh->GetControlPoints()[controlPointIndex]; position[2] = -position[2]; BabylonVertex v; v.position = position; if (normals) { int normalMapIndex = (normalMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int normalValueIndex = (normalReferenceMode == FbxLayerElement::eDirect) ? normalMapIndex : normals->GetIndexArray().GetAt(normalMapIndex); v.normal = normals->GetDirectArray().GetAt(normalValueIndex); v.normal.z = -v.normal.z; } if (colors) { int mappingIndex = (colorMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (colorReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : colors->GetIndexArray().GetAt(mappingIndex); v.color = colors->GetDirectArray().GetAt(valueIndex); } if (uvs) { int mappingIndex = (uvsMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvsReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs->GetIndexArray().GetAt(mappingIndex); v.uv = uvs->GetDirectArray().GetAt(valueIndex); //v.uv.y = 1 - v.uv.y; } if (uvs2) { int mappingIndex = (uvs2MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs2ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs2->GetIndexArray().GetAt(mappingIndex); v.uv2 = uvs2->GetDirectArray().GetAt(valueIndex); } if (uvs3) { int mappingIndex = (uvs3MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs3ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs3->GetIndexArray().GetAt(mappingIndex); v.uv3 = uvs3->GetDirectArray().GetAt(valueIndex); } if (uvs4) { int mappingIndex = (uvs4MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs4ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs4->GetIndexArray().GetAt(mappingIndex); v.uv4 = uvs4->GetDirectArray().GetAt(valueIndex); } if (uvs5) { int mappingIndex = (uvs5MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs5ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs5->GetIndexArray().GetAt(mappingIndex); v.uv5 = uvs5->GetDirectArray().GetAt(valueIndex); } if (uvs6) { int mappingIndex = (uvs6MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs6ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs6->GetIndexArray().GetAt(mappingIndex); v.uv6 = uvs6->GetDirectArray().GetAt(valueIndex); } if (skinInfo.hasSkin()){ auto& skinData = skinInfo.controlPointBoneIndicesAndWeights(controlPointIndex); for (auto boneix = 0; boneix < skinData.size()&&boneix<4; ++boneix){ v.boneIndices[boneix] = skinData[boneix].index; v.boneWeights[boneix] = static_cast<float>(skinData[boneix].weight); } for (auto boneix = skinData.size(); boneix < 4; ++boneix){ v.boneIndices[boneix] = skinInfo.bonesCount(); v.boneWeights[boneix] = 0; } } auto foundVertex = submesh.knownVertices.find(v); if (foundVertex != submesh.knownVertices.end()) { //submesh.indices.push_back(foundVertex->second); t.indices[cornerIndex] = foundVertex->second; } else { auto index = static_cast<int>(submesh.vertices.size()); submesh.vertices.push_back(v); //submesh.indices.push_back(index); submesh.knownVertices[v] = index; t.indices[cornerIndex] = index; } } if (submesh.knownTriangles.insert(t).second) { submesh.indices.push_back(t.indices[0]); submesh.indices.push_back(t.indices[1]); submesh.indices.push_back(t.indices[2]); } else { std::cout << "duplicate triangle found (and eliminated) in " << fbxNode->GetName() << std::endl; } } std::uint32_t vertexOffset = 0; for (auto matIndex = 0u; matIndex < submeshes.size(); ++matIndex) { auto& submesh = submeshes[matIndex]; BabylonSubmesh babsubmesh; babsubmesh.indexCount = static_cast<int>(submesh.indices.size()); babsubmesh.indexStart = static_cast<int>(_indices.size()); babsubmesh.materialIndex = matIndex; babsubmesh.verticesCount = static_cast<int>(submesh.vertices.size()); babsubmesh.verticesStart = static_cast<int>(_positions.size()); for (auto& v : submesh.vertices) { _positions.push_back(v.position); if (normals) { _normals.push_back(v.normal); } if (colors) { _colors.push_back(v.color); } if (uvs) { _uvs.push_back(v.uv); } if (uvs2) { _uvs2.push_back(v.uv2); } if (uvs3) { _uvs3.push_back(v.uv3); } if (uvs4) { _uvs4.push_back(v.uv4); } if (uvs5) { _uvs5.push_back(v.uv5); } if (uvs6) { _uvs6.push_back(v.uv6); } if (skinInfo.hasSkin()){ float weight0 = v.boneWeights[0]; float weight1 = v.boneWeights[1]; float weight2 = v.boneWeights[2]; int bone0 = v.boneIndices[0]; int bone1 = v.boneIndices[1]; int bone2 = v.boneIndices[2]; int bone3 = v.boneIndices[3]; _boneWeights.push_back(babylon_vector4( weight0, weight1, weight2, 1.0f - weight0 - weight1 - weight2)); _boneIndices.push_back((bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0); } } for (auto i : submesh.indices) { _indices.push_back(i + vertexOffset); } vertexOffset = static_cast<int>(_positions.size()); _submeshes.push_back(babsubmesh); } }
void MeshImporter::LoadUV(FbxMesh* fbxMesh, Vertex* vertices, unsigned int* indices) { //get all UV set names FbxStringList UVSetNameList; fbxMesh->GetUVSetNames(UVSetNameList); //iterating over all uv sets for (int lUVSetIndex = 0; lUVSetIndex < UVSetNameList.GetCount(); lUVSetIndex++) { //get lUVSetIndex-th uv set const char* UVSetName = UVSetNameList.GetStringAt(lUVSetIndex); const FbxGeometryElementUV* UVElement = fbxMesh->GetElementUV(UVSetName); if (!UVElement) { continue; } // only support mapping mode eByPolygonVertex and eByControlPoint if (UVElement->GetMappingMode() != FbxGeometryElement::eByPolygonVertex && UVElement->GetMappingMode() != FbxGeometryElement::eByControlPoint) { return; } //index array, where holds the index referenced to the uv data const bool useIndex = UVElement->GetReferenceMode() != FbxGeometryElement::eDirect; const int indexCount = (useIndex) ? UVElement->GetIndexArray().GetCount() : 0; //iterating through the data by polygon const int polyCount = fbxMesh->GetPolygonCount(); if (UVElement->GetMappingMode() == FbxGeometryElement::eByControlPoint) { for (int polyIndex = 0; polyIndex < polyCount; ++polyIndex) { // build the max index array that we need to pass into MakePoly const unsigned int polySize = fbxMesh->GetPolygonSize(polyIndex); for (unsigned int vertIndex = 0; vertIndex < polySize; ++vertIndex) { FbxVector2 UVValue; // get the index of the current vertex in control points array int polyVertIndex = fbxMesh->GetPolygonVertex(polyIndex, vertIndex); // the UV index depends on the reference mode int UVIndex = useIndex ? UVElement->GetIndexArray().GetAt(polyVertIndex) : polyVertIndex; UVValue = UVElement->GetDirectArray().GetAt(UVIndex); // Copy texture coordinates // For indexed drawing //unsigned int vertexIndex = indices[polyVertIndex]; vertices[polyVertIndex].uv.x = (float)UVValue.mData[0]; vertices[polyVertIndex].uv.y = 1.0f - (float)UVValue.mData[1]; } } PrintTab("UV got eByControlPoint!!"); } else if (UVElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { int polyIndexCounter = 0; for (int polyIndex = 0; polyIndex < polyCount; ++polyIndex) { // build the max index array that we need to pass into MakePoly const int polySize = fbxMesh->GetPolygonSize(polyIndex); for (int vertIndex = 0; vertIndex < polySize; ++vertIndex) { if (polyIndexCounter < indexCount) { FbxVector2 UVValue; // the UV index depends on the reference mode int UVIndex = useIndex ? UVElement->GetIndexArray().GetAt(polyIndexCounter) : polyIndexCounter; UVValue = UVElement->GetDirectArray().GetAt(UVIndex); // Copy texture coordinates // For indexed drawing //unsigned int vertexIndex = indices[polyIndexCounter]; vertices[polyIndexCounter].uv.x = (float)UVValue.mData[0]; vertices[polyIndexCounter].uv.y = 1.0f - (float)UVValue.mData[1]; polyIndexCounter++; } } } PrintTab("UV got eByPolygonVertex!!"); } } }
Mesh* FBXSceneEncoder::loadMesh(FbxMesh* fbxMesh) { // Check if this mesh has already been loaded. Mesh* mesh = getMesh(fbxMesh->GetUniqueID()); if (mesh) { return mesh; } mesh = new Mesh(); // GamePlay requires that a mesh have a unique ID but FbxMesh doesn't have a string ID. const char* name = fbxMesh->GetNode()->GetName(); if (name) { string id(name); id.append("_Mesh"); mesh->setId(id); } // The number of mesh parts is equal to the number of materials that affect this mesh. // There is always at least one mesh part. vector<MeshPart*> meshParts; const int materialCount = fbxMesh->GetNode()->GetMaterialCount(); int meshPartSize = (materialCount > 0) ? materialCount : 1; for (int i = 0; i < meshPartSize; ++i) { meshParts.push_back(new MeshPart()); } // Find the blend weights and blend indices if this mesh is skinned. vector<vector<Vector2> > weights; bool hasSkin = loadBlendWeights(fbxMesh, weights); // Get list of uv sets for mesh FbxStringList uvSetNameList; fbxMesh->GetUVSetNames(uvSetNameList); const int uvSetCount = uvSetNameList.GetCount(); int vertexIndex = 0; FbxVector4* controlPoints = fbxMesh->GetControlPoints(); const int polygonCount = fbxMesh->GetPolygonCount(); for (int polyIndex = 0; polyIndex < polygonCount; ++polyIndex) { const int polygonSize = fbxMesh->GetPolygonSize(polyIndex); for (int posInPoly = 0; posInPoly < polygonSize; ++posInPoly) { int controlPointIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly); Vertex vertex; FbxVector4& position = controlPoints[controlPointIndex]; vertex.position.x = (float)position[0]; vertex.position.y = (float)position[1]; vertex.position.z = (float)position[2]; // Load tex coords for all uv sets for (int uvSetIndex = 0; uvSetIndex < uvSetCount; ++uvSetIndex) { const FbxGeometryElementUV* uvElement = fbxMesh->GetElementUV(uvSetNameList.GetStringAt(uvSetIndex)); if (uvElement) loadTextureCoords(fbxMesh, uvElement, uvSetIndex, polyIndex, posInPoly, vertexIndex, &vertex); } // Load other data loadNormal(fbxMesh, vertexIndex, controlPointIndex, &vertex); loadTangent(fbxMesh, vertexIndex, controlPointIndex, &vertex); loadBinormal(fbxMesh, vertexIndex, controlPointIndex, &vertex); loadVertexColor(fbxMesh, vertexIndex, controlPointIndex, &vertex); if (hasSkin) { loadBlendData(weights[controlPointIndex], &vertex); } // Determine which mesh part this vertex index should be added to based on the material that affects it. int meshPartIndex = 0; const int elementMatrialCount = fbxMesh->GetElementMaterialCount(); for (int k = 0; k < elementMatrialCount; ++k) { FbxGeometryElementMaterial* elementMaterial = fbxMesh->GetElementMaterial(k); meshPartIndex = elementMaterial->GetIndexArray().GetAt(polyIndex); } // Add the vertex to the mesh if it hasn't already been added and find the vertex index. unsigned int index; if (mesh->contains(vertex)) { index = mesh->getVertexIndex(vertex); } else { index = mesh->addVertex(vertex); } meshParts[meshPartIndex]->addIndex(index); vertexIndex++; } } const size_t meshpartsSize = meshParts.size(); for (size_t i = 0; i < meshpartsSize; ++i) { mesh->addMeshPart(meshParts[i]); } // The order that the vertex elements are add to the list matters. // It should be the same order as how the Vertex data is written. // Position mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT); const Vertex& vertex = mesh->vertices[0]; // Normals if (vertex.hasNormal) { mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT); } // Tangents if (vertex.hasTangent) { mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT); } // Binormals if (vertex.hasBinormal) { mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT); } // Texture Coordinates for (unsigned int i = 0; i < MAX_UV_SETS; ++i) { if (vertex.hasTexCoord[i]) { mesh->addVetexAttribute(TEXCOORD0 + i, Vertex::TEXCOORD_COUNT); } } // Diffuse Color if (vertex.hasDiffuse) { mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT); } // Skinning BlendWeights BlendIndices if (vertex.hasWeights) { mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT); mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT); } _gamePlayFile.addMesh(mesh); saveMesh(fbxMesh->GetUniqueID(), mesh); return mesh; }
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 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 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; }
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; } }