//Frist processing bone weights BOOL ProcessingBoneWeights(INode* pNode,INode* pRoot,BoneData* BD) { if((!pNode)||(!IsMesh(pNode))) return FALSE; Modifier* pmf=GetPhysiqueMod(pNode); if(pmf) GetPhysiqueWeights(pNode, pRoot, pmf, BD); else { pmf = GetSkinMod(pNode); if (pmf) GetSkinWeights(pNode,pMeshIdx,pRoot, pmf, BD); } int num=pNode->NumberOfChildren(); for(int n=0;n<num;n++) { ProcessingBoneWeights(pNode->GetChildNode(n),pRoot,BD); } return TRUE; } //here just take with Physique and Skin Modify .... static Modifier* GetPhysiqueMod(INode* pNode) { Object* pObj=pNode->GetObjectRef(); if(!pObj) return NULL; while(pObj->SuperClassID()==GEN_DERIVOB_CLASS_ID) { IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj); int modStackIndex=0; while(modStackIndex<pDerivedObj->NumModifiers()) { Modifier* mod=pDerivedObj->GetModifier(modStackIndex); if(mod->ClassID()==Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) return mod; modStackIndex++; } pObj=pDerivedObj->GetObjRef(); } return NULL; } static Modifier* GetSkinMod(INode* pNode) { Object* pObj=pNode->GetObjectRef(); if(!pObj) return NULL; while(pObj->SuperClassID()==GEN_DERIVOB_CLASS_ID) { IDerivedObject* pDerivedObj = static_cast<IDerivedObject*>(pObj); int modStackIndex=0; while(modStackIndex<pDerivedObj->NumModifiers()) { Modifier* mod=pDerivedObj->GetModifier(modStackIndex); if(mod->ClassID()==SKIN_CLASSID) return mod; modStackIndex++; } pObj=pDerivedObj->GetObjRef(); } return NULL; } // Get an index from a node pointer int GetBoneIndex(INode *pRoot, INode *pNode) { if(!IsBone(pNode)) return -1;
int boneCount = 0; return RecursiveGetBoneIndex(pRoot, pNode, boneCount); } //if there is more than one mesh ,we will use pMeshIdx BOOL GetSkinWeights(INode* pNode,int* pMeshIdx,INode* pRoot,Modifier* pMod,BoneData* BD) { ISkin* skin = (ISkin*)pMod->GetInterface(I_SKIN); if(skin) { ISkinContextData* skincontext = skin->GetContextInterface(pNode); if(skincontext) { int numVert=skincontext->GetNumPoints(); for(int i=0;i<numVert;i++) { int numBones=skincontext->GetNumAssignedBones(i); for(int j=0;j<numBones;j++) { INode* bone=skin->GetBone(skincontext->GetAssignedBone(i,j));//do not use j,but use GetAssignedBone(i,j) int boneIdx; if(bone) { boneIdx=GetBoneIndex(pRoot, bone); if(boneIdx==-1) continue; } else continue; BoneWeight_hdr wData; wData.meshIdx=*pMeshIdx; wData.vertIdx=i; wData.weight=skincontext->GetBoneWeight(i,j); bool notfound = true; for(int v=0;notfound&&v<BD[boneIdx].weightVect.size();v++) { if(BD[boneIdx].weightVect[v].vertIdx==wData.vertIdx&&BD[boneIdx].weightVect[v].meshIdx==wData.meshIdx) { BD[boneIdx].weightVect[v].weight += wData.weight; notfound = false; } } if(notfound) { BD[boneIdx].weightVect.push_back(wData); BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size(); } } } } pMod->ReleaseInterface(I_SKIN, skin); } return TRUE; } BOOL GetPhysiqueWeights(INode *pNode, int* pMeshIdx,INode *pRoot, Modifier *pMod, BoneData *BD) { IPhysiqueExport* phyInterface=(IPhysiqueExport*)pMod->GetInterface(I_PHYINTERFACE); if(phyInterface) { // create a ModContext Export Interface for the specific node of the Physique Modifier IPhyContextExport *modContextInt = (IPhyContextExport*)phyInterface->GetContextInterface(pNode); // needed by vertex interface (only Rigid one supported for now) modContextInt->ConvertToRigid(TRUE); // more than a single bone per vertex modContextInt->AllowBlending(TRUE); if(modContextInt) { int totalVtx=modContextInt->GetNumberVertices(); for(int i=0;i<totalVtx;i++) { IPhyVertexExport* vtxInterface=(IPhyVertexExport*)modContextInt->GetVertexInterface(i); if(vtxInterface) { int vertType=vtxInterface->GetVertexType(); if(vertType==RIGID_TYPE) { INode* boneNode=((IPhyRigidVertex*)vtxInterface)->GetNode(); int boneIdx=GetBoneIndex(pRoot, boneNode); BoneWeight_hdr wData; wData.meshIdx=*pMeshIdx; wData.vertIdx=i; wData.weight=1.0f; BD[boneIdx].weightVect.push_back(wData); BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size(); } else if(vertType==RIGID_BLENDED_TYPE) { IPhyBlendedRigidVertex *vtxBlendedInt = (IPhyBlendedRigidVertex*)vtxInterface; for(int j=0;j<vtxBlendedInt->GetNumberNodes();j++) { INode* boneNode=vtxBlendedInt->GetNode(j); int boneIdx=GetBoneIndex(pRoot, boneNode); BoneWeight_hdr wData; wData.meshIdx=*pMeshIdx; wData.vertIdx=i; wData.weight=vtxBlendedInt->GetWeight(j); //check vertex existence for this bone bool notfound = true; for(int v=0;notfound&&v<BD[boneIdx].weightVect.size();v++) { if(BD[boneIdx].weightVect[v].vertIdx==wData.vertIdx&&BD[boneIdx].weightVect[v].meshIdx==wData.meshIdx) { BD[boneIdx].weightVect[v].weight += wData.weight; notfound = false; } } if(notfound) { BD[boneIdx].weightVect.push_back(wData); BD[boneIdx].boneHdr.vertexCnt=BD[boneIdx].weightVect.size(); } } } } } phyInterface->ReleaseContextInterface(modContextInt); } pMod->ReleaseInterface(I_PHYINTERFACE, phyInterface); } return FALSE; } //=========================================== Matrix3 GetBoneTM(INode *pNode, TimeValue t) { Matrix3 tm(1);
tm = pNode->GetNodeTM(t);
tm.NoScale(); return tm; } // ============================================================================ // Recursive iterator to get a bone index, used with GetBoneIndex int RecursiveGetBoneIndex(INode *pRoot, INode *pNodeTest, int &boneCount) { int boneIdx = -1;
if(IsBone(pRoot)) { boneIdx = boneCount; boneCount++;
if(pRoot == pNodeTest) return boneIdx; }
// recurse child nodes for(int i = 0; i < pRoot->NumberOfChildren(); i++) { int boneIdx = RecursiveGetBoneIndex(pRoot->GetChildNode(i), pNodeTest, boneCount); if(boneIdx >= 0) return boneIdx; }
return -1; } // Get the number of direct child bones of a node int GetChildBoneCount(INode *pNode) { int count = 0;
for(int i = 0; i < pNode->NumberOfChildren(); i++) { if(IsBone(pNode->GetChildNode(i))) count++; } return count; } int ProcessBoneStruct(INode *pNode, INode *pRoot,int parentIdx, BoneData* BD) { if(IsBone(pNode)) { int currIdx=GetBoneIndex(pRoot,pNode); assert(-1!=currIdx); Bone_hdr &boneHdr=BD[currIdx].boneHdr; // get the bones inverse base matrix at time 0 Matrix3 tm=GetBoneTM(pNode,0); tm.Invert(); MAXtoGL(tm,boneHdr.inverseOrientationTM); boneHdr.parentIdx=parentIdx; boneHdr.childCnt=GetChildBoneCount(pNode); if(boneHdr.childCnt>0) { BD[currIdx].childIdxVect.reserve(boneHdr.childCnt); for(int i=0;i<pNode->NumberOfChildren();i++) { int cIdx=ProcessBoneStruct(pNode->GetChildNode(i),pRoot,currIdx,BD); if(cIdx>=0) BD[currIdx].childIdxVect.push_back(cIdx); } } assert(BD[currIdx].childIdxVect.size()==BD[currIdx].boneHdr.childCnt); return currIdx; } else { for (int i=0; i<pNode->NumberOfChildren(); ++i) ProcessBoneStruct(pNode->GetChildNode(i),pRoot,-1, BD); return -1; } } // used by GetBoneByIndex static bool BuildIter(INode* pnode, INode** const Iterator, int& currIdx) { if(IsBone(pnode)){ Iterator[currIdx++] = pnode; }
for(int i = 0; i < pnode->NumberOfChildren(); i++) { BuildIter(pnode->GetChildNode(i),Iterator,currIdx); }
return true; } // Get bone pointer from an index, this should get passed the root node INode* GetBoneByIndex(INode* const pRoot, int index) { INode* bone = NULL; const int bone_cnt = CountBones(pRoot); if (index>=bone_cnt) return NULL;
INode** const Iterator = new INode* [bone_cnt]; int currIdx=0; BuildIter(pRoot,Iterator,currIdx); assert(currIdx==bone_cnt);
bone = Iterator[index]; assert (GetBoneIndex(pRoot,bone)==index);
delete [] Iterator; assert (IsBone(bone)); return bone; }
int ProcessBoneAnim (INode *pRoot, Interval range, ULONG sampleD, BoneData* BD) { int keycnt=0; int totalbones=CountBones(pRoot); const ULONG start = TicksToMilliSec(range.Start()); const ULONG end = TicksToMilliSec(range.End()); if(!totalbones) return 0; for(int idx=0;idx<totalbones;idx++) { INode *pBone=GetBoneByIndex(pRoot,idx); assert(IsBone(pBone)); ULONG msec=0; for(msec=start;msec<end+sampleD;msec+=sampleD) { BoneKey_hdr keyHdr; memset(&keyHdr,0,sizeof(BoneKey_hdr)); if(msec>end) keyHdr.time=end; else keyHdr.time=msec; Matrix3 tm; TimeValue t; t=MilliSecToTicks(msec); tm=GetBoneTM(pBone,t); MAXtoGL(tm);
Point3 pt=tm.GetTrans(); keyHdr.pos[0]=pt.x; keyHdr.pos[1]=pt.y; keyHdr.pos[2]=pt.z;
Quat quat(tm); quat.Normalize(); keyHdr.quat[0] = quat.x; keyHdr.quat[1] = quat.y; keyHdr.quat[2] = quat.z; keyHdr.quat[3] = quat.w; BD[idx].keyVect.push_back(keyHdr); } } keycnt = BD[0].keyVect.size(); return keycnt; } 
|