void NifImporter::SetNormals(Mesh& mesh, const vector<Niflib::Triangle>& tris, const vector<Niflib::Vector3>& n) { mesh.checkNormals(TRUE); if (n.size() > 0) { bool needNormals = false; for (unsigned int i=0; i<n.size(); i++){ Vector3 v = n[i]; Point3 norm(v.x, v.y, v.z); if (norm != mesh.getNormal(i)) { needNormals = true; break; } } if (needNormals) { #if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 5 mesh.SpecifyNormals(); MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->ClearAndFree(); specNorms->SetNumFaces(tris.size()); specNorms->SetNumNormals(n.size()); Point3* norms = specNorms->GetNormalArray(); for (unsigned int i=0; i<n.size(); i++){ Vector3 v = n[i]; norms[i] = Point3(v.x, v.y, v.z); } MeshNormalFace* pFaces = specNorms->GetFaceArray(); for (unsigned int i=0; i<tris.size(); i++){ const Triangle& tri = tris[i]; pFaces[i].SpecifyNormalID(0, tri.v1); pFaces[i].SpecifyNormalID(1, tri.v2); pFaces[i].SpecifyNormalID(2, tri.v3); } #if VERSION_3DSMAX > ((7000<<16)+(15<<8)+0) // Version 7+ specNorms->SetAllExplicit(true); #else for (int i=0; i<specNorms->GetNumNormals(); ++i) { specNorms->SetNormalExplicit(i, true); } #endif specNorms->CheckNormals(); } #endif } } }
void SymmetryMod::ModifyTriObject (TimeValue t, ModContext &mc, TriObject *tobj, INode *inode) { Mesh &mesh = tobj->GetMesh(); Interval iv = FOREVER; int axis, slice, weld, flip; float threshold; mp_pblock->GetValue (kSymAxis, t, axis, iv); mp_pblock->GetValue (kSymFlip, t, flip, iv); mp_pblock->GetValue (kSymSlice, t, slice, iv); mp_pblock->GetValue (kSymWeld, t, weld, iv); mp_pblock->GetValue (kSymThreshold, t, threshold, iv); if (threshold<0) threshold=0; // Get transform from mirror controller: Matrix3 tm = CompMatrix (t, NULL, &mc, &iv); Matrix3 itm = Inverse (tm); // Get DotProd(N,x)=offset plane definition from transform Point3 Axis(0,0,0); Axis[axis] = flip ? -1.0f : 1.0f; Point3 origin = tm.GetTrans(); Point3 N = Normalize(tm*Axis - origin); float offset = DotProd (N, origin); // Slice operation does not handle NormalSpecs, but it handles mapping channels. // move our mesh normal data to a map channel MeshNormalSpec *pNormals = mesh.GetSpecifiedNormals (); int normalMapChannel = INVALID_NORMALMAPCHANNEL; if (pNormals && pNormals->GetNumFaces()) { pNormals->SetParent(&mesh); //find an empty map channel for (int mp = 0; mp < mesh.getNumMaps(); mp++) { if (!mesh.mapSupport(mp)) { normalMapChannel = mp; mesh.setMapSupport(normalMapChannel,TRUE); MeshMap& map = mesh.Map(normalMapChannel); for (int i = 0; i < map.fnum; i++) { for (int j = 0; j < 3; j++) { unsigned int newID = pNormals->Face(i).GetNormalID(j); map.tf[i].t[j] = newID; } } map.setNumVerts(pNormals->GetNumNormals()); for (int i = 0; i < map.vnum; i++) { map.tv[i] = pNormals->Normal(i); } // make sure nothing is done with MeshNormalSpec (until data is copied back) pNormals->Clear(); break; } } } // Slice off everything below the plane. if (slice) SliceTriObject (mesh, N, offset); MirrorTriObject (mesh, axis, tm, itm,normalMapChannel); if (weld) WeldTriObject (mesh, N, offset, threshold); //now move the normals back if (pNormals && normalMapChannel != -1) { MeshMap& map = mesh.Map(normalMapChannel); pNormals->SetNumFaces(map.fnum); pNormals->SetNumNormals(map.vnum); pNormals->SetAllExplicit(true); BitArray temp; temp.SetSize(map.vnum); temp.SetAll(); pNormals->SpecifyNormals(TRUE,&temp); for (int i = 0; i < map.vnum; i++) { pNormals->GetNormalArray()[i] = map.tv[i]; pNormals->SetNormalExplicit(i,true); } for (int i = 0; i < map.fnum; i++) { for (int j = 0; j < 3; j++) { pNormals->SetNormalIndex(i,j,map.tf[i].t[j]); MeshNormalFace& face = pNormals->Face(i); face.SpecifyAll(true); } } pNormals->SetFlag(MESH_NORMAL_MODIFIER_SUPPORT); for (int i = 0; i < pNormals->GetNumFaces(); i++) { for (int j = 0; j < 3; j++) { int id = pNormals->GetNormalIndex(i,j); } } pNormals->CheckNormals(); pNormals->SetParent(NULL); // Free the map channel mesh.setMapSupport(normalMapChannel,FALSE); } tobj->UpdateValidity (GEOM_CHAN_NUM, iv); tobj->UpdateValidity (TOPO_CHAN_NUM, iv); tobj->UpdateValidity (VERT_COLOR_CHAN_NUM, iv); tobj->UpdateValidity (TEXMAP_CHAN_NUM, iv); tobj->UpdateValidity (SELECT_CHAN_NUM, iv); }
void WMOGroupImpl::buildMaxData() { // Group Header Node INode* groupHeadNode = createGroupHeaderNode(); groupHeadNode->SetGroupHead(TRUE); groupHeadNode->SetGroupMember(FALSE); // Geoset // 一个Render Batch构造一个Node, 并且加入到组中 for (int i = 0; i < m_batchCount; ++i) { WMORenderBatch& renderBatch = m_batchData[i]; m_wmoImporter->m_logStream << "Model Geoset " << i << " Vertex Info: " << renderBatch.vertexStart << " -- " << renderBatch.vertexEnd << endl; m_wmoImporter->m_logStream << "Model Geoset " << i << " Index Info: " << renderBatch.indexStart << " -- " << renderBatch.indexCount << endl; // Triangle Mesh Object // 基本的三角形模型对象 TriObject* triObject = CreateNewTriObject(); // 创建Node, 并且设为Group Header Node的子节点 ImpNode* tmpImpNode = m_wmoImporter->m_impInterface->CreateNode(); tmpImpNode->Reference(triObject); m_wmoImporter->m_impInterface->AddNodeToScene(tmpImpNode); INode* realINode = tmpImpNode->GetINode(); realINode->SetGroupHead(FALSE); realINode->SetGroupMember(TRUE); groupHeadNode->AttachChild(realINode); m_geosetNodeList.push_back(realINode); TCHAR nodeName[256]; sprintf(nodeName, "%s_part_%03d", m_groupName.c_str(), i); realINode->SetName(nodeName); // mesh unsigned short vertexCount = renderBatch.vertexEnd - renderBatch.vertexStart + 1; unsigned int trigangleCount = renderBatch.indexCount / 3; Mesh& mesh = triObject->GetMesh(); mesh.setNumVerts(vertexCount); mesh.setNumTVerts(vertexCount, TRUE); mesh.setNumFaces(trigangleCount); mesh.setNumTVFaces(trigangleCount); // 顶点坐标和UV for (int i = 0; i < vertexCount; ++i) { mesh.verts[i] = *(Point3*)(&(m_vertexData[renderBatch.vertexStart + i])); // UV坐标反转 mesh.tVerts[i].x = m_textureCoords[renderBatch.vertexStart + i].x; mesh.tVerts[i].y = 1.0f - m_textureCoords[renderBatch.vertexStart + i].y; } // 三角形 for (unsigned int i = 0; i < trigangleCount; ++i) { Face& face = mesh.faces[i]; int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart; int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart; int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart; face.setVerts(index1, index2, index3); face.Show(); face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS); TVFace& tface = mesh.tvFace[i]; tface.setTVerts(index1, index2, index3); } // 法线 mesh.SpecifyNormals(); MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals(); if (specNorms) { specNorms->ClearAndFree(); specNorms->SetNumFaces(trigangleCount); specNorms->SetNumNormals(vertexCount); Point3* norms = specNorms->GetNormalArray(); for (int i = 0; i < vertexCount; ++i) { norms[i] = *(Point3*)(&m_normalData[renderBatch.vertexStart + i]); } MeshNormalFace* pFaces = specNorms->GetFaceArray(); for (unsigned int i = 0; i < trigangleCount; ++i) { int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart; int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart; int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart; pFaces[i].SpecifyNormalID(0, index1); pFaces[i].SpecifyNormalID(1, index2); pFaces[i].SpecifyNormalID(2, index3); } specNorms->SetAllExplicit(true); specNorms->CheckNormals(); } // 删除重复的和无效的面 mesh.RemoveDegenerateFaces(); mesh.RemoveIllegalFaces(); realINode->SetMtl(m_wmoImporter->m_materialList[renderBatch.texture]); //realINode->BackCull(FALSE); // 取消背面裁减 不是所有的Node都要取消背面裁减 realINode->EvalWorldState(0); } }
// 1. 加载模型顶点数据 void M2Importer::importGeomObject() { // Group Header Node INode* groupHeadNode = createGroupHeaderNode(); groupHeadNode->SetGroupHead(TRUE); groupHeadNode->SetGroupMember(FALSE); if (m_modelHeader->nameLength > 1) { TCHAR* modelName = (TCHAR*)(m_m2FileData + m_modelHeader->nameOfs); groupHeadNode->SetName(modelName); m_logStream << "ModelName: " << modelName << endl; } else groupHeadNode->SetName("GeomGroup"); // Geoset // 一个Geoset构造一个Node, 并且加入到组中 unsigned short* verDataIndex = (unsigned short*)(m_m2FileData + m_modelView->ofsIndex); unsigned short* triData = (unsigned short*)(m_m2FileData + m_modelView->ofsTris); m_geosetNodeList.reserve(m_modelView->nSub); m_materialList.reserve(m_modelView->nSub); for (unsigned int i = 0; i < m_modelView->nSub; ++i) m_materialList.push_back(0); for (unsigned int i = 0; i < m_modelView->nSub; ++i) { ModelGeoset& geosetData = m_modelGeoset[i]; // Triangle Mesh Object // 基本的三角形模型对象 TriObject* triObject = CreateNewTriObject(); // 创建Node, 并且设为Group Header Node的子节点 ImpNode* tmpImpNode = m_impInterface->CreateNode(); tmpImpNode->Reference(triObject); //tmpImpNode->SetPivot(*(Point3*)&(geosetData.v)); m_impInterface->AddNodeToScene(tmpImpNode); INode* realINode = tmpImpNode->GetINode(); realINode->SetGroupHead(FALSE); realINode->SetGroupMember(TRUE); groupHeadNode->AttachChild(realINode); m_geosetNodeList.push_back(realINode); TCHAR nodeName[256]; sprintf(nodeName, "GeosetPart_%d", i); realINode->SetName(nodeName); // mesh Mesh& mesh = triObject->GetMesh(); mesh.setNumVerts(geosetData.vcount); mesh.setNumTVerts(geosetData.vcount, TRUE); unsigned int triangeCount = geosetData.icount / 3; mesh.setNumFaces(triangeCount); mesh.setNumTVFaces(triangeCount); m_logStream << "Model Geoset " << i << " Vertex Count: " << geosetData.vcount << endl; m_logStream << "Model Geoset " << i << " Index Count: " << triangeCount << endl; // 顶点坐标和UV for (unsigned int i = 0; i < geosetData.vcount; ++i) { ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ]; mesh.verts[i] = *(Point3*)(&vertexData.pos); // UV坐标反转 mesh.tVerts[i].x = vertexData.texcoords.x; mesh.tVerts[i].y = 1.0f - vertexData.texcoords.y; } // 三角形 for (unsigned int i = 0; i < triangeCount; ++i) { Face& face = mesh.faces[i]; face.setVerts(triData[geosetData.istart + i*3] - m_indexCount, triData[geosetData.istart + i*3+1] - m_indexCount, triData[geosetData.istart + i*3+2] - m_indexCount); face.Show(); face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS); TVFace& tface = mesh.tvFace[i]; tface.setTVerts(triData[geosetData.istart + i*3] - m_indexCount, triData[geosetData.istart + i*3+1] - m_indexCount, triData[geosetData.istart + i*3+2] - m_indexCount); } // 法线 mesh.SpecifyNormals(); MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals(); if (specNorms) { specNorms->ClearAndFree(); specNorms->SetNumFaces(triangeCount); specNorms->SetNumNormals(geosetData.vcount); Point3* norms = specNorms->GetNormalArray(); for (unsigned int i = 0; i < geosetData.vcount; ++i) { ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ]; norms[i] = *(Point3*)(&vertexData.normal); } MeshNormalFace* pFaces = specNorms->GetFaceArray(); for (unsigned int i = 0; i < triangeCount; ++i) { pFaces[i].SpecifyNormalID(0, triData[geosetData.istart + i*3] - m_indexCount); pFaces[i].SpecifyNormalID(1, triData[geosetData.istart + i*3+1] - m_indexCount); pFaces[i].SpecifyNormalID(2, triData[geosetData.istart + i*3+2] - m_indexCount); } specNorms->SetAllExplicit(true); specNorms->CheckNormals(); } // 删除重复的和无效的面 mesh.RemoveDegenerateFaces(); mesh.RemoveIllegalFaces(); //realINode->BackCull(FALSE); // 取消背面裁减 双面绘制与取消背面裁减一起设置 realINode->EvalWorldState(0); // 索引值修正 m_indexCount += geosetData.vcount; } // 加载材质 unsigned short* texLookupData = (unsigned short*)(m_m2FileData + m_modelHeader->ofsTexLookup); ModelTextureDef* texUnitDefData = (ModelTextureDef*)(m_m2FileData + m_modelHeader->ofsTextures); ModelTexUnit* texUnitData = (ModelTexUnit*)(m_m2FileData + m_modelView->ofsTex); for (unsigned int i = 0; i < m_modelView->nTex; ++i) { ModelTexUnit& texUnit = texUnitData[i]; unsigned short textureID = texLookupData[texUnit.textureid]; ModelTextureDef& texDef = texUnitDefData[textureID]; string textureName; if (texDef.type == 0) textureName = (LPCSTR)(m_m2FileData + texDef.nameOfs); else textureName = getReplacableTexture(texDef.type); StdMat2* material = m_materialList[texUnit.op]; if (!material) material = createMaterial(); // 根据混合属性决定加在第几层 material->SetSubTexmap(ID_DI, createTexture(textureName.c_str())); material->EnableMap(ID_DI, TRUE); //material->SetTwoSided(TRUE); // 双面 设置了此标志的才打开 m_maxInterface->GetMaterialLibrary().Add(material); m_geosetNodeList[texUnit.op]->SetMtl(material); } m_maxInterface->RedrawViews(m_maxInterface->GetTime()); }