📄 maxmesh.cpp
字号:
pMesh->m_FrameCount = itr->second.m_transList.size();
else
pMesh->m_FrameCount = 0;
for (i=0; i<m_Bones.size(); i++, itr++)
{
bone.trans.clear();
bone.vertexIndics.clear();
if (itr->second.bUse)
{
strcpy(bone.name, itr->second.name);
for (int j=0; j<itr->second.m_transList.size(); j++)
{
bmat = itr->second.m_transList[j].mat;
bpt = bmat.GetRow(3);
bpt*=16;
bmat.SetRow(3, bpt);
bone.trans.push_back(bmat);
}
bone.nodeId = itr->first;
pMesh->m_Bones.push_back(bone);
}
}
//this section get the most weightest bone of every vertex. And record the vertex index to bone's
//info. It "only" useful for only One Bone per-vertex.
//we use other two struct to record max two bone information for one vertex.
int bonecount;
BoneInfo bitemp;
for (m=0; m<m_Vertics.size(); m++)
{
bonecount = m_Vertics[m].boneInfo.size();
if (bonecount > 0)
{
//rearrange the bones sequence for a vertex acoording to weight
for (int i=0; i<bonecount; i++)
{
bitemp = m_Vertics[m].boneInfo[i];
for (int j=i+1; j<bonecount; j++)
{
if (m_Vertics[m].boneInfo[i].weight < m_Vertics[m].boneInfo[j].weight )
{
bitemp = m_Vertics[m].boneInfo[i];
m_Vertics[m].boneInfo[i] = m_Vertics[m].boneInfo[j];
m_Vertics[m].boneInfo[j] = bitemp;
}
}
}
}
if (m_Vertics[m].boneInfo.size() > 0)
{
int index = FindBoneIndex(m_Vertics[m].boneInfo[0].boneIndex, pMesh->m_Bones);
if (index != -1)
pMesh->m_Bones[index].vertexIndics.push_back(m);
}
}
//remove bone not used for one bone and two bone.
for (m=0; m<pMesh->m_Bones.size(); m++)
pMesh->m_Bones[m].bUsed = false;
int boneidx;
for (m=0; m<m_Vertics.size(); m++)
{
int bonecount = m_Vertics[m].boneInfo.size();
if (bonecount == 1)
{
boneidx = FindBoneIndex(m_Vertics[m].boneInfo[0].boneIndex, pMesh->m_Bones);
if (boneidx >= 0)
pMesh->m_Bones[boneidx].bUsed = true;
}
if (bonecount >= 2)
{
boneidx = FindBoneIndex(m_Vertics[m].boneInfo[0].boneIndex, pMesh->m_Bones);
if (boneidx >= 0)
pMesh->m_Bones[boneidx].bUsed = true;
boneidx = FindBoneIndex(m_Vertics[m].boneInfo[1].boneIndex, pMesh->m_Bones);
if (boneidx >= 0)
pMesh->m_Bones[boneidx].bUsed = true;
}
}
vector<Bone>::iterator bitr = pMesh->m_Bones.begin();
while (bitr != pMesh->m_Bones.end())
{
if (!bitr->bUsed)
bitr = pMesh->m_Bones.erase(bitr);
else
bitr++;
}
//get one bone and two bones for every vertex
OneBoneVertex onebone;
TwoBoneVertex twoBone;
for (m=0; m<m_Vertics.size(); m++)
{
int bonecount = m_Vertics[m].boneInfo.size();
if (bonecount == 1)
{
onebone.boneIndex = FindBoneIndex(m_Vertics[m].boneInfo[0].boneIndex, pMesh->m_Bones);
onebone.vertexIndex = m;
pMesh->m_oneBoneVertex.push_back(onebone);
}
if (bonecount >= 2)
{
twoBone.vertexIndex = m;
twoBone.boneIndex1 = FindBoneIndex(m_Vertics[m].boneInfo[0].boneIndex, pMesh->m_Bones);
assert(m_Vertics[m].boneInfo[0].weight >= 0 && m_Vertics[m].boneInfo[0].weight<=1);
twoBone.boneWeight1 = m_Vertics[m].boneInfo[0].weight*128;
twoBone.boneIndex2 = FindBoneIndex(m_Vertics[m].boneInfo[1].boneIndex, pMesh->m_Bones);
assert(m_Vertics[m].boneInfo[1].weight >= 0 && m_Vertics[m].boneInfo[1].weight<=1);
twoBone.boneWeight2 = m_Vertics[m].boneInfo[1].weight*128;
if (m_Vertics[m].boneInfo[0].weight+m_Vertics[m].boneInfo[1].weight<0.99f)
twoBone.boneWeight2 = twoBone.boneWeight2;
twoBone.boneWeight1 = twoBone.boneWeight1*128/(twoBone.boneWeight1+twoBone.boneWeight2);
twoBone.boneWeight2 = 128 - twoBone.boneWeight1;
pMesh->m_twoBoneVertex.push_back(twoBone);
}
}
//we do need erase the bone not use when one bone per vertex. But when for two bones per vertex
//some bones shouldn't be removed any more. so we comment it. It will not effect the compatiblity
//with the old one bone file format. We just have some bones without vertex list.
/*
vector<Bone>::iterator bitr = pMesh->m_Bones.begin();
while (bitr != pMesh->m_Bones.end())
{
if (bitr->vertexIndics.size() == 0)
bitr = pMesh->m_Bones.erase(bitr);
else
bitr++;
}
*/
}
void CMaxMesh::AddAnimationData(MaxSubMesh *pSubMesh, IGameNode *pGameNode)
{
//in pSubMesh, we already have all vertex data in it.
//animation data. we should get every bone for every submesh in a max file.
//bone will have transform data for every frame
//for every vertex, it may be bonded to one than one bone with different weight
//step 1: get all bones of one submesh, and get it key frame transform data: position,
// rotation, scale.
//step 2: for every vertex for this submesh, get its related bones and weight;
// get weights ,CFace is a class that hold face info,i0,i1,i2 is face's vertexes id
// find skin modifier
Matrix3 mat;
AffineParts affp;
MaxBone bone;
FrameTransform trans;
BoneInfo binfo;
TSTR buf;
IGameObject * obj = pGameNode->GetIGameObject();
switch(obj->GetIGameType())
{
case IGameObject::IGAME_MESH:
IGameMesh * gM = (IGameMesh*)obj;
if(gM->InitializeData())
{
int numMod = obj->GetNumModifiers();
if(numMod > 0)
{
for(int i=0;i<numMod;++i)
{
IGameModifier * m = obj->GetIGameModifier(i);
if(m->IsSkin())
{
IGameSkin * skin = (IGameSkin*)m;
for(int vertexId=0; vertexId<skin->GetNumOfSkinnedVerts(); ++vertexId)
{
Matrix3 matrix;
const int numBones = skin->GetNumberOfBones(vertexId);
int i;
for(i=0;i<numBones; ++i)
{
ULONG boneId = skin->GetBoneID(vertexId,i);
float weight = skin->GetWeight(vertexId,i);
int intWeight = (int)(weight*256);
//if we already have the same bone. we only need to add weight to it
for (int j=0; j<pSubMesh->Vertics[vertexId].boneInfo.size(); j++)
{
if (boneId == pSubMesh->Vertics[vertexId].boneInfo[j].boneIndex)
{
pSubMesh->Vertics[vertexId].boneInfo[j].weight += weight;
break;
}
}
if (j < pSubMesh->Vertics[vertexId].boneInfo.size())
continue; //the bone was add, continue to next bone
if (intWeight <= 0)
{
intWeight = 1;
continue;
}
if (m_Bones.find(boneId) == m_Bones.end()) //we don't have this bone
{
IGameNode *pkBone = skin->GetIGameBone(vertexId, i);
AddBone(pkBone);
//continue;
}
m_Bones[boneId].bUse = TRUE;
binfo.boneIndex = boneId;
binfo.weight = weight;
pSubMesh->Vertics[vertexId].boneInfo.push_back(binfo);
}
}
}
}
}
}
break;
}
/*
Object *pObject = pNode->GetObjectRef();
if (pObject->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
IDerivedObject *pDerivedObject = (IDerivedObject *)pObject;
int nMod = pDerivedObject->NumModifiers();
for(i = 0; i < nMod; i++)
{
Modifier *pModifier = pDerivedObject->GetModifier(i);
Class_ID cid= pModifier->ClassID();
if (pModifier->ClassID() == SKIN_CLASSID)
{
ISkin *pSkin = (ISkin*)pModifier->GetInterface(I_SKIN); // get ISkin interface
if(pSkin)
{
bonecount = pSkin->GetNumBones();
for (m=0; m<bonecount; m++)
{
//get every bone
pBone = pSkin->GetBone(m);
//get every frame data
cpt = 0;
for (n=m_startTime; n<=m_endTime; n+=m_interval)
{
mat = pBone->GetNodeTM(n);
decomp_affine(mat, &affp);
trans.frameNo = cpt++;
trans.mat = mat;
bone.m_transList.push_back(trans);
}
m_Bones.push_back(bone);
}
//for every vertex in a submesh, find it's bones and weight;
ISkinContextData* pSkinContext = pSkin->GetContextInterface(pNode); // get context interface
if (pSkinContext != NULL && bonecount>0)
{
for (j=0; j<pSubMesh->Vertics.size(); j++)
{
n = pSkinContext->GetNumAssignedBones(j);
for (m=0; m<n; m++)
{
binfo.boneIndex = pSkinContext->GetAssignedBone(j,m);
binfo.weight = pSkinContext->GetBoneWeight(j, m);
pSubMesh->Vertics[j].boneInfo.push_back(binfo);
}
}
}
}
}
}
}
*/
}
void CMaxMesh::MergeSubmesh()
{
int vcount = 0, bcount = 0;
int tcount = 0;
int mcount = 0;
MaxFace face;
MaxVertex vertex;
int i,j;
for (i=0; i<m_meshs.size(); i++)
{
/*
for (j=0; j<m_meshs[i].m_Bones.size(); j++)
{
m_Bones.push_back(m_meshs[i].m_Bones[j]);
} */
for (j=0; j<m_meshs[i].Vertics.size(); j++)
{
vertex = m_meshs[i].Vertics[j];
m_Vertics.push_back(vertex);
}
for (j=0; j<m_meshs[i].TexCoord.size(); j++)
{
m_TexCoord.push_back(m_meshs[i].TexCoord[j]);
}
for (j=0; j<m_meshs[i].Mtrl.size(); j++)
{
m_Matrials.push_back(m_meshs[i].Mtrl[j]);
}
for (j=0; j<m_meshs[i].Faces.size(); j++)
{
face = m_meshs[i].Faces[j];
face.matid += mcount;
face.t1 += tcount;
face.t2 += tcount;
face.t3 += tcount;
face.v1 += vcount;
face.v2 += vcount;
face.v3 += vcount;
m_Faces.push_back(face);
}
mcount += m_meshs[i].Mtrl.size();
tcount += m_meshs[i].TexCoord.size();
vcount += m_meshs[i].Vertics.size();
}
m_numFaces = m_Faces.size();
m_numTexCoords = m_TexCoord.size();
m_numVertics = m_Vertics.size();
m_numMatrials = m_Matrials.size();
}
void CMaxMesh::GetBones()
{
for(int loop = 0; loop<m_pScene->GetTopLevelNodeCount();++loop)
{
IGameNode * pGameNode = m_pScene->GetTopLevelNode(loop);
//check for selected state - we deal with targets in the light/camera section
if(pGameNode->IsTarget())
continue;
RetrieveInverseMatrices(pGameNode);
}
}
void CMaxMesh::AddBone(IGameNode * node)
{
MaxBone bone;
Matrix3 matrix;
FrameTransform trans;
INode *onode = node->GetMaxNode();
strcpy(bone.name, onode->GetName());
int nodeid = node->GetNodeID();
bone.boneIndex = m_Bones.size();
Matrix3 nodematInv = node->GetWorldTM().ExtractMatrix3();
nodematInv.Invert();
int n=0;
for (int time=m_startTime; time<=m_endTime; time+=m_interval, n++)
{
trans.frameNo = n;
onode->EvalWorldState(time);
matrix = onode->GetNodeTM(time);
trans.mat = nodematInv*matrix;
bone.m_transList.push_back(trans);
}
m_Bones[nodeid] = bone;
}
void CMaxMesh::RetrieveInverseMatrices(IGameNode * node)
{
MaxBone bone;
FrameTransform trans;
int nodid = node->GetNodeID();
bool temp = node->IsGroupOwner();
int count = node->GetChildCount();
IGameNode *par = node->GetNodeParent();
if(!node->IsGroupOwner()
&& (node->GetChildCount() > 0 || node->GetNodeParent() != 0))
{
IGameObject * obj = node->GetIGameObject();
int nid = node->GetNodeID();
switch(obj->GetIGameType())
{
case IGameObject::IGAME_BONE:
case IGameObject::IGAME_HELPER:
case IGameObject::IGAME_MESH:
{
Matrix3 nodematInv = node->GetWorldTM(m_startTime).ExtractMatrix3();
nodematInv.Invert();
IGameControl * pGameControl = node->GetIGameControl();
IGameKeyTab Key;
if(pGameControl->GetFullSampledKeys(Key,1,IGAME_TM, false))
{
if (Key.Count() > 0)
{
strcpy(bone.name, node->GetName());
bone.m_transList.clear();
int nodeid = node->GetNodeID();
bone.boneIndex = m_Bones.size();
for (int m=0; m<Key.Count(); m++)
{
trans.frameNo = m;
trans.mat = Key[m].sampleKey.gval.ExtractMatrix3();
trans.mat = nodematInv*Key[m].sampleKey.gval.ExtractMatrix3();
// trans.mat = nodematInv*Key[m].sampleKey.gval.ExtractMatrix3();
bone.m_transList.push_back(trans);
}
m_Bones[nodeid] = bone;
}
}
break;
}
}
}
for(int i=0;i<node->GetChildCount();++i)
{
IGameNode * child = node->GetNodeChild(i);
// we deal with targets in the light/camera section
if(child->IsTarget())
continue;
RetrieveInverseMatrices(child);
}
node->ReleaseIGameObject();
}
int CMaxMesh::FindBoneIndex(int BoneID, vector<Bone> &bones)
{
for (int x=0; x<bones.size(); x++)
{
if (BoneID == bones[x].nodeId)
{
return x;
}
}
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -