//----------------------------------------------------------------------------- BOOL CExporter::Capture() { VERIFY (m_Style!=eExportUndef); Modifier* pPhysique; IPhysiqueExport* pExport; IPhyContextExport* pContext; Object* pObject; Matrix3 matMesh; Matrix3 matZero; if (!m_MeshNode){ ERR("Select mesh and try again."); m_bHasError=TRUE; return FALSE; } pObject = m_MeshNode->GetObjectRef(); if (!IsExportableMesh(m_MeshNode,pObject)){ ERR("Can't receive node references."); m_bHasError=TRUE; return FALSE; } // Get export interface pPhysique = FindPhysiqueModifier(m_MeshNode); if (!pPhysique){ ERR("Can't find Physique modifier."); m_bHasError=TRUE; return FALSE; } pExport = (IPhysiqueExport *)pPhysique->GetInterface(I_PHYINTERFACE); if (!pExport){ ERR("Can't find Physique interface."); m_bHasError=TRUE; return FALSE; } // Get mesh initial transform (used to mult by the bone matrices) int rval = CGINTM(m_MeshNode,pExport->GetInitNodeTM(m_MeshNode, matMesh)); matZero.Zero(); if (rval || matMesh.Equals(matZero, 0.0)){ ERR("Old CS version. Can't export mesh"); matMesh.IdentityMatrix(); } // Add hierrarhy parts that has no effect on vertices, // but required for hierrarhy stability if (eExportMotion==m_Style){ if (m_AllBones.empty()){ ERR("Invalid skin object. Bone not found."); return FALSE; } EConsole.ProgressStart((float)m_AllBones.size(),"..Capturing bones"); for (DWORD i=0; i<m_AllBones.size(); i++){ AddBone(m_AllBones[i], matMesh, pExport); EConsole.ProgressInc(); } EConsole.ProgressEnd(); } bool bRes = TRUE; if (eExportSkin==m_Style){ // For a given Object's INode get a // ModContext Interface from the Physique Export Interface: pContext = (IPhyContextExport *)pExport->GetContextInterface(m_MeshNode); if (!pContext){ ERR("Can't find Physique context interface."); return FALSE; } // convert to rigid with blending pContext->ConvertToRigid(TRUE); pContext->AllowBlending (TRUE); // process vertices int numVertices = pContext->GetNumberVertices(); EConsole.ProgressStart(float(numVertices),"..Capturing vertices"); for (int iVertex = 0; iVertex < numVertices; iVertex++ ){ IPhyVertexExport *pVertexExport = (IPhyVertexExport *)pContext->GetVertexInterface(iVertex); R_ASSERT(pVertexExport); // What kind of vertices are these? int iVertexType = pVertexExport->GetVertexType(); IPhyRigidVertex* pRigidVertex=(IPhyRigidVertex*)pContext->GetVertexInterface(iVertex); R_ASSERT (pRigidVertex); switch (iVertexType){ case RIGID_TYPE:{ INode* node = pRigidVertex->GetNode(); R_ASSERT (node); LPCSTR nm = node->GetName(); // get bone and create vertex CVertexDef* pVertex = AddVertex(); int boneId = AddBone(node,matMesh,pExport); if(BONE_NONE==boneId){ ERR ("Invalid bone: ",node->GetName()); bRes = FALSE; }else pVertex->Append (boneId,1.f); }break; case RIGID_BLENDED_TYPE:{ IPhyBlendedRigidVertex* pBlendedRigidVertex=(IPhyBlendedRigidVertex*)pRigidVertex; int cnt = pBlendedRigidVertex->GetNumberNodes(); CVertexDef* pVertex = AddVertex(); for (int i=0; i<cnt; i++){ INode* node = pBlendedRigidVertex->GetNode(i); R_ASSERT (node); LPCSTR nm = node->GetName(); // get bone and create vertex int boneId = AddBone(node,matMesh,pExport); if(BONE_NONE==boneId){ ERR ("Invalid bone: ",node->GetName()); bRes = FALSE; }else pVertex->Append(boneId,pBlendedRigidVertex->GetWeight(i)); } }break; } // release vertex pContext->ReleaseVertexInterface( pRigidVertex ); EConsole.ProgressInc(); if (!bRes) break; } EConsole.ProgressEnd(); if (!bRes) return FALSE; static int remap[3]; if (U.m_SkinFlipFaces){ remap[0] = 0; remap[1] = 1; remap[2] = 2; }else{ remap[0] = 0; remap[1] = 2; remap[2] = 1; } // Process mesh // Get object from node. Abort if no object. Log("..Transforming mesh"); BOOL bDeleteTriObject; R_ASSERT (pObject); TriObject * pTriObject = GetTriObjectFromObjRef(pObject, &bDeleteTriObject); if (!pTriObject){ ERR("Can't create tri object."); return FALSE; } Mesh& M = pTriObject->mesh; // Vertices { // check match with int iNumVert = M.getNumVerts(); if (!(iNumVert==numVertices && iNumVert==m_Vertices.size())) { ERR("Non attached vertices found."); if (bDeleteTriObject) delete(pTriObject); return FALSE; } // transform vertices for (int i=0; i<iNumVert; i++){ Point3 P = M.getVert(i); Point3 T = matMesh.PointTransform(P); T *= m_fGlobalScale; m_Vertices[i]->SetPosition(T); } } Log("..Parsing materials"); // Parse Materials m_MtlMain = m_MeshNode->GetMtl(); R_ASSERT(m_MtlMain); DWORD cSubMaterials=m_MtlMain->NumSubMtls(); if (cSubMaterials < 1) { // Count the material itself as a submaterial. cSubMaterials = 1; } // build normals M.buildRenderNormals(); Log("..Converting vertices"); // our Faces and Vertices { for (int i=0; i<M.getNumFaces(); i++){ Face* gF = M.faces + i; TVFace* tF = M.tvFace + i; int m_id = gF->getMatID(); if (cSubMaterials == 1){ m_id = 0; }else{ // SDK recommends mod'ing the material ID by the valid # of materials, // as sometimes a material number that's too high is returned. m_id %= cSubMaterials; } st_FACE* nF = xr_new<st_FACE>(); nF->m_id = m_id; nF->sm_group = gF->getSmGroup(); for (int VVV=0; VVV<3; VVV++){ int vert_id = gF->v[remap[VVV]]; CVertexDef &D = *(m_Vertices[vert_id]); Point3 &UV = M.tVerts[tF->t[remap[VVV]]]; st_VERT v; v.Set (D); v.P.set (D.P); v.SetUV (UV.x,1-UV.y); // v.sm_group = U.m_SkinSuppressSmoothGroup?0:gF->getSmGroup(); // smooth group nF->v[VVV] = AddVert(v); } m_ExpFaces.push_back(nF); } } if (bDeleteTriObject) delete(pTriObject); } UpdateParenting(); return bRes; };
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId) { // check for valid mesh and physique modifier if((m_pIMesh == 0)) { theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__); return 0; } // check if face id is valid if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces())) { theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__); return 0; } // check if face vertex id is valid if((faceVertexId < 0) || (faceVertexId >= 3)) { theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__); return 0; } // allocate a new vertex candidate CVertexCandidate *pVertexCandidate; pVertexCandidate = new CVertexCandidate(); if(pVertexCandidate == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); return 0; } // create the new vertex candidate if(!pVertexCandidate->Create()) { delete pVertexCandidate; return 0; } // get vertex id int vertexId; vertexId = m_pIMesh->faces[faceId].v[faceVertexId]; // get the absolute vertex position Point3 vertex; vertex = m_pIMesh->getVert(vertexId) * m_tm; // set the vertex candidate position pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z); pVertexCandidate->SetUniqueId(vertexId); // get the absolute vertex normal Point3 normal; normal = GetVertexNormal(faceId, vertexId); normal = normal * Inverse(Transpose(m_tm)); normal = normal.Normalize(); // set the vertex candidate normal pVertexCandidate->SetNormal(normal.x, normal.y, normal.z); if(m_pIMesh->numCVerts > 0) { VertColor vc; vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]]; CalVector vcCal(vc.x, vc.y, vc.z); pVertexCandidate->SetVertColor(vcCal); } // get the vertex weight array float *pVertexWeights; pVertexWeights = m_pIMesh->getVertexWeights(); //if( pVertexWeights == NULL ) { // delete pVertexCandidate; // theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__); // return 0; //} // get the vertex weight (if possible) float weight; if(pVertexWeights != 0) { weight = pVertexWeights[vertexId]; } else { weight = 0.0f; } // another 3ds max weird behaviour: // zero out epsilon weights if(weight < 0.0005f) weight = 0.0f; // set the vertex candidate weight pVertexCandidate->SetPhysicalProperty(weight); // get the material id of the face int materialId; materialId = GetFaceMaterialId(faceId); if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size())) { delete pVertexCandidate; theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__); return 0; } // get the material of the face StdMat *pStdMat; pStdMat = m_vectorStdMat[materialId]; // loop through all the mapping channels and extract texture coordinates int mapId; for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++) { // get texture map Texmap *pTexMap; pTexMap = pStdMat->GetSubTexmap(mapId); // check if map is valid if((pTexMap != 0) && (pStdMat->MapEnabled(mapId))) { // get the mapping channel int channel; channel = pTexMap->GetMapChannel(); bool bValidUV; bValidUV = false; // extract the texture coordinate UVVert uvVert; if(m_pIMesh->mapSupport(channel)) { TVFace *pTVFace; pTVFace = m_pIMesh->mapFaces(channel); UVVert *pUVVert; pUVVert = m_pIMesh->mapVerts(channel); uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]]; bValidUV = true; } else if(m_pIMesh->numTVerts > 0) { uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]]; bValidUV = true; } // if we found valid texture coordinates, add them to the vertex candidate if(bValidUV) { // apply a possible uv generator StdUVGen *pStdUVGen; pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen(); if(pStdUVGen != 0) { Matrix3 tmUV; pStdUVGen->GetUVTransform(tmUV); uvVert = uvVert * tmUV; } // add texture coordinate to the vertex candidate, inverting the y coordinate pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y); } } } // check for physique modifier if(m_modifierType == MODIFIER_PHYSIQUE) { // create a physique export interface IPhysiqueExport *pPhysiqueExport; pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == 0) { delete pVertexCandidate; theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__); return 0; } // create a context export interface IPhyContextExport *pContextExport; pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode); if(pContextExport == 0) { m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__); return 0; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport; pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId); if(pVertexExport == 0) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__); return 0; } // get the vertex type int vertexType; vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex; pTypeVertex = (IPhyRigidVertex *)pVertexExport; // add the influence to the vertex candidate // get the influencing bone if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f)) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex; pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId))) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } #if MAX_RELEASE >= 4000 // check for skin modifier else if(m_modifierType == MODIFIER_SKIN) { // create a skin interface ISkin *pSkin; pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN); if(pSkin == 0) { delete pVertexCandidate; theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__); return 0; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode); if(pSkinContextData == 0) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__); return 0; } // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++) { // get the bone id int boneId; boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId); if(boneId < 0) continue; // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId))) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } // release all interfaces m_pModifier->ReleaseInterface(I_SKIN, pSkin); } #endif else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) { } else { theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__); return 0; } return pVertexCandidate; }
// --[ Method ]--------------------------------------------------------------- // // - Class : CStravaganzaMaxTools // // - prototype : bool AddNodeBones(std::vector<INode*> &vecMaxBones, INode *pMaxNode) // // - Purpose : Adds all bones belonging to the node to the given list. // // ----------------------------------------------------------------------------- bool CStravaganzaMaxTools::AddNodeBones(std::vector<INode*> &vecMaxBones, INode *pMaxNode) { int nCount = 0; int nBoneCount = 0; bool bOK = true; Modifier *pPhyModifier = NULL; // Physique modifier IPhysiqueExport *pPhyExport = NULL; // Physique export interface IPhyContextExport *pPhyObjExport = NULL; // Physique object export interface // Get Physique modifier if(pPhyModifier = GetPhysiqueModifier(pMaxNode)) { pPhyExport = (IPhysiqueExport *)pPhyModifier->GetInterface(I_PHYINTERFACE); if(pPhyExport == NULL) { return false; } } else { return false; } // Get physique object export interface pPhyObjExport = pPhyExport->GetContextInterface(pMaxNode); if(pPhyObjExport == NULL) { pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); return false; } pPhyObjExport->ConvertToRigid(true); pPhyObjExport->AllowBlending(true); INode *pMaxBone; // Build bone list LOG.Write("\nObject %s Bone List:", pMaxNode->GetName()); for(nCount = 0; nCount < pPhyObjExport->GetNumberVertices(); nCount++) { IPhyVertexExport *pPhyVertExport; IPhyBlendedRigidVertex *pPhyBRVertexExport; IPhyRigidVertex *pPhyRigidVertexExport; IPhyFloatingVertex *pPhyFloatingVertex; pPhyVertExport = pPhyObjExport->GetVertexInterface(nCount); if(pPhyVertExport) { if(pPhyVertExport->GetVertexType() & BLENDED_TYPE) { pPhyBRVertexExport = (IPhyBlendedRigidVertex *)pPhyVertExport; for(nBoneCount = 0; nBoneCount < pPhyBRVertexExport->GetNumberNodes(); nBoneCount++) { pMaxBone = pPhyBRVertexExport->GetNode(nBoneCount); if(IsBoneInList(vecMaxBones, pMaxBone) == false) { // LOG.Write("\n %s (blended)", pMaxBone->GetName()); vecMaxBones.push_back(pMaxBone); } } } else { pPhyRigidVertexExport = (IPhyRigidVertex *)pPhyVertExport; pMaxBone = pPhyRigidVertexExport->GetNode(); if(IsBoneInList(vecMaxBones, pMaxBone) == false) { // LOG.Write("\n %s (rigid)", pMaxBone->GetName()); vecMaxBones.push_back(pMaxBone); } } pPhyObjExport->ReleaseVertexInterface(pPhyVertExport); } pPhyFloatingVertex = pPhyObjExport->GetFloatingVertexInterface(nCount); if(pPhyFloatingVertex) { for(nBoneCount = 0; nBoneCount < pPhyFloatingVertex->GetNumberNodes(); nBoneCount++) { pMaxBone = pPhyFloatingVertex->GetNode(nBoneCount); if(IsBoneInList(vecMaxBones, pMaxBone) == false) { // LOG.Write("\n %s (floating)", pMaxBone->GetName()); vecMaxBones.push_back(pMaxBone); } } pPhyObjExport->ReleaseVertexInterface(pPhyFloatingVertex); } } pPhyExport->ReleaseContextInterface(pPhyObjExport); pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); return bOK; }
// --[ Method ]--------------------------------------------------------------- // // - Class : CStravaganzaMaxTools // // - prototype : int BuildPhysiqueData(INode* pMaxNode, // CObject* pObject, // std::vector<std::string> &vecBoneNames, // std::vector<CBlendedVertex> &vecBlendedVertices) // // - Purpose : Builds the bone data for a given node. Returns the number // of bones processed (0 = failure). // // ----------------------------------------------------------------------------- int CStravaganzaMaxTools::BuildPhysiqueData(INode* pMaxNode, CObject* pObject, std::vector<std::string> &vecBoneNames, std::vector<CBlendedVertex> &vecBlendedVertices) { int nCount = 0; int nBoneCount = 0; Modifier *pPhyModifier = NULL; // Physique modifier IPhysiqueExport *pPhyExport = NULL; // Physique export interface IPhyContextExport *pPhyObjExport = NULL; // Physique object export interface vecBoneNames.clear(); vecBlendedVertices.clear(); // Build bone list std::vector<INode*> vecMaxBones; if(!AddNodeBones(vecMaxBones, pMaxNode)) { LOG.Write("\nWARNING - Error building node %s bone list", pMaxNode->GetName()); return 0; } // Build bones name list for(nBoneCount = 0; nBoneCount < vecMaxBones.size(); nBoneCount++) { vecBoneNames.push_back(vecMaxBones[nBoneCount]->GetName()); } // Get Physique modifier if(pPhyModifier = GetPhysiqueModifier(pMaxNode)) { pPhyExport = (IPhysiqueExport *)pPhyModifier->GetInterface(I_PHYINTERFACE); if(pPhyExport == NULL) { LOG.Write("\nWARNING - Couldn't get Physique export interface.\nFailed with node %s.", pMaxNode->GetName()); return 0; } } // Get physique object export interface pPhyObjExport = pPhyExport->GetContextInterface(pMaxNode); if(pPhyObjExport == NULL) { pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); LOG.Write("\nWARNING - Unable to get physique context export.\nFailed with node %s.", pMaxNode->GetName()); return 0; } // Convert to rigid for time independent vertex assignment // Allow blending to export multi-link assignments pPhyObjExport->ConvertToRigid(true); pPhyObjExport->AllowBlending(true); // Build deformable vertex list bool bOK = true; int nBlendedCount = 0, nBlendedRigidCount = 0, nFloatingCount = 0; for(nCount = 0; nCount < pPhyObjExport->GetNumberVertices(); nCount++) { IPhyVertexExport *pPhyVertExport; IPhyBlendedRigidVertex *pPhyBRVertexExport; IPhyRigidVertex *pPhyRigidVertexExport; IPhyFloatingVertex *pPhyFloatingVertex; pPhyVertExport = pPhyObjExport->GetVertexInterface(nCount); CBlendedVertex blendedVertex; float fTotalWeight = 0.0f; bool bFloatingBones = false; // Floating Vertex pPhyFloatingVertex = pPhyObjExport->GetFloatingVertexInterface(nCount); if(pPhyFloatingVertex) { bFloatingBones = true; CVector3 v3OffsetVector; float fWeight; // More than one bone int nNumVtxBones = pPhyFloatingVertex->GetNumberNodes(); // LOG.Write("\n%u - Floating, with %u bones", nCount, nNumVtxBones); for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++) { int nIndex = GetBoneIndex(vecMaxBones, pPhyFloatingVertex->GetNode(nBoneCount)); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyFloatingVertex->GetNode(nBoneCount)->GetName()); bOK = false; break; } float fTotal; v3OffsetVector = Point3ToVector3(pPhyFloatingVertex->GetOffsetVector(nBoneCount)); fWeight = pPhyFloatingVertex->GetWeight(nBoneCount, fTotal); fTotalWeight += fWeight;//fTotal; //fWeight = fTotal; // LOG.Write("\n Weight = %f (%s)", fWeight, pPhyFloatingVertex->GetNode(nBoneCount)->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); } // LOG.Write("\n Total = %f", fTotalWeight); if(!ARE_EQUAL(fTotalWeight, 1.0f)) { LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight); } nFloatingCount++; pPhyObjExport->ReleaseVertexInterface(pPhyFloatingVertex); } if(pPhyVertExport) { if(pPhyVertExport->GetVertexType() & BLENDED_TYPE) { CVector3 v3OffsetVector; float fWeight; // More than one bone pPhyBRVertexExport = (IPhyBlendedRigidVertex *)pPhyVertExport; int nNumVtxBones = pPhyBRVertexExport->GetNumberNodes(); // LOG.Write("\n%u - Blended, with %u bones", nCount, nNumVtxBones); for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++) { int nIndex = GetBoneIndex(vecMaxBones, pPhyBRVertexExport->GetNode(nBoneCount)); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyBRVertexExport->GetNode(nBoneCount)->GetName()); bOK = false; break; } v3OffsetVector = Point3ToVector3(pPhyBRVertexExport->GetOffsetVector(nBoneCount)); fWeight = pPhyBRVertexExport->GetWeight(nBoneCount); fTotalWeight += fWeight; // LOG.Write("\n Weight = %f (%s)", fWeight, pPhyBRVertexExport->GetNode(nBoneCount)->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); } // LOG.Write("\n Total = %f", fTotalWeight); if(!ARE_EQUAL(fTotalWeight, 1.0f)) { LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight); } nBlendedCount++; } else { CVector3 v3OffsetVector; float fWeight; // Single bone pPhyRigidVertexExport = (IPhyRigidVertex *)pPhyVertExport; int nIndex = GetBoneIndex(vecMaxBones, pPhyRigidVertexExport->GetNode()); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyRigidVertexExport->GetNode()->GetName()); bOK = false; break; } v3OffsetVector = Point3ToVector3(pPhyRigidVertexExport->GetOffsetVector()); fWeight = 1.0f; fTotalWeight = 1.0f; // LOG.Write("\n%u - Rigid (%s)", nCount, pPhyRigidVertexExport->GetNode()->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); nBlendedRigidCount++; } pPhyObjExport->ReleaseVertexInterface(pPhyVertExport); } for(int i = 0; i < blendedVertex.GetNumLinks(); i++) { // Normalize blendedVertex.SetWeight(i, blendedVertex.GetWeight(i) / fTotalWeight); } vecBlendedVertices.push_back(blendedVertex); } pPhyExport->ReleaseContextInterface(pPhyObjExport); pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); if(!bOK) { vecMaxBones.clear(); vecBoneNames.clear(); vecBlendedVertices.clear(); } else { LOG.Write("\nPhysique: %u bones, %u vertices (%u rigid, %u rigidblended, %u floating)", vecBoneNames.size(), vecBlendedVertices.size(), nBlendedRigidCount, nBlendedCount, nFloatingCount); } return vecMaxBones.size(); }
void SGP_MaxInterface::GetBoneGroup( Modifier *pModifier, int nModifierType, INode* pNode, Mesh* pMesh, int nVertexId, BoneGroup& boneGroup ) { if( !pMesh ) { assert( false ); return; } if( nVertexId >= pMesh->numVerts ) { assert( false ); return; } // static mesh if( nModifierType == MODIFIER_NONE ) { INode* pParent = pNode->GetParentNode(); if( pParent && ( IsBone( pParent ) || IsBipedBone( pParent ) ) ) { Influence infl; infl.fWeight = 1.0f; strcpy( infl.szBoneName, pParent->GetName() ); boneGroup.AddInfluence( infl ); } } // check for physique modifier else if( nModifierType == MODIFIER_PHYSIQUE ) { assert( pModifier && "get bone group error, modifier is null" ); // create a physique export interface IPhysiqueExport *pPhysiqueExport = (IPhysiqueExport *)pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == NULL) { return; } // create a context export interface IPhyContextExport *pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(pNode); if(pContextExport == NULL) { pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); return; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(nVertexId); if(pVertexExport == NULL) { pPhysiqueExport->ReleaseContextInterface(pContextExport); pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); return; } // get the vertex type int vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex = (IPhyRigidVertex *)pVertexExport; Influence infl; if( pTypeVertex->GetNode() ) { strcpy( infl.szBoneName, pTypeVertex->GetNode()->GetName() ); infl.fWeight = 1.0f; boneGroup.AddInfluence( infl ); } else return; } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones Influence infl; for(int nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { strcpy( infl.szBoneName, pTypeVertex->GetNode( nodeId )->GetName() ); infl.fWeight = pTypeVertex->GetWeight( nodeId ); boneGroup.AddInfluence( infl ); } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } else if( nModifierType == MODIFIER_SKIN) { assert( pModifier && "get bone group error, modifier is null" ); // create a skin interface ISkin *pSkin = (ISkin*)pModifier->GetInterface(I_SKIN); if(pSkin == 0) { return; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(pNode); if(pSkinContextData == NULL) { pModifier->ReleaseInterface(I_SKIN, pSkin); return; } // loop through all influencing bones for(int nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(nVertexId); nodeId++) { // get the bone id int boneId = pSkinContextData->GetAssignedBone(nVertexId, nodeId); if(boneId < 0) continue; INode* pBone = pSkin->GetBone( boneId ); Influence infl; strcpy( infl.szBoneName, pBone->GetName() ); infl.fWeight = pSkinContextData->GetBoneWeight(nVertexId, nodeId); boneGroup.AddInfluence( infl ); } // release all interfaces pModifier->ReleaseInterface(I_SKIN, pSkin); } }