////////////////////////////////////////////////////////////////////////// // splitIntoBonePalettes std::vector< MdlMesh >& MdlMesh::splitIntoBonePalettes( BcU32 PaletteSize ) { // Empty current submeshes. SubMeshes_.clear(); // Build a triangle array. MdlTriangleArray Triangles; BcU32 NoofTriangles = aIndices_.size() / 3; Triangles.reserve( NoofTriangles ); for( BcU32 Idx = 0; Idx < NoofTriangles; ++Idx ) { BcU32 StartIndex = Idx * 3; MdlTriangle Triangle = { aVertices_[ aIndices_[ StartIndex + 0 ].iVertex_ ], aVertices_[ aIndices_[ StartIndex + 1 ].iVertex_ ], aVertices_[ aIndices_[ StartIndex + 2 ].iVertex_ ] }; Triangles.push_back( Triangle ); } while( Triangles.size() > 0 ) { MdlBonePalette NewBonePalette( PaletteSize ); MdlTriangleArray NewTriangles; NewTriangles.reserve( Triangles.size() ); // Iterate over triangles, and add them to the bone palette if possible. for( MdlTriangleArray::iterator It( Triangles.begin() ); It != Triangles.end(); ) { MdlTriangle& Triangle = (*It); // If we can add it, add it to the new triangles array + erase it. if( NewBonePalette.addTriangle( Triangle ) ) { NewTriangles.push_back( Triangle ); It = Triangles.erase( It ); } else { ++It; } } // Construct a new mesh for the triangles. MdlMesh NewMesh; NewMesh.bonePalette( NewBonePalette ); // Add materials. BcAssert( aMaterials_.size() == 1 ); for( BcU32 Idx = 0; Idx < aMaterials_.size(); ++Idx ) { NewMesh.addMaterial( aMaterials_[ Idx ] ); } // Add triangles. for( BcU32 Idx = 0; Idx < NewTriangles.size(); ++Idx ) { const MdlTriangle& Triangle( NewTriangles[ Idx ] ); for( BcU32 VertIdx = 0; VertIdx < 3; ++VertIdx ) { MdlIndex Index; Index.iVertex_ = NewMesh.addVertexShared( Triangle.Vertex_[ VertIdx ] ); Index.iMaterial_ = 0; NewMesh.addIndex( Index ); } } BcAssert( NewMesh.findBoneCount() <= PaletteSize ); SubMeshes_.push_back( NewMesh ); } return SubMeshes_; }
////////////////////////////////////////////////////////////////////////// // buildBindPose void MD5MeshLoader::buildBindPose( MdlNode* pNode, BcU32 iMesh ) { // Skin the mesh. MD5_Joint* pJoints = pJoint( 0 ); MD5_Mesh* pMeshes = pMesh( iMesh ); // This node is a mesh if we have 1 joint, skin if we have more. MdlMesh* pMesh = NULL; if( nJoints_ == 1 ) { pNode->type( eNT_MESH ); pMesh = pNode->pMeshObject(); } else { pNode->type( eNT_SKIN ); pMesh = pNode->pSkinObject(); } // Add material. MdlMaterial Material; Material.default3d(); Material.Name_ = pMeshes->Shader_; BcU32 iMaterial = pMesh->addMaterial( Material ); // Add indices. for( BcU32 i = 0; i < pMeshes->nIndices_; ++i ) { MdlIndex Index; Index.iMaterial_ = iMaterial; Index.iVertex_ = pMeshes->pIndices_[ i ]; pMesh->addIndex( Index ); } BcVec3d WeightPos; for ( BcU32 i = 0; i < pMeshes->nVerts_; ++i ) { MD5_Vert* pMD5Vert = &pMeshes->pVerts_[ i ]; BcVec3d Position( 0.0f, 0.0f, 0.0f ); // Setup vertex. MdlVertex Vert; Vert.bUV_ = BcTrue; Vert.UV_.x( pMD5Vert->U_ ); Vert.UV_.y( pMD5Vert->V_ ); for ( BcU32 j = 0; j < 4; ++j ) { Vert.Weights_[ j ] = 0.0f; Vert.iJoints_[ j ] = 0; } // Get bind pose vertex. Vert.nWeights_ = 0; for ( BcU32 j = 0; j < pMD5Vert->nWeights_; ++j ) { if ( j > 4 ) { break; } BcU32 WeightIndex = pMD5Vert->WeightIndex_ + j; MD5_Weight* pMD5Weight = &pMeshes->pWeights_[ WeightIndex ]; // Fix up a joint. MD5_Joint* pJoint = &pJoints[ pMD5Weight->JointID_ ]; BcVec3d JointTran( pJoint->TX_, pJoint->TY_, pJoint->TZ_ ); BcQuat JointRot( pJoint->QX_, pJoint->QY_, pJoint->QZ_, 0.0f ); JointRot.calcFromXYZ(); // const BcReal WeightVal = pMD5Weight->Weight_; WeightPos.set( pMD5Weight->X_, pMD5Weight->Y_, pMD5Weight->Z_ ); JointRot.rotateVector( WeightPos ); Position += ( WeightPos + JointTran ) * WeightVal; // Setup vertex indices and weights: Vert.iJoints_[ j ] = pMD5Weight->JointID_; Vert.Weights_[ j ] = WeightVal; Vert.nWeights_++; } // Correct weights. BcReal WeightTotal = 0.0f; for( BcU32 j = 0; j < Vert.nWeights_; ++j ) { WeightTotal += Vert.Weights_[ j ]; } for( BcU32 j = 0; j < Vert.nWeights_; ++j ) { Vert.Weights_[ j ] = Vert.Weights_[ j ] / WeightTotal; } Vert.bPosition_ = BcTrue; Vert.Position_ = Position; pMesh->addVertex( Vert ); } pMesh->sortIndicesByMaterial(); pMesh->buildNormals(); pMesh->buildTangents(); // Setup AABB to be larger than the skin to account for motion. BcAABB AABB = pMesh->findAABB(); AABB.min( AABB.min() * 1.5f ); AABB.max( AABB.max() * 1.5f ); pNode->aabb( AABB ); // TODO: Refine into bone palettes properly. }