void Exporter::ExportMesh(INode* node, TimeValue t, int indentLevel) { int i; Mtl* nodeMtl = node->GetMtl(); Matrix3 tm = node->GetObjTMAfterWSM(t); BOOL negScale = TMNegParity(tm); int vx1, vx2, vx3; TSTR indent; ObjectState os = node->EvalWorldState(t); if (!os.obj || os.obj->SuperClassID()!=GEOMOBJECT_CLASS_ID) { return; // Safety net. This shouldn't happen. } // Order of the vertices. Get 'em counter clockwise if the objects is // negatively scaled. if (negScale) { vx1 = 2; vx2 = 1; vx3 = 0; } else { vx1 = 0; vx2 = 1; vx3 = 2; } BOOL needDel; TriObject* tri = GetTriObjectFromNode(node, t, needDel); if (!tri) { return; } Mesh* mesh = &tri->mesh; mesh->buildNormals(); { // make vertices and faces rsm->mesh->nV=mesh->getNumVerts(); rsm->mesh->nF=mesh->getNumFaces(); rsm->mesh->ver=new rvertex[mesh->getNumVerts()]; rsm->mesh->face=new rface[mesh->getNumFaces()]; } // Export the vertices for (i=0; i<mesh->getNumVerts(); i++) { Point3 v = tm * mesh->verts[i]; rsm->mesh->ver[i].coord=rvector(v); rsm->mesh->ver[i].normal=rvector(0,0,0); } // To determine visibility of a face, get the vertices in clockwise order. // If the objects has a negative scaling, we must compensate for that by // taking the vertices counter clockwise for (i=0; i<mesh->getNumFaces(); i++) { rsm->mesh->face[i].a=(WORD)mesh->faces[i].v[vx1]; rsm->mesh->face[i].c=(WORD)mesh->faces[i].v[vx2]; rsm->mesh->face[i].b=(WORD)mesh->faces[i].v[vx3]; rsm->mesh->face[i].nMaterial=mesh->faces[i].getMatID(); } // Export face map texcoords if we have them... if (!CheckForAndExportFaceMap(nodeMtl, mesh, indentLevel+1)) { // If not, export standard tverts int numTVx = mesh->getNumTVerts(); if (numTVx) { rface *f=rsm->mesh->face; for (i=0; i<mesh->getNumFaces(); i++) { // dubble added TVFace *tvf=&mesh->tvFace[i]; f->u[0]=mesh->tVerts[tvf->t[vx1]].x; f->v[0]=1.0f-mesh->tVerts[tvf->t[vx1]].y; f->u[2]=mesh->tVerts[tvf->t[vx2]].x; f->v[2]=1.0f-mesh->tVerts[tvf->t[vx2]].y; f->u[1]=mesh->tVerts[tvf->t[vx3]].x; f->v[1]=1.0f-mesh->tVerts[tvf->t[vx3]].y; // good f++; // end of dubble added } } } { // Export mesh (face + vertex) normals Point3 fn; // Face normal Point3 vn; // Vertex normal int vert; Face* f; // Face and vertex normals. // In MAX a vertex can have more than one normal (but doesn't always have it). // This is depending on the face you are accessing the vertex through. // To get all information we need to export all three vertex normals // for every face. Matrix3 pivot = node->GetNodeTM(GetStaticFrame()); pivot.NoTrans(); for (i=0; i<mesh->getNumFaces(); i++) { f = &mesh->faces[i]; fn = mesh->getFaceNormal(i); rsm->mesh->face[i].normal=fn; vert = f->getVert(vx1); vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); rsm->mesh->face[i].vnormals[0]=pivot*vn; rsm->mesh->ver[rsm->mesh->face[i].a].normal+=vn; vert = f->getVert(vx2); vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); rsm->mesh->face[i].vnormals[2]=pivot*vn; rsm->mesh->ver[rsm->mesh->face[i].b].normal+=vn; vert = f->getVert(vx3); vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(vert)); rsm->mesh->face[i].vnormals[1]=pivot*vn; rsm->mesh->ver[rsm->mesh->face[i].c].normal+=vn; } } if (needDel) { delete tri; } }
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; } }
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId) { // check for valid mesh and physique modifier if((m_pIMesh == 0)) { theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__); return 0; } // check if face id is valid if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces())) { theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__); return 0; } // check if face vertex id is valid if((faceVertexId < 0) || (faceVertexId >= 3)) { theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__); return 0; } // allocate a new vertex candidate CVertexCandidate *pVertexCandidate; pVertexCandidate = new CVertexCandidate(); if(pVertexCandidate == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); return 0; } // create the new vertex candidate if(!pVertexCandidate->Create()) { delete pVertexCandidate; return 0; } // get vertex id int vertexId; vertexId = m_pIMesh->faces[faceId].v[faceVertexId]; // get the absolute vertex position Point3 vertex; vertex = m_pIMesh->getVert(vertexId) * m_tm; // set the vertex candidate position pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z); pVertexCandidate->SetUniqueId(vertexId); // get the absolute vertex normal Point3 normal; normal = GetVertexNormal(faceId, vertexId); normal = normal * Inverse(Transpose(m_tm)); normal = normal.Normalize(); // set the vertex candidate normal pVertexCandidate->SetNormal(normal.x, normal.y, normal.z); if(m_pIMesh->numCVerts > 0) { VertColor vc; vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]]; CalVector vcCal(vc.x, vc.y, vc.z); pVertexCandidate->SetVertColor(vcCal); } // get the vertex weight array float *pVertexWeights; pVertexWeights = m_pIMesh->getVertexWeights(); //if( pVertexWeights == NULL ) { // delete pVertexCandidate; // theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__); // return 0; //} // get the vertex weight (if possible) float weight; if(pVertexWeights != 0) { weight = pVertexWeights[vertexId]; } else { weight = 0.0f; } // another 3ds max weird behaviour: // zero out epsilon weights if(weight < 0.0005f) weight = 0.0f; // set the vertex candidate weight pVertexCandidate->SetPhysicalProperty(weight); // get the material id of the face int materialId; materialId = GetFaceMaterialId(faceId); if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size())) { delete pVertexCandidate; theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__); return 0; } // get the material of the face StdMat *pStdMat; pStdMat = m_vectorStdMat[materialId]; // loop through all the mapping channels and extract texture coordinates int mapId; for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++) { // get texture map Texmap *pTexMap; pTexMap = pStdMat->GetSubTexmap(mapId); // check if map is valid if((pTexMap != 0) && (pStdMat->MapEnabled(mapId))) { // get the mapping channel int channel; channel = pTexMap->GetMapChannel(); bool bValidUV; bValidUV = false; // extract the texture coordinate UVVert uvVert; if(m_pIMesh->mapSupport(channel)) { TVFace *pTVFace; pTVFace = m_pIMesh->mapFaces(channel); UVVert *pUVVert; pUVVert = m_pIMesh->mapVerts(channel); uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]]; bValidUV = true; } else if(m_pIMesh->numTVerts > 0) { uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]]; bValidUV = true; } // if we found valid texture coordinates, add them to the vertex candidate if(bValidUV) { // apply a possible uv generator StdUVGen *pStdUVGen; pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen(); if(pStdUVGen != 0) { Matrix3 tmUV; pStdUVGen->GetUVTransform(tmUV); uvVert = uvVert * tmUV; } // add texture coordinate to the vertex candidate, inverting the y coordinate pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y); } } } // check for physique modifier if(m_modifierType == MODIFIER_PHYSIQUE) { // create a physique export interface IPhysiqueExport *pPhysiqueExport; pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == 0) { delete pVertexCandidate; theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__); return 0; } // create a context export interface IPhyContextExport *pContextExport; pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode); if(pContextExport == 0) { m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__); return 0; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport; pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId); if(pVertexExport == 0) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__); return 0; } // get the vertex type int vertexType; vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex; pTypeVertex = (IPhyRigidVertex *)pVertexExport; // add the influence to the vertex candidate // get the influencing bone if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f)) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex; pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId))) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } #if MAX_RELEASE >= 4000 // check for skin modifier else if(m_modifierType == MODIFIER_SKIN) { // create a skin interface ISkin *pSkin; pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN); if(pSkin == 0) { delete pVertexCandidate; theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__); return 0; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode); if(pSkinContextData == 0) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__); return 0; } // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++) { // get the bone id int boneId; boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId); if(boneId < 0) continue; // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId))) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } // release all interfaces m_pModifier->ReleaseInterface(I_SKIN, pSkin); } #endif else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) { } else { theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__); return 0; } return pVertexCandidate; }
void CSMFRenderer::DrawSquare(RSquare& q, const vec3f& v, const CReadMap* rm, const float* hm) { const float d = v.flen2D() - 0.01f; const int xshift = GetXLOD(d, viewRadius, squareSizeX, lodDists); const int zshift = GetZLOD(d, viewRadius, squareSizeZ, lodDists); const int xlod = (1 << xshift); const int zlod = (1 << zshift); const int xverts = (squareSizeX / xlod) + 1; // #vertices in the x-direction for this square const int zverts = (squareSizeZ / zlod) + 1; // #vertices in the z-direction for this square const int numQuads = (xverts - 1) * (zverts - 1); // #quads needed to cover square at wanted LOD const bool wantList = (xlod == 1 && zlod == 1); // highest-LOD squares are rendered from dlists int vertex = 0; int offset = 0; const float r = 1.0f - (xshift * 0.1667f), g = 0.333f, b = (zshift * 0.1667f); glColor3f(r, g, b); if (q.hasDisLst && wantList) { // note: for deformable terrain, the list // would possibly need to be invalidated glCallList(q.disLstID); } else { if (!q.hasDisLst && wantList) { q.disLstID = glGenLists(1); glNewList(q.disLstID, GL_COMPILE); } va.Initialize(); va.EnlargeArrays(numQuads * 4, 0, VA_SIZE_N); // note: LESS OR EQUAL, so that when {x, z}lod == squareSize{X, Z} // four vertices (two in each direction) are added instead of one for (int x = 0; x <= squareSizeX; x += xlod) { for (int z = 0; z <= squareSizeZ; z += zlod) { vec3f tl(q.tlp.x + x, 0.0f, q.tlp.z + z); tl.y = GetHeight(hm, tl.x, tl.z); vec3f nv = GetVertexNormal(hm, q, tl, rm->maxxpos, rm->maxzpos, x, xlod, z, zlod); va.AddVertexN(tl, nv); // the bottom- and right-most row and column // of vertices do not define any new quads // if ((x < squareSizeX && z < squareSizeZ)) { if (!(x & squareSizeX) && !(z & squareSizeZ)) { indices[offset++] = vertex + 0; // tl indices[offset++] = vertex + zverts; // tr indices[offset++] = vertex + zverts + 1; // br indices[offset++] = vertex + 1; // bl } vertex++; } } /// FIXME: add indexed drawing to VA class /// va.Draw(numQuads, indices); va.DrawArrayN(GL_QUADS); if (!q.hasDisLst && wantList) { q.hasDisLst = true; glEndList(); } } glColor3f(1.0f, 1.0f, 1.0f); }
//---------------------------------------------------------------------------- void SceneBuilder::SplitGeometry(Mesh *maxMesh, int mtlIndex, std::vector<UniMaterialMesh*> &uMeshes) { // 如果这个Mesh有多个material并且使用两个或者多个material。这个网格需要 // 被拆分,因为Phoenix2是一个物体只对应一个material。 // // maxMesh: // 要分割的Max网格。 // mtlIndex: // 材质ID // uMeshes: // UniMaterialMesh集合,Max的mesh被拆分后放里面。 int i, j; PX2::Float3 *normalsAll = 0; if (mSettings->IncludeNormals) { maxMesh->buildNormals(); normalsAll = new1<PX2::Float3>(maxMesh->numVerts); for (i=0; i<maxMesh->numFaces; i++) { Face &face = maxMesh->faces[i]; for (j=0; j<3; j++) { int vertexIndex = face.getVert(j); normalsAll[vertexIndex] = GetVertexNormal(maxMesh, i, vertexIndex); } } } // 没有材质 if (mtlIndex < 0) { UniMaterialMesh *triMesh = new0 UniMaterialMesh; triMesh->SetMaterialInstance(PX2::VertexColor4Material::CreateUniqueInstance()); std::vector<int> faceIndexs; int faceIndex = -1; for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { faceIndexs.push_back(faceIndex); } PackVertices(triMesh, maxMesh, faceIndexs, normalsAll); if (mSettings->IncludeVertexColors && maxMesh->numCVerts>0) { PackColors(triMesh, maxMesh, faceIndexs); } if (mSettings->IncludeTargentBiNormal && maxMesh->numTVerts>0) { triMesh->SetExportTargentBinormal(true); } else { triMesh->SetExportTargentBinormal(false); } if (mSettings->IncludeTexCoords && maxMesh->numTVerts>0) { triMesh->SetNumTexcoordToExport(mSettings->NumTexCoords); PackTextureCoords(triMesh, maxMesh, faceIndexs); } uMeshes.push_back(triMesh); triMesh->DuplicateGeometry(); } else { // 获得Mtl的子材质数量 MtlTree &tree = mMtlTreeList[mtlIndex]; int subQuantity = 0; // 子材质数量 if (mtlIndex >= 0) { subQuantity = tree.GetMChildQuantity(); } // 计算几何图形所使用的最大附加材质索引 int faceIndex, subID, maxSubID = -1; for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { subID = maxMesh->faces[faceIndex].getMatID(); if (subID >= subQuantity) { if (subQuantity > 0) { subID = subID % subQuantity; } else { subID = 0; } } if (subID > maxSubID) { maxSubID = subID; } } if (-1 != maxSubID) { // 根据material ID,将每个三角形面分类 std::vector<int> *faceIndexPartByMtl = new1<std::vector<int> >(maxSubID+1); for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { subID = maxMesh->faces[faceIndex].getMatID(); if (subID >= subQuantity) { if (subQuantity > 0) { subID = subID % subQuantity; } else { subID = 0; } } // 将每个面按照材质分类 faceIndexPartByMtl[subID].push_back(faceIndex); } // 对每种材质类型,分配网格 for (subID=0; subID<=maxSubID; subID++) { if (faceIndexPartByMtl[subID].size() == 0) { // 这种材质没有三角形面 continue; } // 为每种材质新建一个mesh UniMaterialMesh *triMesh = new0 UniMaterialMesh; if (mtlIndex >= 0) { if (subQuantity > 0) { MtlTree &subtree = tree.GetMChild(subID); triMesh->SetShineProperty(subtree.GetShine()); triMesh->SetMaterialInstance(subtree.GetMaterialInstance()); } else { triMesh->SetShineProperty(tree.GetShine()); triMesh->SetMaterialInstance(tree.GetMaterialInstance()); } } PackVertices(triMesh, maxMesh, faceIndexPartByMtl[subID], normalsAll); if (mSettings->IncludeVertexColors && maxMesh->numCVerts>0) { PackColors(triMesh, maxMesh, faceIndexPartByMtl[subID]); } if (mSettings->IncludeTargentBiNormal && maxMesh->numTVerts>0) { triMesh->SetExportTargentBinormal(true); } else { triMesh->SetExportTargentBinormal(false); } triMesh->SetExportSkin(mSettings->IncludeSkins); if (mSettings->IncludeTexCoords && maxMesh->numTVerts>0) { triMesh->SetNumTexcoordToExport(mSettings->NumTexCoords); PackTextureCoords(triMesh, maxMesh, faceIndexPartByMtl[subID]); } uMeshes.push_back(triMesh); } delete1(faceIndexPartByMtl); } for (i=0; i<(int)uMeshes.size(); i++) { uMeshes[i]->DuplicateGeometry(); } } delete1(normalsAll); }
/* int MshExp::ExportMeshTiles(Interface* ip,INode* node,TimeValue t_start,TimeValue t_end,int tiles_count) { // Get animation range Interval animRange = ip->GetAnimRange(); TimeValue curtime; curtime = animRange.Start(); } */ int MshExp::ExportMesh(const TCHAR *filename,Interface* i,INode* node,TimeValue curtime) { char buf[4096]; void* cur=buf; void* end=buf+sizeof(buf); // Verifie les arguments if(node==0){ NP_LOG("ExportMesh: !node"); return 0; } /*----------------------------------------------------- Obtient l'objet Mesh -----------------------------------------------------*/ // Frame a exporter if(curtime<0) curtime = i->GetTime(); // Obtient la matrice de transformation Matrix3 tm = TransformNode(node,curtime,this->exportTransform); // Evalue l'objet a partir du noeud ObjectState os = node->EvalWorldState(curtime); if(!os.obj || os.obj->SuperClassID()!=GEOMOBJECT_CLASS_ID){ NP_LOG("ExportMesh: !ObjectState"); return 0; } Interval objRange = os.obj->ObjectValidity(curtime); // convertie l'objet en Tiangles BOOL needDel; TriObject* tri = GetTriObjectFromNode(node, curtime, needDel); if (!tri) { NP_LOG("ExportMesh: !TriObject"); return 0; } // obtient le maillage Mesh* mesh = &tri->GetMesh(); // obtient le nombre de points uint npoint=(uint)mesh->getNumVerts(); // construit les normals mesh->buildNormals(); // obtient le nombre de faces uint nfaces=(uint)mesh->getNumFaces(); //Supprime l'objet TriObject, si necessaire if(needDel) { delete tri; } /*----------------------------------------------------- Exporte les triangles -----------------------------------------------------*/ //Obtient la matrice de transformation tm = TransformNode(node,curtime,this->exportTransform); // Evalue l'objet a partir du node os = node->EvalWorldState(curtime); objRange = os.obj->ObjectValidity(curtime); // convertie l'objet en Tiangles tri = GetTriObjectFromNode(node, curtime, needDel); if (!tri) { NP_LOG("ExportMesh: !TriObject"); return 0; } // obtient le maillage mesh = &tri->GetMesh(); // construit les normals mesh->buildNormals(); // copie les faces for(uint y=0; y<nfaces; y++) { Face* face; uint facenumber=0;//numero de la face dans l'index du maillage 3DS //obtient la face en cours face = &mesh->faces[y]; facenumber = y; ////////////////////////////////////////////// // Definit les 3 points de la face ////////////////////////////////////////////// for(uint w=0;w<3;w++) { if((cur = descWriteText(cur,end,"point")==0) return 0; Point3 pos; Point3 nml; Point3 clr; UVVert tex; uint nvertex; // obtient le point nvertex = face->v[w]; pos = tm * mesh->verts[nvertex]; float point[3]={pos.x,pos.y,pos.z}; if((cur = descWriteStruct(cur,end,Point3_t,sizeof(Point3_t)/sizeof(Point3_t[0]),&point))==0) return 0; // obtient les normals nvertex = face->getVert(w); nml = GetVertexNormal(mesh, face, mesh->getRVertPtr(nvertex)); float normal[3]={nml.x,nml.y,nml.z}; if((cur = descWriteStruct(cur,end,Normal_t,sizeof(Normal_t)/sizeof(Normal_t[0]),&normal))==0) return 0; // obtient les coordonnees de texture if(mesh->tvFace){ nvertex = mesh->tvFace[facenumber].t[w]; tex = mesh->tVerts[nvertex]; float textureMap[3]={tex.x,tex.y,tex.z}; if((cur = descWriteStruct(cur,end,TextureMap_t,sizeof(TextureMap_t)/sizeof(TextureMap_t[0]),&textureMap))==0) return 0; } // obtient la couleur if(mesh->vcFace){ nvertex = mesh->vcFace[facenumber].t[w]; clr = mesh->vertCol[nvertex]; float color[3]={clr.x,clr.y,clr.z}; if((cur = descWriteStruct(cur,end,Color_t,sizeof(Color_t)/sizeof(Color_t[0]),&color))==0) return 0; } } } //Supprime l'objet TriObject, si necessaire if(needDel) { delete tri; } /* ecrit les donnees de la structure */ if(!fileWrite(filename,0,buf,(char*)cur)) return 0; NP_LOG("done"); return 1; }