void SceneExportUtil::getUsedMaterials( INode* node, Vector<Mtl*>& materials ) { require( node ); Mtl* mat = node->GetMtl(); if ( mat ) { materials.add( mat ); // get sub-materials (Multi/Sub-Object material) for ( int k = 0 ; k < mat->NumSubMtls() ; ++k ) { Mtl* submat = mat->GetSubMtl(k); if ( submat ) materials.add( submat ); } } // remove duplicates std::sort( materials.begin(), materials.end() ); std::unique( materials.begin(), materials.end() ); // sort to abc order std::sort( materials.begin(), materials.end(), MtlNameLess() ); }
int EnumMtlTree(MtlBase *mb, int subMtl, MtlEnum &tenum) { for (int i=0; i<mb->NumSubTexmaps(); i++) { Texmap *st = mb->GetSubTexmap(i); if (st) { if (!EnumMtlTree(st,subMtl, tenum)) { return 0; } } } if (IsTex(mb)) { if (!tenum.proc(mb,subMtl)) { return 0; } } if (IsMtl(mb)) { Mtl *m = (Mtl *)mb; for (i=0; i<m->NumSubMtls(); i++) { Mtl *sm = m->GetSubMtl(i); int subm = (mb->IsMultiMtl()&&subMtl<0)?i:subMtl; if (sm) { if (!EnumMtlTree(sm,subm,tenum)) { return 0; } } } if (!tenum.proc(mb,subMtl)) { return 0; } } return 1; }
bool Exporter::splitMesh(INode *node, Mesh& mesh, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors, bool noSplit) { Mtl* nodeMtl = node->GetMtl(); Matrix3 tm = node->GetObjTMAfterWSM(t); // Order of the vertices. Get 'em counter clockwise if the objects is // negatively scaled. int vi[3]; if (TMNegParity(tm)) { vi[0] = 2; vi[1] = 1; vi[2] = 0; } else { vi[0] = 0; vi[1] = 1; vi[2] = 2; } Matrix3 flip; flip.IdentityMatrix(); flip.Scale(Point3(1, -1, 1)); int nv = mesh.getNumVerts(); int nf = mesh.getNumFaces(); if (noSplit) { int nv = mesh.getNumVerts(); int nf = mesh.getNumFaces(); // Dont split the mesh at all. For debugging purposes. FaceGroup& grp = grps[0]; grp.vidx.resize(nv, -1); grp.verts.resize(nv); grp.faces.resize(nf); grp.uvs.resize(nv); grp.vnorms.resize(nv); grp.fidx.resize(nf); Matrix3 texm; getTextureMatrix(texm, getMaterial(node, 0)); texm *= flip; for (int face=0; face<nf; ++face) { grp.fidx[face] = face; for (int vi=0; vi<3; ++vi) { int idx = mesh.faces[face].getVert(vi); grp.faces[face][vi] = idx; // Calculate normal Point3 norm; #if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5 norm = getVertexNormal(&mesh, face, mesh.getRVertPtr(idx)); #else MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals (); if (NULL != specNorms && specNorms->GetNumNormals() != 0) norm = specNorms->GetNormal(face, vi); else norm = getVertexNormal(&mesh, face, mesh.getRVertPtr(idx)); #endif Point3 uv; if (mesh.tVerts && mesh.tvFace) { uv = mesh.tVerts[ mesh.tvFace[ face ].t[ vi ]] * texm; uv.y += 1.0f; } if (grp.vidx[idx] == idx){ ASSERT(grp.verts[idx] == TOVECTOR3(mesh.getVert(idx))); //ASSERT(vg.norm == norm); //Point3 uv = mesh.getTVert(idx); //if (mesh.getNumTVerts() > 0) //{ // ASSERT(grp.uvs[idx].u == uv.x && grp.uvs[idx].v == uv.y); //} } else { grp.vidx[idx] = idx; grp.verts[idx] = TOVECTOR3(mesh.getVert(idx)); //grp.uvs[idx].u = uv.x; //grp.uvs[idx].v = uv.y; grp.vnorms[idx] = TOVECTOR3(norm); } } } for (int i=0; i<nv; ++i) { ASSERT(grp.vidx[i] != -1); } } else { int face, numSubMtls = nodeMtl?nodeMtl->NumSubMtls():0; for (face=0; face<mesh.getNumFaces(); face++) { int mtlID = (numSubMtls!=0) ? (mesh.faces[face].getMatID() % numSubMtls) : 0; Mtl *mtl = getMaterial(node, mtlID); Matrix3 texm; getTextureMatrix(texm, mtl); texm *= flip; FaceGroup& grp = grps[mtlID]; if (grp.uvMapping.size() == 0) // Only needs to be done once per face group { int nmaps = 0; int nmapsStart = max(1, mesh.getNumMaps() - (mesh.mapSupport(0) ? 1 : 0)); // Omit vertex color map. for (int ii = 1; ii <= nmapsStart; ii++) // Winnow out the unsupported maps. { if (!mesh.mapSupport(ii)) continue; grp.uvMapping[ii] = nmaps++; } grp.uvs.resize(nmaps == 0 ? 1 : nmaps); } if (nv > int(grp.verts.capacity())) { grp.vgrp.reserve(nv); grp.verts.reserve(nv); grp.vnorms.reserve(nv); for (int i=0; i<grp.uvs.size(); ++i) grp.uvs[i].reserve(nv); grp.vcolors.reserve(nv); grp.vidx.reserve(nv); } if (nf > int(grp.faces.capacity())) { grp.faces.reserve(nf); grp.fidx.reserve(nf); } Triangle tri; for (int i=0; i<3; i++) tri[i] = addVertex(grp, face, vi[i], &mesh, texm, vertColors); grp.faces.push_back(tri); if (grp.fidx.size() < nf) grp.fidx.resize(nf,-1); grp.fidx[face] = grp.faces.size() - 1; } } return true; }
void XsiExp::ExportMesh( INode * node, TimeValue t, int indentLevel) { ObjectState os = node->EvalWorldState(t); if (!os.obj || os.obj->SuperClassID() != GEOMOBJECT_CLASS_ID) { return; // Safety net. This shouldn't happen. } BOOL needDel; TriObject * tri = GetTriObjectFromNode(node, t, needDel); if (!tri) { // no tri object return; } // prepare mesh Mesh * mesh = &tri->GetMesh(); mesh->buildNormals(); // object offset matrix; apply to verts // swap y and z; max to soft correction Matrix3 matrix(1); // translate matrix.PreTranslate( Point3( node->GetObjOffsetPos().x, node->GetObjOffsetPos().z, -node->GetObjOffsetPos().y)); // rotate AngAxis aa( node->GetObjOffsetRot()); float temp = aa.axis.z; aa.axis.z = -aa.axis.y; aa.axis.y = temp; PreRotateMatrix(matrix, Quat( aa)); // scale ScaleValue scale = node->GetObjOffsetScale(); aa.Set( scale.q); temp = aa.axis.z; aa.axis.z = -aa.axis.y; aa.axis.y = temp; scale.q.Set( aa); temp = scale.s.z; scale.s.z = scale.s.y; scale.s.y = temp; ApplyScaling(matrix, scale); // apply root transform matrix = matrix * topMatrix; // only rotation for normals AffineParts ap; Matrix3 rotMatrix(1); decomp_affine( matrix, &ap); PreRotateMatrix( rotMatrix, ap.q); // set winding order int vx1 = 0, vx2 = 1, vx3 = 2; if (TMNegParity( node->GetNodeTM(GetStaticFrame())) != TMNegParity( matrix) ) { // negative scaling; invert winding order and normal rotation vx1 = 2; vx2 = 1; vx3 = 0; rotMatrix = rotMatrix * Matrix3( Point3(-1,0,0), Point3(0,-1,0), Point3(0,0,-1), Point3(0,0,0)); } // header TSTR indent = GetIndent(indentLevel+1); fprintf(pStream, "%s%s %s {\n",indent.data(), "Mesh", FixupName(node->GetName())); // write number of verts int numLoop = mesh->getNumVerts(); fprintf(pStream, "%s\t%d;\n",indent.data(), numLoop); // write verts for (int i = 0; i < numLoop; i++) { Point3 v = mesh->verts[i]; float temp = v.z; v.z = -v.y; v.y = temp; v = matrix * v; fprintf(pStream, "%s\t%.6f;%.6f;%.6f;%s\n", indent.data(), v.x, v.y, v.z, i == numLoop - 1 ? ";\n" : ","); } // write number of faces numLoop = mesh->getNumFaces(); fprintf(pStream, "%s\t%d;\n", indent.data(), numLoop); // write faces for (i = 0; i < numLoop; i++) { fprintf(pStream, "%s\t3;%d,%d,%d;%s\n", indent.data(), mesh->faces[i].v[vx1], mesh->faces[i].v[vx2], mesh->faces[i].v[vx3], i == numLoop - 1 ? ";\n" : ","); } // face materials Mtl * nodeMtl = node->GetMtl(); int numMtls = !nodeMtl || !nodeMtl->NumSubMtls() ? 1 : nodeMtl->NumSubMtls(); // write face material list header fprintf(pStream, "%s\tMeshMaterialList {\n", indent.data()); // write number of materials fprintf(pStream, "%s\t\t%d;\n", indent.data(), numMtls); // write number of faces fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write face material indices (1 for each face) for (i = 0; i < numLoop; i++) { int index = numMtls ? mesh->faces[i].getMatID() % numMtls : 0; fprintf(pStream,"%s\t\t%d%s\n", indent.data(), index, i == numLoop - 1 ? ";\n" : ","); } // write the materials ExportMaterial( node, indentLevel+2); // verts close brace fprintf(pStream, "%s\t}\n\n",indent.data()); // write normals header fprintf(pStream, "%s\t%s {\n", indent.data(), "SI_MeshNormals"); // write number of normals fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop * 3); // write normals (3 for each face) for (i = 0; i < numLoop; i++) { Face * f = &mesh->faces[i]; int vert = f->getVert(vx1); Point3 vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); float temp = vn.z; vn.z = -vn.y; vn.y = temp; vn = rotMatrix * vn; fprintf(pStream,"%s\t\t%.6f;%.6f;%.6f;,\n", indent.data(), vn.x, vn.y, vn.z); vert = f->getVert(vx2); vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); temp = vn.z; vn.z = -vn.y; vn.y = temp; vn = rotMatrix * vn; fprintf(pStream,"%s\t\t%.6f;%.6f;%.6f;,\n", indent.data(), vn.x, vn.y, vn.z); vert = f->getVert(vx3); vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); temp = vn.z; vn.z = -vn.y; vn.y = temp; vn = rotMatrix * vn; fprintf(pStream,"%s\t\t%.6f;%.6f;%.6f;%s\n", indent.data(), vn.x, vn.y, vn.z, i == numLoop - 1 ? ";\n" : ","); } // write number of faces fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write faces for (i = 0; i < numLoop; i++) { fprintf(pStream, "%s\t\t%d;3;%d,%d,%d;%s\n", indent.data(), i, i * 3 + vx1, i * 3 + vx2, i * 3 + vx3, i == numLoop - 1 ? ";\n" : ","); } // normals close brace fprintf(pStream, "%s\t}\n\n",indent.data()); // texcoords if (nodeMtl && mesh && (nodeMtl->Requirements(-1) & MTLREQ_FACEMAP)) { // facemapping numLoop = mesh->getNumFaces() * 3; // write texture coords header fprintf(pStream, "%s\tSI_MeshTextureCoords {\n", indent.data()); // write number of texture coords fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write texture coords for (int i = 0; i < numLoop; i++) { Point3 tv[3]; Face * f = &mesh->faces[i]; make_face_uv( f, tv); fprintf(pStream, "%s\t\t%.6f;%.6f;,\n", indent.data(), tv[0].x, tv[0].y); fprintf(pStream, "%s\t\t%.6f;%.6f;,\n", indent.data(), tv[1].x, tv[1].y); fprintf(pStream, "%s\t\t%.6f;%.6f;%s\n", indent.data(), tv[2].x, tv[2].y, i == numLoop - 1 ? ";\n" : ","); } // write number of faces numLoop = mesh->getNumFaces(); fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write faces for (i = 0; i < numLoop; i++) { fprintf(pStream,"%s\t\t%d;3;%d,%d,%d;%s\n", indent.data(), i, mesh->tvFace[i].t[vx1], mesh->tvFace[i].t[vx2], mesh->tvFace[i].t[vx3], i == numLoop - 1 ? ";\n" : ","); } // texture coords close brace fprintf(pStream, "%s\t}\n\n", indent.data()); } else { numLoop = mesh->getNumTVerts(); if (numLoop) { // write texture coords header fprintf(pStream, "%s\tSI_MeshTextureCoords {\n", indent.data()); // write number of texture coords fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write texture coords for (i = 0; i < numLoop; i++) { UVVert tv = mesh->tVerts[i]; fprintf(pStream, "%s\t\t%.6f;%.6f;%s\n", indent.data(), tv.x, tv.y, i == numLoop - 1 ? ";\n" : ","); } // write number of faces numLoop = mesh->getNumFaces(); fprintf(pStream, "%s\t\t%d;\n", indent.data(), numLoop); // write faces for (i = 0; i < numLoop; i++) { fprintf(pStream,"%s\t\t%d;3;%d,%d,%d;%s\n", indent.data(), i, mesh->tvFace[i].t[vx1], mesh->tvFace[i].t[vx2], mesh->tvFace[i].t[vx3], i == numLoop - 1 ? ";\n" : ","); } // texture coords close brace fprintf(pStream, "%s\t}\n\n", indent.data()); } } /* // Export color per vertex info if (GetIncludeVertexColors()) { int numCVx = mesh->numCVerts; fprintf(pStream, "%s\t%s %d\n",indent.data(), ID_MESH_NUMCVERTEX, numCVx); if (numCVx) { fprintf(pStream,"%s\t%s {\n",indent.data(), ID_MESH_CVERTLIST); for (i=0; i<numCVx; i++) { Point3 vc = mesh->vertCol[i]; fprintf(pStream, "%s\t\t%s %d\t%s\n",indent.data(), ID_MESH_VERTCOL, i, Format(vc)); } fprintf(pStream,"%s\t}\n",indent.data()); fprintf(pStream, "%s\t%s %d\n",indent.data(), ID_MESH_NUMCVFACES, mesh->getNumFaces()); fprintf(pStream, "%s\t%s {\n",indent.data(), ID_MESH_CFACELIST); for (i=0; i<mesh->getNumFaces(); i++) { fprintf(pStream,"%s\t\t%s %d\t%d\t%d\t%d\n", indent.data(), ID_MESH_CFACE, i, mesh->vcFace[i].t[vx1], mesh->vcFace[i].t[vx2], mesh->vcFace[i].t[vx3]); } fprintf(pStream, "%s\t}\n",indent.data()); } } */ // Mesh close brace fprintf(pStream, "%s}\n",indent.data()); // dispose of tri object if (needDel) { delete tri; } }
bool CEditableMesh::Convert( INode *node ) { // prepares & checks BOOL bDeleteObj; bool bResult = true; TriObject *obj = ExtractTriObject( node, bDeleteObj ); if( !obj ){ ELog.Msg(mtError,"%s -> Can't convert to TriObject", node->GetName() ); return false; } if( obj->mesh.getNumFaces() <=0 ){ ELog.Msg(mtError,"%s -> There are no faces ?", node->GetName() ); if (bDeleteObj) delete (obj); return false; } Mtl *pMtlMain = node->GetMtl(); DWORD cSubMaterials=0; if (pMtlMain){ // There is at least one material. We're in case 1) or 2) cSubMaterials = pMtlMain->NumSubMtls(); if (cSubMaterials < 1){ // Count the material itself as a submaterial. cSubMaterials = 1; } } // build normals obj->mesh.buildRenderNormals(); // vertices m_VertCount = obj->mesh.getNumVerts(); m_Vertices = xr_alloc<Fvector>(m_VertCount); for (int v_i=0; v_i<m_VertCount; v_i++){ Point3* p = obj->mesh.verts+v_i; m_Vertices[v_i].set(p->x,p->y,p->z); } // set smooth group MAX type m_Flags.set(flSGMask,TRUE); // faces m_FaceCount = obj->mesh.getNumFaces(); m_Faces = xr_alloc<st_Face> (m_FaceCount); m_SmoothGroups = xr_alloc<u32> (m_FaceCount); m_VMRefs.reserve(m_FaceCount*3); if (0==obj->mesh.mapFaces(1)) { bResult = false; ELog.Msg(mtError,"'%s' hasn't UV mapping!", node->GetName()); } if (bResult) { CSurface* surf=0; for (int f_i=0; f_i<m_FaceCount; ++f_i) { Face* vf = obj->mesh.faces+f_i; TVFace* tf = obj->mesh.mapFaces(1) + f_i; if (!tf) { bResult = false; ELog.Msg(mtError,"'%s' hasn't UV mapping!", node->GetName()); break; } m_SmoothGroups[f_i] = vf->getSmGroup(); for (int k=0; k<3; ++k) { m_Faces[f_i].pv[k].pindex = vf->v[k]; m_VMRefs.push_back(st_VMapPtLst()); st_VMapPtLst& vm_lst = m_VMRefs.back(); vm_lst.count = 1; vm_lst.pts = xr_alloc<st_VMapPt>(vm_lst.count); for (DWORD vm_i=0; vm_i<vm_lst.count; ++vm_i) { vm_lst.pts[vm_i].vmap_index = 0; vm_lst.pts[vm_i].index = tf->t[k]; } m_Faces[f_i].pv[k].vmref = m_VMRefs.size()-1; if (!bResult) break; } if (pMtlMain) { int m_id = obj->mesh.getFaceMtlIndex(f_i); if (cSubMaterials == 1) { m_id = 0; }else { // SDK recommends mod'ing the material ID by the valid # of materials, // as sometimes a material number that's too high is returned. m_id %= cSubMaterials; } surf = m_Parent->CreateSurface(pMtlMain,m_id); if (!surf) bResult = false; } if (!bResult) break; m_SurfFaces[surf].push_back(f_i); } } // vmaps if( bResult ){ int vm_cnt = obj->mesh.getNumTVerts(); m_VMaps.resize(1); st_VMap*& VM = m_VMaps.back(); VM = xr_new<st_VMap>("Texture",vmtUV,false); for (int tx_i=0; tx_i<vm_cnt; tx_i++){ UVVert* tv = obj->mesh.tVerts + tx_i; VM->appendUV(tv->x,1-tv->y); } } if ((GetVertexCount()<4)||(GetFaceCount()<2)) { ELog.Msg(mtError,"Invalid mesh: '%s'. Faces<2 or Verts<4"); bResult = false; } if (bResult ){ ELog.Msg(mtInformation,"Model '%s' contains: %d points, %d faces", node->GetName(), m_VertCount, m_FaceCount); } if (bResult) { RecomputeBBox (); OptimizeMesh (false); RebuildVMaps (); ELog.Msg(mtInformation,"Model '%s' converted: %d points, %d faces", node->GetName(), GetVertexCount(), GetFaceCount()); } if (bDeleteObj) delete (obj); return bResult; }
static void extractTriangleGeometry( GmModel* gm, INode* node, Mesh* mesh, Mtl* material ) { #ifdef SGEXPORT_PHYSIQUE Modifier* phyMod = 0; IPhysiqueExport* phyExport = 0; IPhyContextExport* mcExport = 0; #endif Modifier* skinMod = 0; ISkin* skin = 0; String nodeName ( node->GetName() ); try { // vertex transform to left-handed system Matrix3 pivot = TmUtil::getPivotTransform( node ); Matrix3 vertexTM = pivot * s_convtm; bool insideOut = TmUtil::hasNegativeParity( pivot ); /*Matrix4x4 pm = TmUtil::toLH( vertexTM ); Debug::println( "Object {0} vertex local TM is", nodeName ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(0,0), pm(0,1), pm(0,2), pm(0,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(1,0), pm(1,1), pm(1,2), pm(1,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(2,0), pm(2,1), pm(2,2), pm(2,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(3,0), pm(3,1), pm(3,2), pm(3,3) );*/ // add vertex positions int vertices = mesh->getNumVerts(); for ( int vi = 0 ; vi < vertices ; ++vi ) { Point3 v = vertexTM * mesh->verts[vi]; mb::Vertex* vert = gm->addVertex(); vert->setPosition( v.x, v.y, v.z ); } // add vertex weights (from Physique modifier) #ifdef SGEXPORT_PHYSIQUE phyMod = PhyExportUtil::findPhysiqueModifier( node ); if ( phyMod ) { Debug::println( " Found Physique modifier: {0}", gm->name ); // get (possibly shared) Physique export interface phyExport = (IPhysiqueExport*)phyMod->GetInterface( I_PHYINTERFACE ); if( !phyExport ) throw Exception( Format("No Physique modifier export interface") ); // export from initial pose? phyExport->SetInitialPose( false ); // get (unique) context dependent export inteface mcExport = (IPhyContextExport*)phyExport->GetContextInterface( node ); if( !mcExport ) throw Exception( Format("No Physique modifier context export interface") ); // convert to rigid for time independent vertex assignment mcExport->ConvertToRigid( true ); // allow blending to export multi-link assignments mcExport->AllowBlending( true ); // list bones Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) ); PhyExportUtil::listBones( mcExport, bones ); // add vertex weight maps for ( int i = 0 ; i < bones.size() ; ++i ) { INode* bone = bones[i]; String name = bone->GetName(); mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT ); PhyExportUtil::addWeights( vmap, bone, mcExport ); } } #endif // SGEXPORT_PHYSIQUE // add vertex weights (from Skin modifier) skinMod = SkinExportUtil::findSkinModifier( node ); if ( skinMod ) { skin = (ISkin*)skinMod->GetInterface(I_SKIN); require( skin ); ISkinContextData* skincx = skin->GetContextInterface( node ); require( skincx ); Debug::println( " Found Skin modifier: {0} ({1} bones, {2} points)", gm->name, skin->GetNumBones(), skincx->GetNumPoints() ); if ( skincx->GetNumPoints() != gm->vertices() ) throw Exception( Format("Only some vertices ({0}/{1}) of {2} are skinned", skincx->GetNumPoints(), gm->vertices(), gm->name) ); // list bones Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) ); SkinExportUtil::listBones( skin, bones ); // add vertex weight maps for ( int i = 0 ; i < bones.size() ; ++i ) { INode* bone = bones[i]; String name = bone->GetName(); mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT ); SkinExportUtil::addWeights( vmap, bone, skin, skincx ); //Debug::println( " Bone {0} is affecting {1} vertices", name, vmap->size() ); } // DEBUG: print skin node tm and initial object tm /*Matrix3 tm; int ok = skin->GetSkinInitTM( node, tm ); require( ok == SKIN_OK ); Debug::println( " NodeInitTM of {0}", nodeName ); TmUtil::println( tm, 4 ); ok = skin->GetSkinInitTM( node, tm, true ); require( ok == SKIN_OK ); Debug::println( " NodeObjectTM of {0}", nodeName ); TmUtil::println( tm, 4 );*/ // DEBUG: print bones /*Debug::println( " bones of {0}:", nodeName ); for ( int i = 0 ; i < bones.size() ; ++i ) { Debug::println( " bone ({0}): {1}", i, String(bones[i]->GetName()) ); skin->GetBoneInitTM( bones[i], tm ); Debug::println( " InitNodeTM:" ); TmUtil::println( tm, 6 ); skin->GetBoneInitTM( bones[i], tm, true ); Debug::println( " InitObjectTM:" ); TmUtil::println( tm, 6 ); }*/ // DEBUG: print bones used by the points /*for ( int i = 0 ; i < skincx->GetNumPoints() ; ++i ) { int bonec = skincx->GetNumAssignedBones(i); Debug::println( " point {0} has {1} bones", i, bonec ); for ( int k = 0 ; k < bonec ; ++k ) { int boneidx = skincx->GetAssignedBone( i, k ); float w = skincx->GetBoneWeight( i, k ); Debug::println( " point {0} boneidx ({1}): {2}, weight {3}", i, k, boneidx, w ); } }*/ } // ensure clockwise polygon vertex order int vx[3] = {2,1,0}; if ( insideOut ) { int tmp = vx[0]; vx[0] = vx[2]; vx[2] = tmp; } // list unique materials used by the triangles Vector<ShellMaterial> usedMaterials( Allocator<ShellMaterial>(__FILE__,__LINE__) ); if ( material ) { for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; int mergesubmaterial = -1; int originalsubmaterial = -1; for ( int j = 0; j < material->NumSubMtls(); ++j) { // Get Sub Material Slot name TSTR name = material->GetSubMtlSlotName(j); // Light maps are stored in sub material slot named "Baked Material" if ( strcmp( name, "Baked Material" ) == 0 ) mergesubmaterial = j; else originalsubmaterial = j; } if ( mergesubmaterial != -1 ) // A baked material was found, shell materials will be created { Mtl* mat = material->GetSubMtl( originalsubmaterial ); Mtl* bakedmtl = material->GetSubMtl( mergesubmaterial ); if ( mat->NumSubMtls() > 0 ) // Check for nested multi-material { for ( int j = 0; j < mat->NumSubMtls(); ++j) usedMaterials.add( ShellMaterial( mat->GetSubMtl( face.getMatID() % mat->NumSubMtls() ), bakedmtl ) ); } else usedMaterials.add( ShellMaterial( mat, bakedmtl ) ); } else if ( material->NumSubMtls() > 0 ) // Multi-material without baked material { usedMaterials.add( ShellMaterial( material->GetSubMtl( face.getMatID() % material->NumSubMtls() ), 0 ) ); } else // Single material without baked material { usedMaterials.add( ShellMaterial( material, 0 ) ); } } std::sort( usedMaterials.begin(), usedMaterials.end() ); usedMaterials.setSize( std::unique( usedMaterials.begin(), usedMaterials.end() ) - usedMaterials.begin() ); } // create used materials for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi ) { ShellMaterial shellmtl = usedMaterials[mi]; gm->materials.add( GmUtil::createGmMaterial( shellmtl.original, shellmtl.baked ) ); } // add triangles for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { mb::Polygon* poly = gm->addPolygon(); // triangle indices Face& face = mesh->faces[fi]; for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; require( vi >= 0 && vi < gm->vertices() ); mb::Vertex* vert = gm->getVertex( vi ); poly->addVertex( vert ); } // triangle material int polyMaterialIndex = 0; if ( material ) { ShellMaterial mat( material, 0 ); int numsubmaterials = material->NumSubMtls(); if ( numsubmaterials > 0 ) { mat.original = material->GetSubMtl( face.getMatID() % material->NumSubMtls() ); for ( int j = 0; j < numsubmaterials; ++j) // Is baked material present? { TSTR name = material->GetSubMtlSlotName(j); if ( strcmp( name, "Baked Material" ) == 0 ) mat.baked = material->GetSubMtl( j ); if ( strcmp( name, "Original Material" ) == 0 ) mat.original = material->GetSubMtl( j ); } if ( mat.original->NumSubMtls() > 0 ) // Is there a nested multi-material? { mat.original = mat.original->GetSubMtl( face.getMatID() % mat.original->NumSubMtls() ); } } for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi ) { if ( usedMaterials[mi] == mat ) { polyMaterialIndex = mi; break; } } } poly->setMaterial( polyMaterialIndex ); } // add vertex colors int mp = 0; if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 ) { mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "rgb", mb::VertexMapFormat::VERTEXMAP_RGB ); int tverts = mesh->getNumMapVerts( mp ); UVVert* tvert = mesh->mapVerts( mp ); TVFace* tface = mesh->mapFaces( mp ); //Debug::println( "Vertex colors:" ); for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; mb::Polygon* poly = gm->getPolygon( fi ); for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; mb::Vertex* vert = gm->getVertex( vi ); Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ]; float rgb[3] = {tc.x, tc.y, tc.z}; vmad->addValue( vert->index(), poly->index(), rgb, 3 ); //Debug::println( " vertex[{0}].rgb: {1} {2} {3}", vert->index(), rgb[0], rgb[1], rgb[2] ); } } } // add texcoord layers int lastCoords = MAX_MESHMAPS-2; while ( lastCoords > 0 && (!mesh->mapSupport(lastCoords) || 0 == mesh->getNumMapVerts(lastCoords)) ) --lastCoords; if ( lastCoords > 8 ) throw IOException( Format("Too many texture coordinate sets ({1}) in {0}", gm->name, lastCoords) ); for ( mp = 1 ; mp <= lastCoords ; ++mp ) { mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 2, "uv", mb::VertexMapFormat::VERTEXMAP_TEXCOORD ); if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 ) { int tverts = mesh->getNumMapVerts( mp ); UVVert* tvert = mesh->mapVerts( mp ); TVFace* tface = mesh->mapFaces( mp ); for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; mb::Polygon* poly = gm->getPolygon( fi ); for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; mb::Vertex* vert = gm->getVertex( vi ); Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ]; float uv[2] = {tc.x, 1.f-tc.y}; vmad->addValue( vert->index(), poly->index(), uv, 2 ); } } } } // compute face vertex normals from smoothing groups require( mesh->getNumFaces() == gm->polygons() ); mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "vnormals", mb::VertexMapFormat::VERTEXMAP_NORMALS ); for ( int fi = 0 ; fi < gm->polygons() ; ++fi ) { mb::Polygon* poly = gm->getPolygon( fi ); require( poly ); require( poly->index() >= 0 && poly->index() < mesh->getNumFaces() ); Face& face = mesh->faces[ poly->index() ]; require( poly->vertices() == 3 ); for ( int j = 0 ; j < poly->vertices() ; ++j ) { Vector3 vn(0,0,0); mb::Vertex* vert = poly->getVertex( j ); // sum influencing normals for ( int k = 0 ; k < vert->polygons() ; ++k ) { mb::Polygon* vpoly = vert->getPolygon( k ); require( vpoly ); require( vpoly->index() >= 0 && vpoly->index() < mesh->getNumFaces() ); Face& vface = mesh->faces[ vpoly->index() ]; if ( 0 != (face.smGroup & vface.smGroup) || poly == vpoly ) { Vector3 vpolyn; vpoly->getNormal( &vpolyn.x, &vpolyn.y, &vpolyn.z ); vn += vpolyn; } } // normalize float lensqr = vn.lengthSquared(); if ( lensqr > Float::MIN_VALUE ) vn *= 1.f / Math::sqrt(lensqr); else vn = Vector3(0,0,0); vmad->addValue( vert->index(), poly->index(), vn.begin(), 3 ); } } // re-export mesh points in non-deformed pose if Skin modifier present // NOTE: 3ds Mesh must not be used after this, because collapsing can invalidate it if ( skin ) { // evaluate derived object before Skin modifier TimeValue time = 0; bool evalNext = false; bool evalDone = false; ::ObjectState os; ::Object* obj = node->GetObjectRef(); while ( obj->SuperClassID() == GEN_DERIVOB_CLASS_ID && !evalDone ) { IDerivedObject* derivedObj = static_cast<IDerivedObject*>(obj); for ( int modStack = 0 ; modStack < derivedObj->NumModifiers() ; ++modStack ) { if ( evalNext ) { os = derivedObj->Eval( time, modStack ); evalDone = true; break; } Modifier* mod = derivedObj->GetModifier(modStack); if ( mod->ClassID() == SKIN_CLASSID ) evalNext = true; } obj = derivedObj->GetObjRef(); } // evaluate possible non-derived object if ( evalNext && !evalDone ) { os = obj->Eval( time ); evalDone = true; } // convert to TriObject and get points if ( evalDone && os.obj->CanConvertToType( Class_ID(TRIOBJ_CLASS_ID,0) ) ) { Debug::println( " Evaluating object {0} before Skin modifier", nodeName ); // get TriObject std::auto_ptr<TriObject> triAutoDel(0); TriObject* tri = static_cast<TriObject*>( os.obj->ConvertToType( time, Class_ID(TRIOBJ_CLASS_ID,0) ) ); if ( tri != os.obj ) triAutoDel = std::auto_ptr<TriObject>( tri ); // get mesh points before Skin is applied //Debug::println( " Original collapsed mesh has {0} points, before Skin modifier {1} points", mesh->getNumVerts(), tri->mesh.getNumVerts() ); require( gm->vertices() == tri->mesh.getNumVerts() ); Mesh* mesh = &tri->mesh; int vertices = mesh->getNumVerts(); for ( int vi = 0 ; vi < vertices ; ++vi ) { Point3 v = vertexTM * mesh->verts[vi]; mb::Vertex* vert = gm->getVertex( vi ); vert->setPosition( v.x, v.y, v.z ); } } } // split vertices with discontinuous vertex map values for ( int vmi = 0 ; vmi < gm->discontinuousVertexMaps() ; ++vmi ) { mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap( vmi ); gm->splitVertexDiscontinuities( vmad ); } // find base texcoord layer mb::DiscontinuousVertexMap* texcoords = 0; for ( int i = 0 ; i < gm->discontinuousVertexMaps() ; ++i ) { mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap(i); if ( vmad->dimensions() == 2 && vmad->format() == mb::VertexMapFormat::VERTEXMAP_TEXCOORD ) { texcoords = vmad; break; } } if ( !texcoords ) Debug::printlnError( "Object {0} must have texture coordinates", gm->name ); // requires identification of footsteps in MySceneExport::isExportableGeometry //throw IOException( Format("Object {0} must have texture coordinates", gm->name) ); // optimize gm->removeUnusedVertices(); // cleanup export interfaces #ifdef SGEXPORT_PHYSIQUE if ( mcExport ) { require( phyExport ); phyExport->ReleaseContextInterface( mcExport ); mcExport = 0; } if ( phyExport ) { require( phyMod ); phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport ); phyExport = 0; } #endif // SGEXPORT_PHYSIQUE if ( skin ) { skinMod->ReleaseInterface( I_SKIN, skin ); skin = 0; skinMod = 0; } } catch ( ... ) { // cleanup export interfaces #ifdef SGEXPORT_PHYSIQUE if ( mcExport ) { require( phyExport ); phyExport->ReleaseContextInterface( mcExport ); mcExport = 0; } if ( phyExport ) { require( phyMod ); phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport ); phyExport = 0; } #endif // SGEXPORT_PHYSIQUE if ( skin ) { skinMod->ReleaseInterface( I_SKIN, skin ); skin = 0; skinMod = 0; } throw; } }
int DxStdMtl2::GetMatIndex(Mtl * m_Mtl) { int i; Mtl *Std; StdMat2 * Shader; // MaxShader *Shader, *s; if(m_Mtl->IsMultiMtl()) { Shader = (StdMat2 *)GetRefTarg(); // I use the SubAnims here, as I do not want any NULL material introduced that are not visible to the user // this can happen when you have N materials and you select N+1 mat ID - the material will add a NULL material // to the list to compensate - this screws with the index into the paramblock for(i=0; i < m_Mtl->NumSubs(); i++) { Std = (Mtl*)m_Mtl->SubAnim(i); if(Std!=NULL) { if(Std->NumSubMtls()>0) { for(int j=0; j< Std->NumSubMtls();j++) { Mtl * subMtl = Std->GetSubMtl(j); if(subMtl == Shader) Std = subMtl; } } MSPlugin* plugin = (MSPlugin*)((ReferenceTarget*)Std)->GetInterface(I_MAXSCRIPTPLUGIN); ReferenceTarget * targ = NULL; if(plugin){ targ = plugin->get_delegate(); Std = (Mtl*)targ; } if(Std == Shader) { int id=0; // this gets interesting - the MatID are editable !! must get them from the PAramblock IParamBlock2 * pblock = m_Mtl->GetParamBlock(0); // there is only one if(pblock) { ParamBlockDesc2 * pd = pblock->GetDesc(); for(int j=0;j<pd->count;j++) { if(_tcsicmp(_T("materialIDList"),pd->paramdefs[j].int_name)==0) //not localised { //int id; pblock->GetValue(j,0,id,FOREVER,i); id = id+1; //for some reason this is stored as a zero index, when a 1's based index is used } } pblock->ReleaseDesc(); } return(id); } } } } return(0); }
//================================================================= // 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 SceneBuilder::ConvertMaterial (Mtl &mtl, MtlTree &mtlTree) { // 光照属性 PX2::Shine *shine = new0 PX2::Shine; Color color = mtl.GetAmbient(); float alpha = 1.0f - mtl.GetXParency(); shine->Ambient = PX2::Float4(color.r, color.g, color.b, 1.0f); color = mtl.GetDiffuse(); shine->Diffuse = PX2::Float4(color.r, color.g, color.b, alpha); color = mtl.GetSpecular(); float shininess = mtl.GetShininess()*2.0f; shine->Specular = PX2::Float4(color.r, color.g, color.b, shininess); const char *name = (const char*)mtl.GetName(); shine->SetName(name); mtlTree.SetShine(shine); bool IsDirect9Shader = false; if (mtl.ClassID() == Class_ID(CMTL_CLASS_ID, 0) || mtl.ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { StdMat2 *stdMat2 = (StdMat2*)(&mtl); Interval valid = FOREVER; stdMat2->Update(mTimeStart, valid); std::string strName(stdMat2->GetName()); bool doubleSide = (stdMat2->GetTwoSided()==1); char strBitMapName[256]; memset(strBitMapName, 0, 256*sizeof(char)); std::string resourcePath; PX2::Shader::SamplerFilter filter = PX2::Shader::SF_LINEAR_LINEAR; PX2::Shader::SamplerCoordinate uvCoord = PX2::Shader::SC_REPEAT; PX2_UNUSED(uvCoord); if (stdMat2->MapEnabled(ID_DI)) { BitmapTex *tex = (BitmapTex*)stdMat2->GetSubTexmap(ID_DI); BitmapInfo bI; const char *mapName = tex->GetMapName(); TheManager->GetImageInfo(&bI, mapName); strcpy(strBitMapName, bI.Name()); std::string fullName = std::string(strBitMapName); std::string::size_type sizeT = fullName.find_first_not_of(mSettings->SrcRootDir); resourcePath = std::string(strBitMapName).substr(sizeT); StdUVGen* uvGen = tex->GetUVGen(); PX2_UNUSED(uvGen); int filType = tex->GetFilterType(); switch (filType) { case FILTER_PYR: filter = PX2::Shader::SF_LINEAR_LINEAR; break; case FILTER_SAT: filter = PX2::Shader::SF_NEAREST; break; default: break; } } else { sprintf(strBitMapName, "%s/%s", mSettings->SrcRootDir, PX2_DEFAULT_TEXTURE); resourcePath = PX2_DEFAULT_TEXTURE; } PX2::Texture2D *tex2d = PX2::DynamicCast<PX2::Texture2D>( PX2::ResourceManager::GetSingleton().BlockLoad(strBitMapName)); tex2d->SetResourcePath(resourcePath); if (tex2d) { PX2::Texture2DMaterial *tex2dMtl = new0 PX2::Texture2DMaterial(filter, uvCoord, uvCoord); if (doubleSide) { tex2dMtl->GetCullProperty(0, 0)->Enabled = false; } PX2::MaterialInstance *instance = tex2dMtl->CreateInstance(tex2d); mtlTree.SetMaterialInstance(instance); } else { PX2::VertexColor4Material *vcMtl = new0 PX2::VertexColor4Material(); PX2::MaterialInstance *instance = vcMtl->CreateInstance(); mtlTree.SetMaterialInstance(instance); } } else if (mtl.ClassID() == Class_ID(MULTI_CLASS_ID, 0)) { } else if (mtl.ClassID() == DIRECTX_9_SHADER_CLASS_ID) { IsDirect9Shader = true; IDxMaterial* dxMtl = (IDxMaterial*)mtl.GetInterface(IDXMATERIAL_INTERFACE); char *effectName = dxMtl->GetEffectFilename(); IParamBlock2 *paramBlock = mtl.GetParamBlock(0); std::string outPath; std::string outBaseName; std::string outExtention; PX2::StringHelp::SplitFullFilename(effectName, outPath, outBaseName, outExtention); PX2::ShinePtr shineStandard = new0 PX2::Shine(); bool alphaVertex = false; PX2::Texture2DPtr diffTex; bool normalEnable = false; PX2::Texture2DPtr normalTex; float normalScale = 0.0f; bool specEnable = false; PX2::Texture2DPtr specTex; float specPower = 0.0f; bool reflectEnable = false; PX2::TextureCubePtr reflectTex; float reflectPower = 0.0f; bool doubleSide = false; int blendMode = 2; ParamBlockDesc2 *paramDesc = 0; int numParam = 0; if (paramBlock) { paramDesc = paramBlock->GetDesc(); numParam = paramBlock->NumParams(); ParamType2 paramType; for (int i=0; i<numParam; i++) { std::string parmName; PX2::Float4 color4 = PX2::Float4(0.0f, 0.0f, 0.0f, 0.0f); PX2::Float3 color3 = PX2::Float3(0.0f, 0.0f, 0.0f); float floatValue = 0.0f; bool boolValue = false; float *floatTable = 0; int intValue = 0; std::string str; PX2::Texture2D *tex2d = 0; paramType = paramBlock->GetParameterType((ParamID)i); if (TYPE_STRING == paramType) ConvertStringAttrib(paramBlock, i, parmName, str); else if (TYPE_FLOAT == paramType) ConvertFloatAttrib(paramBlock, i, parmName, floatValue); else if (TYPE_INT == paramType) ConvertIntAttrib(paramBlock, i, parmName, intValue); else if (TYPE_RGBA == paramType) ConvertColorAttrib(paramBlock, i, parmName, color4, i); else if (TYPE_POINT3 == paramType) ConvertPoint3Attrib(paramBlock, i, parmName, color3); else if (TYPE_POINT4 == paramType) ConvertPoint4Attrib(paramBlock, i, parmName, color4); else if (TYPE_BOOL == paramType) ConvertBoolAttrib(paramBlock, i, parmName, boolValue); else if (TYPE_FLOAT_TAB == paramType) ConvertFloatTabAttrib(paramBlock, i, parmName, floatTable); else if (TYPE_BITMAP == paramType) ConvertBitMapAttrib(paramBlock, i, parmName, tex2d); else if (TYPE_FRGBA ==paramType) ConvertFRGBAAttrib(paramBlock, i, parmName, color4); // shine if (parmName == "gBlendMode") { blendMode = intValue; } else if (parmName == "gShineEmissive") { shineStandard->Emissive = color4; } else if (parmName == "gShineAmbient") { shineStandard->Ambient = color4; } else if (parmName == "gShineDiffuse") { shineStandard->Diffuse = color4; } // alpha vertex else if (parmName == "gAlphaVertex") { alphaVertex = boolValue; } // diffuse else if (parmName == "gDiffuseTexture") { diffTex = tex2d; } // normal else if (parmName == "gNormalEnable") { normalEnable = boolValue; } else if (parmName == "gNormalTexture") { normalTex = tex2d; } else if (parmName == "gNormalScale") { normalScale = floatValue; } // specular else if (parmName == "gSpecularEnable") { specEnable = boolValue; } else if (parmName == "gSpecularTexture") { specTex = tex2d; } else if (parmName == "gSpecularPower") { specPower = floatValue; } // reflect else if (parmName == "gReflectionEnable") { reflectEnable = boolValue; } else if (parmName == "gReflectTexture") { //reflectTex = tex2d; } else if (parmName == "gReflectPower") { reflectPower = floatValue; } // other else if (parmName == "gDoubleSide") { doubleSide = boolValue; } } } PX2::MaterialInstance *inst = 0; PX2::StandardMaterial *standardMtl = 0; PX2::StandardESMaterial_Default *standardESMtl_D = 0; PX2::StandardESMaterial_Specular *standardESMtl_S = 0; if (outBaseName == "Standard") { char mtlName[256]; memset(mtlName, 0, 256*sizeof(char)); sprintf(mtlName, "%s/%s", mSettings->DstRootDir, "Data/mtls/Standard.pxfx"); standardMtl = new0 PX2::StandardMaterial(mtlName); } else if (outBaseName == "StandardES") { if (false == specEnable) { standardESMtl_D = new0 PX2::StandardESMaterial_Default(); if (0 == blendMode) { standardESMtl_D->GetAlphaProperty(0, 0)->BlendEnabled = false; standardESMtl_D->GetAlphaProperty(0, 0)->CompareEnabled = false; } else if (1 == blendMode) { standardESMtl_D->GetAlphaProperty(0, 0)->BlendEnabled = true; } else if (2 == blendMode) { standardESMtl_D->GetAlphaProperty(0, 0)->BlendEnabled = false; standardESMtl_D->GetAlphaProperty(0, 0)->CompareEnabled = true; standardESMtl_D->GetAlphaProperty(0, 0)->Compare = PX2::AlphaProperty::CM_GEQUAL; standardESMtl_D->GetAlphaProperty(0, 0)->Reference = 0.2f; } } else { char mtlName[256]; memset(mtlName, 0, 256*sizeof(char)); sprintf(mtlName, "%s/%s", mSettings->DstRootDir, "Data/mtls/StandardES_Specular.pxfx"); standardESMtl_S = new0 PX2::StandardESMaterial_Specular(mtlName); } } if (standardMtl && diffTex) { if (doubleSide) { standardMtl->GetCullProperty(0, 0)->Enabled = false; } inst = standardMtl->CreateInstance(diffTex, alphaVertex, normalEnable, normalTex, normalScale, specEnable, specTex, specPower, 0, shineStandard); } else if (standardESMtl_D && diffTex) { if (doubleSide) { standardESMtl_D->GetCullProperty(0, 0)->Enabled = false; } inst = standardESMtl_D->CreateInstance(diffTex, 0, shineStandard); } else if (standardESMtl_S && diffTex && specTex) { if (doubleSide) { standardESMtl_S->GetCullProperty(0, 0)->Enabled = false; } inst = standardESMtl_S->CreateInstance(diffTex, specTex, specPower, 0, shineStandard); } if (inst) { mtlTree.SetMaterialInstance(inst); } else { PX2::MaterialInstance *instance = PX2::VertexColor4Material::CreateUniqueInstance(); mtlTree.SetMaterialInstance(instance); } } else { PX2::VertexColor4Material *vcMtl = new0 PX2::VertexColor4Material(); PX2::MaterialInstance *instance = vcMtl->CreateInstance(); mtlTree.SetMaterialInstance(instance); } // 对子材质进行处理 if (IsDirect9Shader) return; int mQuantity = mtl.NumSubMtls(); // Class_ID(MULTI_CLASS_ID, 0) if (mQuantity > 0) { mtlTree.SetMChildQuantity(mQuantity); for (int i=0; i<mQuantity; i++) { Mtl *subMtl = 0; subMtl = mtl.GetSubMtl(i); if (subMtl) { ConvertMaterial(*subMtl, mtlTree.GetMChild(i)); } } } }
RefResult PFOperatorMaterialFrequency::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message) { IParamMap2* map; TSTR dynamicNameSuffix; if ( hTarget == pblock() ) { int lastUpdateID; switch (message) { case REFMSG_CHANGE: lastUpdateID = pblock()->LastNotifyParamID(); if (lastUpdateID == kMaterialFrequency_material) { if (updateFromMXSMtl()) { NotifyDependents(FOREVER, PART_MTL, kPFMSG_UpdateMaterial, NOTIFY_ALL, TRUE); NotifyDependents(FOREVER, 0, kPFMSG_DynamicNameChange, NOTIFY_ALL, TRUE); } UpdatePViewUI(lastUpdateID); return REF_STOP; } if (!(theHold.Holding() || theHold.RestoreOrRedoing())) return REF_STOP; switch ( lastUpdateID ) { case kMaterialFrequency_assignMaterial: RefreshUI(kMaterialFrequency_message_assignMaterial); NotifyDependents(FOREVER, PART_MTL, kPFMSG_UpdateMaterial, NOTIFY_ALL, TRUE); break; case kMaterialFrequency_assignID: RefreshUI(kMaterialFrequency_message_assignID); break; } UpdatePViewUI(lastUpdateID); break; case REFMSG_NODE_WSCACHE_UPDATED: updateFromRealMtl(); break; // Initialization of Dialog case kMaterialFrequency_RefMsg_InitDlg: // Set ICustButton properties for MaterialFrequency DAD button map = (IParamMap2*)partID; if (map != NULL) { HWND hWnd = map->GetHWnd(); if (hWnd) { ICustButton *iBut = GetICustButton(GetDlgItem(hWnd, IDC_MATERIAL)); iBut->SetDADMgr(_dadMgr()); ReleaseICustButton(iBut); } } // Refresh UI RefreshUI(kMaterialFrequency_message_assignMaterial); RefreshUI(kMaterialFrequency_message_numSubMtls); RefreshUI(kMaterialFrequency_message_assignID); return REF_STOP; // New Random Seed case kMaterialFrequency_RefMsg_NewRand: theHold.Begin(); NewRand(); theHold.Accept(GetString(IDS_NEWRANDOMSEED)); return REF_STOP; } } if ( hTarget == const_cast <Mtl*> (material()) ) { switch (message) { case REFMSG_CHANGE: { if (pblock() != NULL) { Mtl* curMtl = pblock()->GetMtl(kMaterialFrequency_material); int curNumSubs = (curMtl != NULL) ? curMtl->NumSubMtls() : 0; if (curNumSubs != lastNumSubs()) { _lastNumSubs() = curNumSubs; RefreshUI(kMaterialFrequency_message_numSubMtls); } } } return REF_STOP; // if (ignoreRefMsgNotify()) return REF_STOP; // if (!(theHold.Holding() || theHold.RestoreOrRedoing())) return REF_STOP; break; case REFMSG_NODE_NAMECHANGE: if (HasDynamicName(dynamicNameSuffix)) { if (lastDynamicName() != dynamicNameSuffix) { _lastDynamicName() = dynamicNameSuffix; NotifyDependents(FOREVER, 0, kPFMSG_DynamicNameChange, NOTIFY_ALL, TRUE); UpdatePViewUI(kMaterialFrequency_material); } } return REF_STOP; case REFMSG_TARGET_DELETED: _material() = NULL; if (pblock() != NULL) pblock()->SetValue(kMaterialFrequency_material, 0, NULL); if (theHold.Holding()) { if (HasDynamicName(dynamicNameSuffix)) { if (lastDynamicName() != dynamicNameSuffix) { _lastDynamicName() = dynamicNameSuffix; NotifyDependents(FOREVER, 0, kPFMSG_DynamicNameChange, NOTIFY_ALL, TRUE); UpdatePViewUI(kMaterialFrequency_material); } } } break; } } return REF_SUCCEED; }