📄 mrchelper.cpp
字号:
Matrix3 tm = GetBoneTM(pNode, 0);
tm.Invert();
MAXtoGL(tm, bHdr.inverseOrientationTM);
bHdr.parentIdx = parentIdx;
bHdr.childCnt = GetChildBoneCount(pNode);
//set child's index vector
if(bHdr.childCnt > 0)
{
BD[currIdx].childsVect.reserve(bHdr.childCnt);
for (int i=0; i<pNode->NumberOfChildren(); ++i)
{
int chIdx = ProcessBoneStruct(pNode->GetChildNode(i),pRoot,currIdx, BD);
if (0<=chIdx)
BD[currIdx].childsVect.push_back(chIdx);
}
}
assert (BD[currIdx].childsVect.size() == BD[currIdx].Hdr.childCnt);
return currIdx;
}
else
{
for (int i=0; i<pNode->NumberOfChildren(); ++i)
ProcessBoneStruct(pNode->GetChildNode(i),pRoot,-1, BD);
return -1;
}
}
// ============================================================================
int ProcessBoneAnim (INode *pRoot, Interval range, ULONG sampleD, BoneData_t* BD)
{
int keyCnt=0;
int totbones = CountBones(pRoot);
const ULONG start = TicksToMilliSec(range.Start());
const ULONG end = TicksToMilliSec(range.End());
if (!totbones) return 0;
// cycle throught every bone
for (int idx=0; idx<totbones; ++idx) {
// get bone node pointer
INode* pBone = GetBoneByIndex(pRoot, idx);
assert (IsBone(pBone));
ULONG msec=0;
//BD[idx].keysVect.reserve(end/sampleD);
// grab keys for this bone
for(msec = start; msec < end+sampleD; msec += sampleD)
{
MRCbonekey_hdr KeyHdr;
memset(&KeyHdr, 0, sizeof(MRCbonekey_hdr));
//grab key time (in millisecs)
if(msec > end) KeyHdr.time = end;
else KeyHdr.time = msec;
//grab bone animation matrix at time t
Matrix3 tm;
TimeValue t;
t = MilliSecToTicks(msec);
tm = GetBoneTM(pBone, t);
MAXtoGL(tm);
// grab translation
Point3 pos = tm.GetTrans();
KeyHdr.pos[0] = pos.x;
KeyHdr.pos[1] = pos.y;
KeyHdr.pos[2] = pos.z;
// grab rotation union quaternion
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].keysVect.push_back(KeyHdr);
}
}
keyCnt = BD[0].keysVect.size();
return keyCnt;
}
// ============================================================================
// ============================================================================
bool GetPhysiqueWeights(INode *pNode, INode *pRoot, Modifier *pMod, BoneData_t *BD)
{
// create a Physique Export Interface for the given Physique Modifier
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++)
{
//get i-th vertex
IPhyVertexExport *vtxInterface = (IPhyVertexExport*)modContextInt->GetVertexInterface(i);
if(vtxInterface)
{
int vtxType = vtxInterface->GetVertexType();
if(vtxType == RIGID_TYPE)
{
//get bone
INode *boneNode = ((IPhyRigidVertex*)vtxInterface)->GetNode();
int boneIdx = GetBoneIndex(pRoot, boneNode);
//Build vertex data
MRCweight_hdr wdata;
wdata.vertIdx = i;
wdata.weight = 1.0f;
//Insert into proper bonedata
BD[boneIdx].weightsVect.push_back(wdata);
//update vertexWeightCnt for that bone
BD[boneIdx].Hdr.vertexCnt = BD[boneIdx].weightsVect.size();
}
else if(vtxType == RIGID_BLENDED_TYPE)
{
IPhyBlendedRigidVertex *vtxBlendedInt = (IPhyBlendedRigidVertex*)vtxInterface;
for(int j = 0; j < vtxBlendedInt->GetNumberNodes(); j++)
{
//get j-th bone
INode *boneNode = vtxBlendedInt->GetNode(j);
//whose index is boneIdx
int boneIdx = GetBoneIndex(pRoot, boneNode);
//Build vertex data
MRCweight_hdr wdata;
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].weightsVect.size();v++)
{
//update found vertex weight data for that bone
if (BD[boneIdx].weightsVect[v].vertIdx == wdata.vertIdx)
{
BD[boneIdx].weightsVect[v].weight += wdata.weight;
notfound = false;
}
}
if (notfound)
{
//Add a new vertex weight data into proper bonedata
BD[boneIdx].weightsVect.push_back(wdata);
//update vertexWeightCnt for that bone
BD[boneIdx].Hdr.vertexCnt = BD[boneIdx].weightsVect.size();
}
}
}
}
}
phyInterface->ReleaseContextInterface(modContextInt);
}
pMod->ReleaseInterface(I_PHYINTERFACE, phyInterface);
}
return true;
}
// ============================================================================
// ============================================================================
// export to MRC file every BoneData entry
bool ExportBoneData(BoneData_t *BD,int boneCnt, int keyCnt, FILE *out)
{
// write weights in bone major format
//i-th bone
for(int i = 0; i < boneCnt; i++)
{
long BoneHdrPos = ftell(out);
fseek(out, sizeof(MRCbone_hdr), SEEK_CUR);
// write the child bone index list
for (int j=0; j<BD[i].Hdr.childCnt; j++)
{
fwrite(&BD[i].childsVect[j], sizeof(int), 1, out);
}
BD[i].Hdr.boneWeightsOfs = ftell(out);
//BoneWeight data export
int weightCnt = BD[i].Hdr.vertexCnt;
//write data for j.th vertex who belongs to i-th bone
for( j = 0; j < weightCnt; j++)
{
MRCweight_hdr &vertWeight = BD[i].weightsVect[j];
fwrite(&vertWeight, sizeof(MRCweight_hdr), 1, out);
}
BD[i].Hdr.boneKeysOfs = ftell(out);
//BoneANIMATION data export
for( j = 0; j < keyCnt; j++)
{
MRCbonekey_hdr &boneKey = BD[i].keysVect[j];
fwrite(&boneKey, sizeof(MRCbonekey_hdr), 1, out);
}
long endPos = ftell(out);
// write down bone header
fseek(out, BoneHdrPos, SEEK_SET);
fwrite(&BD[i].Hdr, sizeof(MRCbone_hdr), 1, out);
fseek(out, endPos, SEEK_SET);
}
return true;
}
// ============================================================================
// dummy view used internally by WriteMesh
class NullView : public View {
public:
Point2 ViewToScreen(Point3 p)
{
return Point2(p.x,p.y);
}
NullView() {
worldToView.IdentityMatrix();
screenW=800.0f; screenH = 600.0f;
}
};
static NullView nullView;
// ============================================================================
// get and export mesh data to file
bool ExportMesh (INode* pNode, FILE *out)
{
if ((!pNode)||(!IsMesh(pNode))) return false;
MRCmesh_hdr mHdr;
memset(&mHdr, 0, sizeof(MRCmesh_hdr));
Matrix3 tm = pNode->GetObjectTM(0);
ObjectState os = pNode->EvalWorldState(0);
int needDelete;
Mesh& mesh = *(( (GeomObject*) os.obj)->GetRenderMesh(0,pNode,nullView,needDelete));
long startPos = ftell(out);
fseek(out, sizeof(MRCmesh_hdr), SEEK_CUR);
// write the mesh vertices
mHdr.vertCnt = mesh.getNumVerts();
mHdr.vertOfs = ftell(out);
for(int i = 0; i < mHdr.vertCnt; i++)
{
Point3 pnt = mesh.getVert(i) * tm; //premultiply in MAX
MAXtoGL(pnt); //useful coordinate transformation
fwrite(&pnt.x, sizeof(float), 3, out);
}
// write vertex normals
mesh.buildNormals();
mHdr.normCnt = mesh.getNumVerts();
mHdr.normOfs = ftell(out);
for(i = 0; i < mHdr.normCnt; i++)
{
// normals are taken from a unique smoothing group
Point3 norm = Normalize(mesh.getNormal(i));
MAXtoGL(norm);
fwrite(&norm.x, sizeof(float), 3, out);
}
// build and write faces
mHdr.faceCnt = mesh.getNumFaces();
mHdr.faceOfs = ftell(out);
for(i = 0; i < mHdr.faceCnt; i++)
{
MRCface_hdr fHdr;
memset(&fHdr, 0, sizeof(MRCface_hdr));
fHdr.vert[0] = mesh.faces[i].v[0];
fHdr.vert[1] = mesh.faces[i].v[1];
fHdr.vert[2] = mesh.faces[i].v[2];
// TODO: insert normals
fwrite(&fHdr, sizeof(MRCface_hdr), 1, out);
}
long endPos = ftell(out);
fseek(out, startPos, SEEK_SET);
fwrite(&mHdr, sizeof(MRCmesh_hdr), 1, out);
fseek(out, endPos, SEEK_SET);
return true;
}
// ============================================================================
// ============================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -