//================================================================= // 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; ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!"); if (::FNodeMarkedToSkip(pnode)) return TREE_CONTINUE; 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); } } } // 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[iFace]; 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) { MtlID mtlidFace = pface->getMatID(); 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; Texmap *ptexmap = pstdmtlFace->GetSubTexmap(ID_DI); // 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); } BitmapTex *pbmptex = (BitmapTex*)ptexmap; strcpy(szBitmapName, pbmptex->GetMapName()); TSTR strPath, strFile; SplitPathFile(TSTR(szBitmapName), &strPath, &strFile); strcpy(szBitmapName,strFile); } } UVVert UVvertex0( 0, 0, 0 ); UVVert UVvertex1( 1, 0, 0 ); UVVert UVvertex2( 0, 1, 0 ); // All faces must have textures assigned to them if (pface->flags & HAS_TVERTS) { // Get TVface's 3 indexes into the Mesh's TVertex array(s). DWORD iTVertex0 = ptvface->getTVert(0); DWORD iTVertex1 = ptvface->getTVert(1); DWORD iTVertex2 = ptvface->getTVert(2); ASSERT_AND_ABORT((int)iTVertex0 < pmesh->getNumTVerts(), "Bogus TVertex 0 index"); ASSERT_AND_ABORT((int)iTVertex1 < pmesh->getNumTVerts(), "Bogus TVertex 1 index"); ASSERT_AND_ABORT((int)iTVertex2 < pmesh->getNumTVerts(), "Bogus TVertex 2 index"); // Get the 3 TVertex's for this TVFace // NOTE: I'm using getRVertPtr instead of getRVert to work around a 3DSMax bug UVvertex0 = pmesh->getTVert(iTVertex0); UVvertex1 = pmesh->getTVert(iTVertex1); UVvertex2 = pmesh->getTVert(iTVertex2); } else { //sprintf(st_szDBG, "ERROR--Node %s has a textureless face. All faces must have an applied texture.", (char*)strNodeName); //ASSERT_AND_ABORT(FALSE, st_szDBG); } /* const char *szExpectedExtension = ".bmp"; if (stricmp(szBitmapName+strlen(szBitmapName)-strlen(szExpectedExtension), szExpectedExtension) != 0) { sprintf(st_szDBG, "Node %s uses %s, which is not a %s file", (char*)strNodeName, szBitmapName, szExpectedExtension); ASSERT_AND_ABORT(FALSE, st_szDBG); } */ // Determine owning bones for the vertices. int iNodeV0, iNodeV1, iNodeV2; if (m_mcExport) { // The Physique add-in allows vertices to be assigned to bones arbitrarily iNodeV0 = InodeOfPhyVectex( iVertex0 ); iNodeV1 = InodeOfPhyVectex( iVertex1 ); iNodeV2 = InodeOfPhyVectex( iVertex2 ); } else { // Simple 3dsMax model: the vertices are owned by the object, and hence the node iNodeV0 = iNode; iNodeV1 = iNode; iNodeV2 = iNode; } // Rotate the face vertices out of object-space, and into world-space space Point3 v0 = pt3Vertex0 * mat3ObjectTM; Point3 v1 = pt3Vertex1 * mat3ObjectTM; Point3 v2 = pt3Vertex2 * mat3ObjectTM; Matrix3 mat3ObjectNTM = mat3ObjectTM; mat3ObjectNTM.NoScale( ); ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus pre normal 0" ); pt3Vertex0Normal = VectorTransform(mat3ObjectNTM, pt3Vertex0Normal); ASSERT_AND_ABORT( Length( pt3Vertex0Normal ) <= 1.1, "bogus post normal 0" ); ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus pre normal 1" ); pt3Vertex1Normal = VectorTransform(mat3ObjectNTM, pt3Vertex1Normal); ASSERT_AND_ABORT( Length( pt3Vertex1Normal ) <= 1.1, "bogus post normal 1" ); ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus pre normal 2" ); pt3Vertex2Normal = VectorTransform(mat3ObjectNTM, pt3Vertex2Normal); ASSERT_AND_ABORT( Length( pt3Vertex2Normal ) <= 1.1, "bogus post normal 2" ); // Finally dump the bitmap name and 3 lines of face info fprintf(m_pfile, "%s\n", szBitmapName); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV0, v0.x, v0.y, v0.z, pt3Vertex0Normal.x, pt3Vertex0Normal.y, pt3Vertex0Normal.z, UVvertex0.x, UVvertex0.y); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV1, v1.x, v1.y, v1.z, pt3Vertex1Normal.x, pt3Vertex1Normal.y, pt3Vertex1Normal.z, UVvertex1.x, UVvertex1.y); fprintf(m_pfile, "%3d %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", iNodeV2, v2.x, v2.y, v2.z, pt3Vertex2Normal.x, pt3Vertex2Normal.y, pt3Vertex2Normal.z, UVvertex2.x, UVvertex2.y); } cleanup( ); return TREE_CONTINUE; }
void XsiExp::DumpScaleKeys( INode * node, int indentLevel) { Control * cont = node->GetTMController()->GetScaleController(); IKeyControl * ikc = GetKeyControlInterface(cont); INode * parent = node->GetParentNode(); if (!cont || !parent || (parent && parent->IsRootNode()) || !ikc) { // no controller or root node return; } int numKeys = ikc->GetNumKeys(); if (numKeys <= 1) { return; } Object * obj = node->EvalWorldState(0).obj; BOOL isBone = obj && obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ? TRUE : FALSE; // anim keys header TSTR indent = GetIndent(indentLevel); fprintf(pStream,"%s\tSI_AnimationKey {\n", indent.data()); fprintf(pStream,"%s\t\t1;\n", indent.data()); // 1 means scale keys fprintf(pStream,"%s\t\t%d;\n", indent.data(), numKeys); int t, delta = GetTicksPerFrame(); Matrix3 matrix; AffineParts ap; for (int i = 0; i < numKeys; i++) { // get the key's time if (cont->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID, 0)) { ITCBRotKey key; ikc->GetKey(i, &key); t = key.time; } else if (cont->ClassID() == Class_ID(HYBRIDINTERP_SCALE_CLASS_ID, 0)) { IBezQuatKey key; ikc->GetKey(i, &key); t = key.time; } else if (cont->ClassID() == Class_ID(LININTERP_SCALE_CLASS_ID, 0)) { ILinRotKey key; ikc->GetKey(i, &key); t = key.time; } // sample the node's matrix matrix = node->GetNodeTM(t) * Inverse(node->GetParentTM(t)); if (!isBone) { matrix = matrix * topMatrix; } decomp_affine(matrix, &ap); fprintf(pStream, "%s\t\t%d; 3; %.6f, %.6f, %.6f;;%s\n", indent.data(), t / delta, ap.k.x, ap.k.z, ap.k.y, i == numKeys - 1 ? ";\n" : ","); } // anim keys close fprintf(pStream,"%s\t}\n\n", indent.data()); }
bool CExporter::buildGrpRigidMesh(grp::RigidMeshExporter* rigidMesh, INode* node, Mesh* mesh, const std::vector<ExportVertex>& exportVertices, const std::vector< std::vector<grp::LodIndices> >& buffers) { assert(rigidMesh != NULL); assert(node != NULL); wchar_t unicodeString[256]; mbstowcs(unicodeString, node->GetName(), 255); rigidMesh->m_name = unicodeString; rigidMesh->m_positions.resize(exportVertices.size()); rigidMesh->m_type = grp::MESH_RIGID; rigidMesh->m_vertexFormat = grp::POSITION; if ((m_options.exportType & EXP_MESH_NORMAL) != 0) { rigidMesh->m_vertexFormat |= grp::NORMAL; } if ((m_options.exportType & EXP_MESH_TANGENT) != 0) { rigidMesh->m_vertexFormat |= grp::TANGENT; } if ((m_options.exportType & EXP_MESH_TEXCOORD) != 0) { rigidMesh->m_vertexFormat |= grp::TEXCOORD; } if ((m_options.exportType & EXP_MESH_TEXCOORD2) != 0) { rigidMesh->m_vertexFormat |= grp::TEXCOORD2; } if ((m_options.exportType & EXP_MESH_VERTEX_COLOR) != 0) { rigidMesh->m_vertexFormat |= grp::COLOR; } //纹理坐标层数 int texCoordCount = mesh->getNumMaps() - 1; //0层为顶点颜色,1层为第一层纹理坐标 assert(texCoordCount >= 0); texCoordCount = std::min(2, texCoordCount); if (mesh->tvFace == NULL) { texCoordCount = 0; } if ((m_options.exportType & EXP_MESH_TEXCOORD) == 0) { texCoordCount = 0; } if (texCoordCount == 0) { rigidMesh->m_vertexFormat &= ~grp::TEXCOORD; rigidMesh->m_vertexFormat &= ~grp::TEXCOORD2; rigidMesh->m_vertexFormat &= ~grp::TANGENT; } else if (texCoordCount == 1) { rigidMesh->m_vertexFormat &= ~grp::TEXCOORD2; } else if ((rigidMesh->m_vertexFormat & grp::TEXCOORD2) == 0) { texCoordCount = 1; } if (mesh->vcFace == NULL) { rigidMesh->m_vertexFormat &= ~grp::COLOR; } if (rigidMesh->checkVertexFormat(grp::NORMAL)) { rigidMesh->m_normals.resize(exportVertices.size()); } if (rigidMesh->checkVertexFormat(grp::TANGENT)) { rigidMesh->m_tangents.resize(exportVertices.size()); rigidMesh->m_binormals.resize(exportVertices.size()); } if (rigidMesh->checkVertexFormat(grp::TEXCOORD)) { rigidMesh->m_texCoordsArray.resize(texCoordCount); for (int i = 0; i < texCoordCount; ++i) { rigidMesh->m_texCoordsArray[i].resize(exportVertices.size()); } } if (rigidMesh->checkVertexFormat(grp::COLOR)) { rigidMesh->m_colors.resize(exportVertices.size()); } for (int iVertex = 0; iVertex < exportVertices.size(); ++iVertex) { const ExportVertex& vertexExp = exportVertices[iVertex]; //pos grp::Vector3& vPos = rigidMesh->m_positions[iVertex]; ::Vector3FromPoint3(vPos, mesh->verts[vertexExp.maxVertexIndex]); //normal if (rigidMesh->checkVertexFormat(grp::NORMAL)) { grp::Vector3& normal = rigidMesh->m_normals[iVertex]; normal = vertexExp.normal; normal.normalize(); } //tangent/binormal if (rigidMesh->checkVertexFormat(grp::TANGENT)) { grp::Vector3& tangent = rigidMesh->m_tangents[iVertex]; grp::Vector3& binormal = rigidMesh->m_binormals[iVertex]; tangent = vertexExp.tangent; binormal = vertexExp.binormal; tangent.normalize(); binormal.normalize(); } //纹理坐标 for (int i = 0; i < texCoordCount; ++i) { grp::Vector2& texcoord = rigidMesh->m_texCoordsArray[i][iVertex]; if (i == 0) { ::Vector2FromPoint3(texcoord, mesh->tVerts[vertexExp.texcoord[i]]); } else { UVVert* pUV = mesh->mapVerts(i + 1); ::Vector2FromPoint3(texcoord, pUV[vertexExp.texcoord[i]]); } texcoord.Y = 1.0f - texcoord.Y; //纹理坐标超出0,1范围就不压缩 if ((m_options.exportType & EXP_MESH_COMPRESS_TEXCOORD) != 0 && (texcoord.X < 0.0f || texcoord.X > 1.0f || texcoord.Y < 0.0f || texcoord.Y > 1.0f)) { m_options.exportType &= (~EXP_MESH_COMPRESS_TEXCOORD); } } //顶点颜色 if (rigidMesh->checkVertexFormat(grp::COLOR)) { ::DWORDFromPoint3(rigidMesh->m_colors[iVertex], mesh->vertCol[vertexExp.color]); } }//for (int iVertex = 0; iVertex < iNumVertexMax; ++iVertex) rigidMesh->m_meshBuffers = buffers; INode* parent = node->GetParentNode(); if (parent != NULL && !parent->IsRootNode()) { mbstowcs(unicodeString, parent->GetName(), 255); rigidMesh->m_attachedBoneName = unicodeString; Matrix3 nodeTM = node->GetObjTMBeforeWSM(0); Matrix3 parentTM = parent->GetNodeTM(0); ::MatrixFromMatrix3(rigidMesh->m_transform, nodeTM * Inverse(parentTM)); } else { ::MatrixFromMatrix3(rigidMesh->m_transform, node->GetObjTMBeforeWSM(0)); } if ((m_options.exportType & EXP_MESH_PROPERTY) != 0) { TSTR buffer; node->GetUserPropBuffer(buffer); wchar_t* unicodeString = new wchar_t[buffer.length() + 1]; mbstowcs(unicodeString, buffer.data(), buffer.length() + 1); rigidMesh->m_property = unicodeString; delete[] unicodeString; } return true; }