std::shared_ptr<Mesh> FbxParser::CreateMesh(GameObjectPtr node, FbxNode * fbxNode) { Mesh::Ptr mesh = Mesh::Create(fbxNode->GetName()); FbxMesh* fbxMesh = static_cast<FbxMesh*>(fbxNode->GetNodeAttribute()); int polygonCount = fbxMesh->GetPolygonCount(); int indicesCount = polygonCount * 3; mesh->Positions.Data.reserve(indicesCount * 3); mesh->Indices.Data.reserve(indicesCount); mesh->Colors.Data.reserve(indicesCount * 3); for (int i = 0; i < polygonCount; ++i) { ASSERT(fbxMesh->GetPolygonSize(i) <= 3, "Error: triangulate %s", mesh->GetName()); for (int jj = 0; jj < 3; ++jj) { int ctrPointIdx = fbxMesh->GetPolygonVertex(i, jj); // TODO // Use Triangle Strip instead of triangle list auto position = fbxMesh->GetControlPointAt(ctrPointIdx); mesh->Positions.Data.push_back((double*)&position); int indices = i * 3 + jj; mesh->Indices.Data.push_back(indices); auto color = fbxMesh->GetElementVertexColor(ctrPointIdx); mesh->Colors.Data.push_back((double*)&color); } } mesh->UpdateBuffer(); return mesh; }
reMesh* reFBXAsset::importMesh(FbxNode* fbxNode) { qDebug() << "import mesh for" << fbxNode->GetName(); reMesh* mesh = new reMesh; FbxMesh* fmesh = (FbxMesh*) fbxNode->GetNodeAttribute(); FbxVector4* controlPoints = fmesh->GetControlPoints(); for (int i=0; i<fmesh->GetPolygonCount(); i++) { reFace* face = new reFace; for (int j=0; j<fmesh->GetPolygonSize(i); j++) { int vi = fmesh->GetPolygonVertex(i, j); reVertex vertex; vertex.pos = reVec3(controlPoints[vi][0], controlPoints[vi][1], controlPoints[vi][2]); FbxVector4 fNormal; fmesh->GetPolygonVertexNormal(i, j, fNormal); vertex.uv = getUV(fmesh, vi, i, j); vertex.normal = reVec3(fNormal[0], fNormal[1], fNormal[2]); face->vertices.push_back(vertex); } reMaterial* mat = getMaterial(fmesh, i, mesh->materialSet); mesh->addFace(face,mat ? mat->id: -1); } reMeshAsset* meshAsset = new reMeshAsset(meshes); meshAsset->mesh = mesh; meshes->children.push_back(meshAsset); meshAsset->setPath((dataDir().toStdString() + "/" + fbxNode->GetName() + ".mesh").c_str()); mesh->save(dataDir().toStdString() + "/" + fbxNode->GetName() + ".mesh"); return mesh; }
MeshData* FBXImporter::GetMeshInfo() { mMeshData = new MeshData(); int indicesIndexOffset = 0; // 记录当前mesh在整个ib中的索引位移。 int verticesIndexOffset = 0; // 记录当前mesh在整个vb中的顶点位移。 for (int meshIndex = 0; meshIndex < mFBXMeshDatas.size(); meshIndex++) { FbxMesh* mesh = mFBXMeshDatas[meshIndex]->mMesh; FBXMeshData* fbxMeshData = mFBXMeshDatas[meshIndex]; fbxMeshData->mVerticesCount = mesh->GetControlPointsCount(); fbxMeshData->mIndicesCount = mesh->GetPolygonVertexCount(); fbxMeshData->mTrianglesCount = mesh->GetPolygonCount(); // 获取3dsmax中的全局变换矩阵,稍后可以在DX中还原。 FbxMatrix gloableTransform = mesh->GetNode()->EvaluateGlobalTransform(); FbxAMatrix matrixGeo; matrixGeo.SetIdentity(); const FbxVector4 lT = mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot); const FbxVector4 lR = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot); const FbxVector4 lS = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot); matrixGeo.SetT(lT); matrixGeo.SetR(lR); matrixGeo.SetS(lS); FbxAMatrix matrixL2W; matrixL2W.SetIdentity(); matrixL2W = mesh->GetNode()->EvaluateGlobalTransform(); matrixL2W *= matrixGeo; XMMATRIX globalTransform = XMLoadFloat4x4(&fbxMeshData->globalTransform); FbxMatrixToXMMATRIX(globalTransform, matrixL2W); XMStoreFloat4x4(&fbxMeshData->globalTransform, globalTransform); // 读取顶点。 ReadVertices(fbxMeshData); // 读取索引。 ReadIndices(fbxMeshData); // 先读取网格对应的材质索引信息,以便优化稍后纹理读取。 // 一个网格可能只对应一个materialId,也可能对应多个materialId(3dsmax里的Multi/Sub-Object材质)。 // 如果只对应一个材质,简单的读取就行,不过普遍情况可能是为了优化渲染合并mesh从而拥有多材质。 // 这个函数调用完毕我们会得到materialId和拥有这个materialId的三角形列表(三角形编号列表),保存在vector<MaterialIdOffset>的容器中。 //struct Material //{ // Material() {} // Material(int id, string diffuse, string normalMap) // : materialId(id), // diffuseTextureFile(diffuse), // normalMapTextureFile(normalMap) // {} // // int materialId; // string diffuseTextureFile; // string normalMapTextureFile; //}; // struct MaterialIdOffset //{ // MaterialIdOffset() // : polygonCount(0) // {} // int polygonCount; // Material material; //}; ConnectMaterialsToMesh(mesh, fbxMeshData->mTrianglesCount); // 根据ConnectMaterialsToMesh得到的信息读取材质纹理信息,同样存入vector<MaterialIdOffset>容器。 LoadMaterials(fbxMeshData); int triangleCount = mesh->GetPolygonCount(); int controlPointIndex = 0; int normalIndex = 0; fbxMeshData->mUVs.resize(fbxMeshData->mIndicesCount, XMFLOAT2(-1.0f, -1.0f)); // Extract normals and uvs from FbxMesh. for (int i = 0; i < triangleCount; i++) { int polygonSize = mesh->GetPolygonSize(i); for (int j = 0; j < polygonSize; j++) { controlPointIndex = mesh->GetPolygonVertex(i, j); ReadNormals(fbxMeshData, controlPointIndex, normalIndex); // 有纹理我们才读取uv,tangent以及binormal。 if (fbxMeshData->hasDiffuseTexture()) { ReadUVs(fbxMeshData, controlPointIndex, normalIndex, mesh->GetTextureUVIndex(i, j), 0); ReadTangents(fbxMeshData, controlPointIndex, normalIndex); ReadBinormals(fbxMeshData, controlPointIndex, normalIndex); } normalIndex++; } } SplitVertexByNormal(fbxMeshData); if (fbxMeshData->hasDiffuseTexture()) { SplitVertexByUV(fbxMeshData); } else { fbxMeshData->mUVs.resize(fbxMeshData->mVerticesCount); } if (fbxMeshData->hasNormalMapTexture()) { SplitVertexByTangent(fbxMeshData); SplitVertexByBinormal(fbxMeshData); } else { fbxMeshData->mTangents.resize(fbxMeshData->mVerticesCount); fbxMeshData->mBinormals.resize(fbxMeshData->mVerticesCount); } // 如果.fbx包含一个以上的mesh,需要计算当前FBXMeshData的索引在全局索引中的位置。 for (int i = 0; i < fbxMeshData->mIndicesCount; i++) { fbxMeshData->mIndices[i] = fbxMeshData->mIndices[i] + verticesIndexOffset; } mMeshData->verticesCount += fbxMeshData->mVerticesCount; mMeshData->indicesCount += fbxMeshData->mIndicesCount; mMeshData->meshesCount++; // 多材质的情况。 // 根据之前填充的materialIdOffsets容器保存的materialId和三角形的对应关系, // 计算每个RenderPackage渲染所需的索引数量和索引起始位置(偏移)。 if (isByPolygon && fbxMeshData->hasDiffuseTexture()) { vector<MaterialIdOffset> materialIdOffsets = mMeshData->materialIdOffsets; for (int i = 0; i < materialIdOffsets.size(); i++) { RenderPackage renderPacakge; renderPacakge.globalTransform = fbxMeshData->globalTransform; renderPacakge.indicesCount = materialIdOffsets[i].polygonCount * 3; if (i == 0) { renderPacakge.indicesOffset = indicesIndexOffset; } else { renderPacakge.indicesOffset += indicesIndexOffset; } renderPacakge.material = materialIdOffsets[i].material; mMeshData->renderPackages.push_back(renderPacakge); indicesIndexOffset += renderPacakge.indicesCount; } } else // 单一材质的情况。 { RenderPackage renderPackage; renderPackage.indicesCount = fbxMeshData->mIndicesCount; renderPackage.indicesOffset = indicesIndexOffset; renderPackage.material = fbxMeshData->mMaterial; renderPackage.globalTransform = fbxMeshData->globalTransform; mMeshData->renderPackages.push_back(renderPackage); indicesIndexOffset += fbxMeshData->mIndices.size(); } verticesIndexOffset += fbxMeshData->mVertices.size(); // 将当前mesh的数据追加到全局数据容器。 Merge(mMeshData->vertices, fbxMeshData->mVertices); Merge(mMeshData->indices, fbxMeshData->mIndices); Merge(mMeshData->normals, fbxMeshData->mNormals); Merge(mMeshData->uvs, fbxMeshData->mUVs); Merge(mMeshData->tangents, fbxMeshData->mTangents); Merge(mMeshData->binormals, fbxMeshData->mBinormals); mMeshData->materialIdOffsets.clear(); } clear(); return mMeshData; }
HRESULT CStaticMesh::Load_StaticMesh(const char* szFilePath,const char* szFileName, FbxManager* _pFBXManager, FbxIOSettings* _pIOsettings, FbxScene* _pFBXScene, FbxImporter* _pImporter) { HRESULT hr = E_FAIL; vector<UINT> vecIndeces; string strFullPath; strFullPath.clear(); strFullPath = szFilePath; strFullPath += szFileName;//경로에 파일이름 추가 if (!(_pImporter->Initialize(strFullPath.c_str(), -1, _pFBXManager->GetIOSettings()))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Init Failed"); if (!(_pImporter->Import(_pFBXScene))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Import Failed"); FbxGeometryConverter clsConverter(_pFBXManager); clsConverter.Triangulate(_pFBXScene, false); FbxNode* pRootNode = _pFBXScene->GetRootNode(); if (!pRootNode) return E_FAIL; vector<VTXTEX> vecVTXTEX; for (int i = 0; i < pRootNode->GetChildCount(); ++i) { FbxNode* pChildNode = pRootNode->GetChild(i); if (pChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pChildNode->GetNodeAttribute(); // 임폴트 하려는 메쉬의 데이터 D3DXVECTOR3 vPos; D3DXVECTOR2 vOutUV; D3DXVECTOR3 vOutNormal; FbxVector4* mControlPoints = pMesh->GetControlPoints(); int iVTXCounter = 0; for (int j = 0; j < pMesh->GetPolygonCount(); j++) // 폴리곤의 인덱스 { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); FbxGeometryElementUV* VtxUV = pMesh->GetElementUV(0); FbxGeometryElementNormal* VtxNormal = pMesh->GetElementNormal(0); for (int k = 0; k < iNumVertices; k++) // 폴리곤을 구성하는 버텍스의 인덱스 { //정점 데이터 얻는곳 int iControlPointIndex = pMesh->GetPolygonVertex(j, k); // 컨트롤 포인트 = 하나의 버텍스 int iTextureUVIndex = pMesh->GetTextureUVIndex(j, k); // Control = Vertex //int iNormalIndex = pMesh->GetPolygonVertexIndex(j, k); ++iVTXCounter; vPos.x = (float)mControlPoints[iControlPointIndex].mData[0]; vPos.y = -(float)mControlPoints[iControlPointIndex].mData[1]; vPos.z = (float)mControlPoints[iControlPointIndex].mData[2]; //uv 얻기 switch (VtxUV->GetMappingMode()) // UV값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxUV->GetIndexArray().GetAt(iControlPointIndex); vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } case FbxGeometryElement::eIndexToDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } //노멀얻기 switch (VtxNormal->GetMappingMode()) // 노멀값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[2]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iControlPointIndex); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } VTXTEX vtxtex; vtxtex.vPos = vPos; vtxtex.vNormal = vOutNormal; vtxtex.vTexUV = vOutUV; vecVTXTEX.push_back(vtxtex); //int index = VtxUV->GetIndexArray().GetAt(iTextureUVIndex); vecIndeces.push_back(VtxUV->GetIndexArray().GetAt(iTextureUVIndex)); } } } unsigned int n = vecVTXTEX.size(); VTXTEX* pVTXTex = new VTXTEX[n]; for (unsigned int i = 0; i < vecVTXTEX.size(); ++i) { pVTXTex[i].vPos = vecVTXTEX[i].vPos; pVTXTex[i].vNormal = vecVTXTEX[i].vNormal; pVTXTex[i].vTexUV = vecVTXTEX[i].vTexUV; } m_iVertices = vecVTXTEX.size(); m_iVertexStrides = sizeof(VTXTEX); m_iVertexOffsets = 0; MakeVertexNormal((BYTE*)pVTXTex, NULL); D3D11_BUFFER_DESC tBufferDesc; ZeroMemory(&tBufferDesc, sizeof(D3D11_BUFFER_DESC)); tBufferDesc.Usage = D3D11_USAGE_DEFAULT; tBufferDesc.ByteWidth = m_iVertexStrides * m_iVertices; tBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; tBufferDesc.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA tData; ZeroMemory(&tData, sizeof(D3D11_SUBRESOURCE_DATA)); tData.pSysMem = pVTXTex; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&tBufferDesc, &tData, &m_VertexBuffer); ::Safe_Delete(pVTXTex); if (FAILED(hr)) return E_FAIL; D3D11_BUFFER_DESC cbd; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.ByteWidth = sizeof(ConstantBuffer); cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.CPUAccessFlags = 0; cbd.MiscFlags = 0; cbd.StructureByteStride = 0; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&cbd, NULL, &m_ConstantBuffer); if (FAILED(hr)) { MessageBox(NULL, L"System Message", L"Constant Buffer Error", MB_OK); return hr; } return S_OK; }
HRESULT FBXLoader::loadFBXFile(char* filePath, VertexBuffer** vBuf, IndexBuffer** iBuf, Renderer* renderer, bool centerShift) { if (g_pFbxSdkManager == nullptr) { g_pFbxSdkManager = FbxManager::Create(); FbxIOSettings* pIOsettings = FbxIOSettings::Create(g_pFbxSdkManager, IOSROOT); g_pFbxSdkManager->SetIOSettings(pIOsettings); } this->shiftCenter = centerShift; FbxImporter* pImporter = FbxImporter::Create(g_pFbxSdkManager, ""); FbxScene* pFbxScene = FbxScene::Create(g_pFbxSdkManager, ""); bool bSuccess = pImporter->Initialize(filePath, -1, g_pFbxSdkManager->GetIOSettings()); if (!bSuccess) return E_FAIL; bSuccess = pImporter->Import(pFbxScene); if (!bSuccess) return E_FAIL; FbxAxisSystem sceneAxisSystem = pFbxScene->GetGlobalSettings().GetAxisSystem(); FbxAxisSystem DirectXAxisSystem(FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eLeftHanded); if (sceneAxisSystem != DirectXAxisSystem) { DirectXAxisSystem.ConvertScene(pFbxScene); } pImporter->Destroy(); FbxNode* pFbxRootNode = pFbxScene->GetRootNode(); if (pFbxRootNode) { // Check if the getChildCount is > 1 TODO int test = pFbxRootNode->GetChildCount(); for (int i = 0; i < pFbxRootNode->GetChildCount(); i++) { FbxNode* pFbxChildNode = pFbxRootNode->GetChild(i); if (pFbxChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pFbxChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pFbxChildNode->GetNodeAttribute(); int numControlPoints = pMesh->GetControlPointsCount(); bool initial = true; float xMin, yMin, zMin; float xMax, yMax, zMax; float xIn, yIn, zIn; float xCenter, yCenter, zCenter; if (this->shiftCenter){ for (int c = 0; c < numControlPoints; c++) { xIn = (float)pMesh->GetControlPointAt(c).mData[0]; yIn = (float)pMesh->GetControlPointAt(c).mData[1]; zIn = (float)pMesh->GetControlPointAt(c).mData[2]; if (initial) { xMin = xIn; yMin = yIn; zMin = zIn; xMax = xIn; yMax = yIn; zMax = zIn; initial = false; } else { if (xIn < xMin) { xMin = xIn; } if (yIn < yMin) { yMin = yIn; } if (zIn < zMin) { zMin = zIn; } if (xIn > xMax) { xMax = xIn; } if (yIn > yMax) { yMax = yIn; } if (zIn > zMax) { zMax = zIn; } } } xCenter = (xMin + xMax) / 2.0f; yCenter = (yMin + yMax) / 2.0f; zCenter = (zMin + zMax) / 2.0f; } else { xCenter = 0; yCenter = 0; zCenter = 0; } FbxVector4* pVertices = pMesh->GetControlPoints(); int vertexCount = pMesh->GetPolygonVertexCount(); //Vertex vertex; Vertex* vertexArray = new Vertex[vertexCount]; //Vertex vertexArray[2592]; int numIndices = vertexCount; unsigned int* indexArray = new unsigned int[numIndices]; FbxVector4 fbxNorm(0, 0, 0, 0); FbxVector2 fbxUV(0, 0); bool isMapped; int vertexIndex = 0; // Loop iterates through the polygons and fills the vertex and index arrays for the buffers for (int j = 0; j < pMesh->GetPolygonCount(); j++) { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); //1st vertex int controlIndex = pMesh->GetPolygonVertex(j, 2); pMesh->GetPolygonVertexUV(j, 2, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 2, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //2nd vertex controlIndex = pMesh->GetPolygonVertex(j, 1); pMesh->GetPolygonVertexUV(j, 1, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 1, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; //3rd vertex controlIndex = pMesh->GetPolygonVertex(j, 0); pMesh->GetPolygonVertexUV(j, 0, "map1", fbxUV, isMapped); pMesh->GetPolygonVertexNormal(j, 0, fbxNorm); vertexArray[vertexIndex].point[0] = (float)pVertices[controlIndex].mData[0] - xCenter; vertexArray[vertexIndex].point[1] = (float)pVertices[controlIndex].mData[1] - yCenter; vertexArray[vertexIndex].point[2] = -(float)pVertices[controlIndex].mData[2] - zCenter; vertexArray[vertexIndex].texCoord[0] = (float)fbxUV[0]; vertexArray[vertexIndex].texCoord[1] = 1.0f - (float)fbxUV[1]; vertexArray[vertexIndex].normal[0] = (float)fbxNorm[0]; vertexArray[vertexIndex].normal[1] = (float)fbxNorm[1]; vertexArray[vertexIndex].normal[2] = -(float)fbxNorm[2]; indexArray[vertexIndex] = vertexIndex; vertexIndex++; } // Generate vertex and index buffers from the vertex and index arrays *vBuf = renderer->createVertexBuffer(vertexArray, vertexCount); *iBuf = renderer->createIndexBuffer(indexArray, numIndices); delete[] vertexArray; delete[] indexArray; } } return S_OK; }
void 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(); }
//=============================================================================================================================== void FBXLoader::LoadMesh(FbxNode* node) { FBXSubsets* newSubset = new FBXSubsets(); FbxMesh* mesh = node->GetMesh(); newSubset->mPolygonCount = mesh->GetPolygonCount(); int vertexCounter = 0; // http://stackoverflow.com/questions/30170521/how-to-read-in-fbx-2014-indices-properly-for-directx /*newSubset->mTriangles.reserve(newSubset->mPolygonCount); for (uint32 i = 0; i < newSubset->mPolygonCount; ++i) { XMFLOAT3 normal[3]; XMFLOAT3 tangent[3]; XMFLOAT3 binormal[3]; XMFLOAT2 uv[3][2]; ZShadeSandboxMesh::FBXTriangle triangle; newSubset->mTriangles.push_back(triangle); for (uint32 j = 0; j < 3; ++j) { int controlPointIndex = mesh->GetPolygonVertex(i, j); ZShadeSandboxMesh::PhysicalPoint* ctlPoint = mControlPoints[controlPointIndex]; LoadVertexNormal(mesh, controlPointIndex, vertexCounter, 0, normal[j]); // Only have diffuse texture for (int k = 0; k < 1; ++k) { LoadVertexTexture(mesh, controlPointIndex, mesh->GetTextureUVIndex(i, j), k, uv[j][k]); } //LoadVertexTangent(mesh, controlPointIndex, vertexCounter, 0, tangent[j]); ZShadeSandboxMesh::VertexNormalTexBlend temp; temp.position = ctlPoint->position; temp.normal = normal[j]; //temp.tangent = tangent[j]; temp.texture = uv[j][0]; // Copy the blending from each control point for (uint32 i = 0; i < ctlPoint->blendingInfo.size(); ++i) { ZShadeSandboxMesh::VertexBlendingInfo blendingInfo; blendingInfo.blendingIndex = ctlPoint->blendingInfo[i].blendingIndex; blendingInfo.blendingWeight = ctlPoint->blendingInfo[i].blendingWeight; temp.vertexBlendingInfos.push_back(blendingInfo); } // Sort blending info to remove duplicate vertices temp.SortBlendingInfoByWeight(); newSubset->mVertices.push_back(temp); newSubset->mTriangles.back().indices.push_back(vertexCounter); ++vertexCounter; } }*/ /*int* indices = mesh->GetPolygonVertices(); for (int ind = 0; ind < mesh->GetPolygonVertexCount(); ind++) { newSubset->mIndices.push_back(indices[ind]); string indice = ZShadeSandboxGlobal::Convert::ConvertToString<int>(indices[ind]); outIndiceFile << "indice: " << indice << "\n"; }*/ for (uint32 polygonID = 0; polygonID < newSubset->mPolygonCount; ++polygonID) { int polyVertCount = mesh->GetPolygonSize(polygonID); for (uint32 polygonVertexID = 0; polygonVertexID < polyVertCount; ++polygonVertexID) { ZShadeSandboxMesh::VertexNormalTexBlend temp; // Initialize the vertex data temp.position = XMFLOAT3(0, 0, 0); temp.normal = XMFLOAT3(0, 0, 0); temp.texture = XMFLOAT2(0, 0); temp.tangent = XMFLOAT3(0, 0, 0); int controlPointIndex = mesh->GetPolygonVertex(polygonID, polygonVertexID); ZShadeSandboxMesh::PhysicalPoint* ctlPoint = mControlPoints[controlPointIndex]; // // Load vertex position // temp.position = ctlPoint->position; // // Load vertex normal // int normElementCount = mesh->GetElementNormalCount(); for (int normElement = 0; normElement < normElementCount; normElement++) { XMFLOAT3 normal; if (LoadVertexNormal(mesh, controlPointIndex, vertexCounter, normElement, normal)) { temp.normal = normal; break; } } // // Load vertex UV // int uvElementCount = mesh->GetElementUVCount(); for (int uvElement = 0; uvElement < uvElementCount; uvElement++) { XMFLOAT2 uv; if (LoadVertexTexture(mesh, controlPointIndex, mesh->GetTextureUVIndex(polygonID, polygonVertexID), uvElement, uv)) { temp.texture = uv; break; } } // // Load vertex tangent // int tangentElementCount = mesh->GetElementTangentCount(); for (int tangentElement = 0; tangentElement < tangentElementCount; tangentElement++) { XMFLOAT3 tangent; if (LoadVertexTangent(mesh, controlPointIndex, vertexCounter, tangentElement, tangent)) { temp.tangent = tangent; break; } } // // Load vertex blending information for skinning // // Copy the blending from each control point for (uint32 i = 0; i < ctlPoint->blendingInfo.size(); ++i) { ZShadeSandboxMesh::VertexBlendingInfo blendingInfo; blendingInfo.blendingIndex = ctlPoint->blendingInfo[i].blendingIndex; blendingInfo.blendingWeight = ctlPoint->blendingInfo[i].blendingWeight; temp.vertexBlendingInfos.push_back(blendingInfo); } // Sort blending info to remove duplicate vertices temp.SortBlendingInfoByWeight(); // // Make sure the vertices are unique and get the index // vector<ZShadeSandboxMesh::VertexNormalTexBlend>& uniqueVerts = newSubset->mVertices; size_t size = uniqueVerts.size(); uint32 indice; for (indice = 0; indice < size; indice++) { if (temp.EqualsPosNormTex(uniqueVerts[indice])) { break; } } if (indice == size) { uniqueVerts.push_back(temp); string pos = ZShadeSandboxGlobal::Convert::ConvertFloat3ToString(temp.position); outVertexFile << "vertex: " << pos << "\n"; } newSubset->mIndices.push_back(indice); string indice_str = ZShadeSandboxGlobal::Convert::ConvertToString<uint32>(indice); outIndiceFile << "indice: " << indice_str << "\n"; ++vertexCounter; } } // Now mControlPoints has served its purpose so we can free its memory for(auto itr = mControlPoints.begin(); itr != mControlPoints.end(); ++itr) { delete itr->second; } mControlPoints.clear(); // Adding a new subset to the mesh mSubsets.push_back(newSubset); }
FBXLoader::FBXLoader(const char *filename) { m_error = true; if (m_fbx_sdk_manager == nullptr) { m_fbx_sdk_manager = FbxManager::Create(); m_fbx_sdk_manager->SetIOSettings(FbxIOSettings::Create(m_fbx_sdk_manager, IOSROOT)); } FbxImporter *importer = FbxImporter::Create(m_fbx_sdk_manager, ""); FbxScene *scene = FbxScene::Create(m_fbx_sdk_manager, ""); if (!importer->Initialize(filename, -1, m_fbx_sdk_manager->GetIOSettings())) return; if (!importer->Import(scene)) return; importer->Destroy(); FbxNode *root_node = scene->GetRootNode(); if (root_node) { for (int i = 0; i < root_node->GetChildCount(); i++) { FbxNode *child_node = root_node->GetChild(i); if (child_node->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType type = child_node->GetNodeAttribute()->GetAttributeType(); if (type != FbxNodeAttribute::eMesh) continue; FbxMesh *mesh = (FbxMesh *) child_node->GetNodeAttribute(); FbxVector4 *vertices = mesh->GetControlPoints(); for (int j = 0; j < mesh->GetPolygonCount(); j++) { int num_verts = mesh->GetPolygonSize(j); assert(num_verts == 3); DirectX::XMFLOAT3 vertex[3]; FbxVector4 polygon_normal(0, 0, 0); for (int k = 0; k < num_verts; k++) { int control_point_idx = mesh->GetPolygonVertex(j, k); FbxVector4 vertex_normal; mesh->GetPolygonVertexNormal(j, k, vertex_normal); polygon_normal += vertex_normal; vertex[k].x = (float) vertices[control_point_idx].mData[0]; vertex[k].y = (float) vertices[control_point_idx].mData[1]; vertex[k].z = (float) vertices[control_point_idx].mData[2]; } if (IsClockwise(vertex, num_verts, polygon_normal)) { for (int i = 0; i < num_verts; i++) m_vertices.push_back(ToD3DCoordinateSystem(vertex[i])); } else { for (int i = 0; i < num_verts; i++) m_vertices.push_back(ToD3DCoordinateSystem(vertex[num_verts - 1 - i])); } } } } for (size_t i = 0; i < m_vertices.size(); i++) m_indices.push_back(i); m_error = false; }
void importFBXNode( FbxNode *node, vector<Vector3> &vertices, vector<Color> &colors, vector<Vector2> &uvs, vector<Vector3> &normals, vector<uint32> &elements) { FbxNode *childNode = 0; int numKids = node->GetChildCount(); for ( int i=0 ; i<numKids ; i++) { childNode = node->GetChild(i); FbxMesh *mesh = childNode->GetMesh(); if ( mesh != NULL ) { auto offset = node->GetGeometricTranslation(FbxNode::eSourcePivot); //================= Get Vertices ==================================== int baseline = vertices.size(); int numVerts = mesh->GetControlPointsCount(); for ( int j=0; j<numVerts; j++) { FbxVector4 vert = mesh->GetControlPointAt(j); vertices.push_back( Vector3(vert.mData[0], vert.mData[1], vert.mData[2]) /*+ Vector3(offset.mData[0], offset.mData[1], offset.mData[2])*/); colors.push_back(Vector3(1, 1, 1)); uvs.push_back(Vector2(0, 0)); } //================= Get Indices ==================================== int numIndices=mesh->GetPolygonVertexCount(); int *indicesRaw = mesh->GetPolygonVertices(); for (int j = 0; j < numIndices; j++) { elements.push_back(indicesRaw[j] + baseline); } int cnt = 0; int polygonCount = mesh->GetPolygonCount(); for (int j = 0; j < polygonCount; ++j) { FbxLayerElementArrayTemplate<FbxVector2>* uvVertices= 0; mesh->GetTextureUV(&uvVertices, FbxLayerElement::eTextureDiffuse); for (int k = 0; k < mesh->GetPolygonSize(j); ++k) { FbxVector2 uv = (*uvVertices)[mesh->GetTextureUVIndex(j, k)]; uvs[indicesRaw[cnt] + baseline].x = uv[0]; uvs[indicesRaw[cnt] + baseline].y = uv[1]; cnt++; } } } importFBXNode(childNode, vertices, colors, uvs, normals, elements); } }
//-------------------------------------------------------------------------- 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); }