📄 smdlexp.cpp
字号:
// Root node has no parent, thus no translation
if (fNodeIsRoot)
iNodeParent = -1;
// check to see if the matrix isn't right handed
m_phec->m_rgmaxnode[iNode].isMirrored = DotProd( CrossProd( m_phec->m_rgmaxnode[iNode].mat3ObjectTM.GetRow(0).Normalize(), m_phec->m_rgmaxnode[iNode].mat3ObjectTM.GetRow(1).Normalize() ).Normalize(), m_phec->m_rgmaxnode[iNode].mat3ObjectTM.GetRow(2).Normalize() ) < 0;
// Dump node description
fprintf(m_pfile, "%3d \"%s\" %3d\n",
iNode,
strNodeName,
iNodeParent );
return TREE_CONTINUE;
}
//=================================================================
// Methods for DumpFrameRotationsTEP
//
int DumpFrameRotationsTEP::callback(INode *pnode)
{
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
int iNode = ::GetIndexOfINode(pnode);
TSTR strNodeName(pnode->GetName());
// The model's root is a child of the real "scene root"
INode *pnodeParent = pnode->GetParentNode();
BOOL fNodeIsRoot = pnodeParent->IsRootNode( );
// Get Node's "Local" Transformation Matrix
Matrix3 mat3NodeTM = pnode->GetNodeTM(m_tvToDump);
Matrix3 mat3ParentTM = pnodeParent->GetNodeTM(m_tvToDump);
mat3NodeTM.NoScale(); // Clear these out because they apparently
mat3ParentTM.NoScale(); // screw up the following calculation.
Matrix3 mat3NodeLocalTM = mat3NodeTM * Inverse(mat3ParentTM);
Point3 rowTrans = mat3NodeLocalTM.GetTrans();
// check to see if the parent bone was mirrored. If so, mirror invert this bones position
if (m_phec->m_rgmaxnode[iNode].imaxnodeParent >= 0 && m_phec->m_rgmaxnode[m_phec->m_rgmaxnode[iNode].imaxnodeParent].isMirrored)
{
rowTrans = rowTrans * -1.0f;
}
// Get the rotation (via decomposition into "affine parts", then quaternion-to-Euler)
// Apparently the order of rotations returned by QuatToEuler() is X, then Y, then Z.
AffineParts affparts;
float rgflXYZRotations[3];
decomp_affine(mat3NodeLocalTM, &affparts);
QuatToEuler(affparts.q, rgflXYZRotations);
float xRot = rgflXYZRotations[0]; // in radians
float yRot = rgflXYZRotations[1]; // in radians
float zRot = rgflXYZRotations[2]; // in radians
// Get rotations in the -2pi...2pi range
xRot = ::FlReduceRotation(xRot);
yRot = ::FlReduceRotation(yRot);
zRot = ::FlReduceRotation(zRot);
// Print rotations
fprintf(m_pfile, "%3d %f %f %f %f %f %f\n",
// Node:%-15s Rotation (x,y,z)\n",
iNode, rowTrans.x, rowTrans.y, rowTrans.z, xRot, yRot, zRot);
return TREE_CONTINUE;
}
//=================================================================
// Methods for DumpModelTEP
//
Modifier *FindPhysiqueModifier (INode *nodePtr)
{
// Get object from node. Abort if no object.
Object *ObjectPtr = nodePtr->GetObjectRef();
if (!ObjectPtr) return NULL;
// Is derived object ?
if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
// Yes -> Cast.
IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr);
// Iterate over all entries of the modifier stack.
int ModStackIndex = 0;
while (ModStackIndex < DerivedObjectPtr->NumModifiers())
{
// Get current modifier.
Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
// Is this Physique ?
if (ModifierPtr->ClassID() == Class_ID( PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B) )
{
// Yes -> Exit.
return ModifierPtr;
}
// Next modifier stack entry.
ModStackIndex++;
}
}
// Not found.
return NULL;
}
Modifier *FindBonesProModifier (INode *nodePtr)
{
// Get object from node. Abort if no object.
Object *ObjectPtr = nodePtr->GetObjectRef();
if (!ObjectPtr) return NULL;
// Is derived object ?
if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
// Yes -> Cast.
IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr);
// Iterate over all entries of the modifier stack.
int ModStackIndex = 0;
while (ModStackIndex < DerivedObjectPtr->NumModifiers())
{
// Get current modifier.
Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
// Is this Bones Pro OSM?
if (ModifierPtr->ClassID() == BP_CLASS_ID_OSM )
{
// Yes -> Exit.
return ModifierPtr;
}
// Is this Bones Pro WSM?
if (ModifierPtr->ClassID() == BP_CLASS_ID_WSM )
{
// Yes -> Exit.
return ModifierPtr;
}
// Next modifier stack entry.
ModStackIndex++;
}
}
// Not found.
return NULL;
}
// #define DEBUG_MESH_DUMP
//=================================================================
// Methods for DumpModelTEP
//
int DumpModelTEP::callback(INode *pnode)
{
Object* pobj;
int fHasMat = TRUE;
// clear physique export parameters
m_mcExport = NULL;
m_phyExport = NULL;
m_phyMod = NULL;
m_bonesProMod = NULL;
ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
if (::FNodeMarkedToSkip(pnode))
return TREE_CONTINUE;
// Actually, if it's not selected, skip it!
//if (!pnode->Selected())
// return TRUE;
int iNode = ::GetIndexOfINode(pnode);
TSTR strNodeName(pnode->GetName());
// The Footsteps node apparently MUST have a dummy mesh attached! Ignore it explicitly.
if (FStrEq((char*)strNodeName, "Bip01 Footsteps"))
return TREE_CONTINUE;
// Helper nodes don't have meshes
pobj = pnode->GetObjectRef();
if (pobj->SuperClassID() == HELPER_CLASS_ID)
return TREE_CONTINUE;
// The model's root is a child of the real "scene root"
INode *pnodeParent = pnode->GetParentNode();
BOOL fNodeIsRoot = pnodeParent->IsRootNode( );
// Get node's material: should be a multi/sub (if it has a material at all)
Mtl *pmtlNode = pnode->GetMtl();
if (pmtlNode == NULL)
{
return TREE_CONTINUE;
fHasMat = FALSE;
}
else if (!(pmtlNode->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlNode->IsMultiMtl()))
{
// sprintf(st_szDBG, "ERROR--Material on node %s isn't a Multi/Sub-Object", (char*)strNodeName);
// ASSERT_AND_ABORT(FALSE, st_szDBG);
// fHasMat = FALSE;
}
// Get Node's object, convert to a triangle-mesh object, so I can access the Faces
ObjectState os = pnode->EvalWorldState(m_tvToDump);
pobj = os.obj;
TriObject *ptriobj;
BOOL fConvertedToTriObject =
pobj->CanConvertToType(triObjectClassID) &&
(ptriobj = (TriObject*)pobj->ConvertToType(m_tvToDump, triObjectClassID)) != NULL;
if (!fConvertedToTriObject)
return TREE_CONTINUE;
Mesh *pmesh = &ptriobj->mesh;
// Shouldn't have gotten this far if it's a helper object
if (pobj->SuperClassID() == HELPER_CLASS_ID)
{
sprintf(st_szDBG, "ERROR--Helper node %s has an attached mesh, and it shouldn't.", (char*)strNodeName);
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
// Ensure that the vertex normals are up-to-date
pmesh->buildNormals();
// We want the vertex coordinates in World-space, not object-space
Matrix3 mat3ObjectTM = pnode->GetObjectTM(m_tvToDump);
// initialize physique export parameters
m_phyMod = FindPhysiqueModifier(pnode);
if (m_phyMod)
{
// Physique Modifier exists for given Node
m_phyExport = (IPhysiqueExport *)m_phyMod->GetInterface(I_PHYINTERFACE);
if (m_phyExport)
{
// create a ModContext Export Interface for the specific node of the Physique Modifier
m_mcExport = (IPhyContextExport *)m_phyExport->GetContextInterface(pnode);
if (m_mcExport)
{
// convert all vertices to Rigid
m_mcExport->ConvertToRigid(TRUE);
}
}
}
// initialize bones pro export parameters
m_wa = NULL;
m_bonesProMod = FindBonesProModifier(pnode);
if (m_bonesProMod)
{
m_bonesProMod->SetProperty( BP_PROPID_GET_WEIGHTS, &m_wa );
}
// Dump the triangle face info
int cFaces = pmesh->getNumFaces();
for (int iFace = 0; iFace < cFaces; iFace++)
{
Face* pface = &pmesh->faces[iFace];
TVFace* ptvface = (pmesh->tvFace) ? &pmesh->tvFace[iFace] : NULL;
DWORD smGroupFace = pface->getSmGroup();
// Get face's 3 indexes into the Mesh's vertex array(s).
DWORD iVertex0 = pface->getVert(0);
DWORD iVertex1 = pface->getVert(1);
DWORD iVertex2 = pface->getVert(2);
ASSERT_AND_ABORT((int)iVertex0 < pmesh->getNumVerts(), "Bogus Vertex 0 index");
ASSERT_AND_ABORT((int)iVertex1 < pmesh->getNumVerts(), "Bogus Vertex 1 index");
ASSERT_AND_ABORT((int)iVertex2 < pmesh->getNumVerts(), "Bogus Vertex 2 index");
// Get the 3 Vertex's for this face
Point3 pt3Vertex0 = pmesh->getVert(iVertex0);
Point3 pt3Vertex1 = pmesh->getVert(iVertex1);
Point3 pt3Vertex2 = pmesh->getVert(iVertex2);
// Get the 3 RVertex's for this face
// NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug
RVertex *prvertex0 = pmesh->getRVertPtr(iVertex0);
RVertex *prvertex1 = pmesh->getRVertPtr(iVertex1);
RVertex *prvertex2 = pmesh->getRVertPtr(iVertex2);
// Find appropriate normals for each RVertex
// A vertex can be part of multiple faces, so the "smoothing group"
// is used to locate the normal for this face's use of the vertex.
Point3 pt3Vertex0Normal;
Point3 pt3Vertex1Normal;
Point3 pt3Vertex2Normal;
if (smGroupFace)
{
pt3Vertex0Normal = Pt3GetRVertexNormal(prvertex0, smGroupFace);
pt3Vertex1Normal = Pt3GetRVertexNormal(prvertex1, smGroupFace);
pt3Vertex2Normal = Pt3GetRVertexNormal(prvertex2, smGroupFace);
}
else
{
pt3Vertex0Normal = pmesh->getFaceNormal( iFace );
pt3Vertex1Normal = pmesh->getFaceNormal( iFace );
pt3Vertex2Normal = pmesh->getFaceNormal( iFace );
}
ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus orig normal 0" );
ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus orig normal 1" );
ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus orig normal 2" );
// Get Face's sub-material from node's material, to get the bitmap name.
// And no, there isn't a simpler way to get the bitmap name, you have to
// dig down through all these levels.
TCHAR szBitmapName[256] = "null.bmp";
if (fHasMat)
{
Texmap *ptexmap = NULL;
MtlID mtlidFace = pface->getMatID();
if (pmtlNode->IsMultiMtl())
{
if (mtlidFace >= pmtlNode->NumSubMtls())
{
sprintf(st_szDBG, "ERROR--Bogus sub-material index %d in node %s; highest valid index is %d",
mtlidFace, (char*)strNodeName, pmtlNode->NumSubMtls()-1);
// ASSERT_AND_ABORT(FALSE, st_szDBG);
mtlidFace = 0;
}
Mtl *pmtlFace = pmtlNode->GetSubMtl(mtlidFace);
ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned");
/*
if ((pmtlFace->ClassID() == Class_ID(MULTI_CLASS_ID, 0) && pmtlFace->IsMultiMtl()))
{
// it's a sub-sub material. Gads.
pmtlFace = pmtlFace->GetSubMtl(mtlidFace);
ASSERT_AND_ABORT(pmtlFace != NULL, "NULL Sub-material returned");
}
*/
if (!(pmtlFace->ClassID() == Class_ID(DMTL_CLASS_ID, 0)))
{
sprintf(st_szDBG,
"ERROR--Sub-material with index %d (used in node %s) isn't a 'default/standard' material [%x].",
mtlidFace, (char*)strNodeName, pmtlFace->ClassID());
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
StdMat *pstdmtlFace = (StdMat*)pmtlFace;
ptexmap = pstdmtlFace->GetSubTexmap(ID_DI);
}
else
{
ptexmap = pmtlNode->GetActiveTexmap();
}
// ASSERT_AND_ABORT(ptexmap != NULL, "NULL diffuse texture")
if (ptexmap != NULL)
{
if (!(ptexmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)))
{
sprintf(st_szDBG,
"ERROR--Sub-material with index %d (used in node %s) doesn't have a bitmap as its diffuse texture.",
mtlidFace, (char*)strNodeName);
ASSERT_AND_ABORT(FALSE, st_szDBG);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -