BOOL CEditableObject::ParseMultiMaterial(MultiMtl* src, u32 mid, CSurface* dest) { R_ASSERT(src); R_ASSERT(src->ClassID()==Class_ID(MULTI_CLASS_ID,0)); Mtl* M = src->GetSubMtl(mid); if (M){ if (M->ClassID()==Class_ID(DMTL_CLASS_ID,0)){ StdMat *smtl = (StdMat*)src->GetSubMtl(mid); if (!ParseStdMaterial(smtl,dest)){ ELog.Msg(mtError,"'%s' -> bad submaterial",src->GetName()); return FALSE; } return TRUE; }else if (M->ClassID()==XRAYMTL_CLASS_ID){ XRayMtl *smtl = (XRayMtl*)src->GetSubMtl(mid); if (!ParseXRayMaterial(smtl,mid,dest)){ ELog.Msg(mtError,"'%s' -> bad submaterial",src->GetName()); return FALSE; } } return TRUE; }else{ ELog.Msg(mtError,"'%s' -> can't extract multi-material items.",src->GetName()); return FALSE; } }
/** * @brief * Creates a material */ PLSceneMaterial *PLSceneMaterial::Create(PLScene &cScene, IGameMaterial *pParentIGameMaterial, IGameMaterial &cIGameMaterial, const String &sName) { // Get the 3ds Max material... I don't use IGame for this because I didn't get it working using it... Mtl *pMaxMaterial = cIGameMaterial.GetMaxMaterial(); if (pMaxMaterial) { // DxMaterial or extend? IDxMaterial2 *pFXMaterial = static_cast<IDxMaterial2*>(pMaxMaterial->GetInterface(IDXMATERIAL2_INTERFACE)); if (!pFXMaterial && pParentIGameMaterial) pFXMaterial = static_cast<IDxMaterial2*>(pParentIGameMaterial->GetMaxMaterial()->GetInterface(IDXMATERIAL2_INTERFACE)); if (pFXMaterial) { // Get information from the DirectX Shader material // Get effect filename #if MAX_RELEASE >= 12000 // For R12 release Url cUrl = pFXMaterial->GetEffectFile().GetFullFilePath().data(); #else Url cUrl = pFXMaterial->GetEffectFilename(); #endif String sEffectFilenameName = cUrl.GetFilename(); // Our effect? if (sEffectFilenameName == "PixelLight_SRShaderLighting.fx") return new PLSceneMaterialSRShaderLighting(cScene, pParentIGameMaterial, cIGameMaterial, sName); else return new PLSceneMaterialFX(cScene, pParentIGameMaterial, cIGameMaterial, sName); } else { // Is this a shell material used for 'backed texture'? if (pMaxMaterial->ClassID() == Class_ID(BAKE_SHELL_CLASS_ID, 0)) return new PLSceneMaterialBakeShell(cScene, pParentIGameMaterial, cIGameMaterial, sName); else return new PLSceneMaterialStandard(cScene, pParentIGameMaterial, cIGameMaterial, sName); } } // Error! return nullptr; }
bool MaterialUIHandler::SetupMtlSubNameCombo (HWND hWnd, EPolyMod *pMod) { INode *singleNode = GetNode(pMod); Mtl *nodeMtl = (singleNode) ? singleNode->GetMtl() : NULL; // check for scripted material if(nodeMtl){ MSPlugin* plugin = (MSPlugin*)((ReferenceTarget*)nodeMtl)->GetInterface(I_MAXSCRIPTPLUGIN); if(plugin) nodeMtl = dynamic_cast<Mtl*>( plugin->get_delegate() ); } if (nodeMtl == NULL || nodeMtl->ClassID() != Class_ID(MULTI_CLASS_ID, 0)) { //no UI for cloned nodes, and not MultiMtl SendMessage(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), CB_RESETCONTENT, 0, 0); EnableWindow(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), false); return false; } NumList mtlIDList; NumList mtlIDMeshList; GetMtlIDList (nodeMtl, mtlIDList); GetMtlIDList (pMod, singleNode, mtlIDMeshList); MultiMtl *nodeMulti = (MultiMtl*) nodeMtl; EnableWindow(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), true); SendMessage(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), CB_RESETCONTENT, 0, 0); for (int i=0; i<mtlIDList.Count(); i++){ TSTR idname, buf; if(mtlIDMeshList.Find(mtlIDList[i]) != -1) { nodeMulti->GetSubMtlName(mtlIDList[i], idname); if (idname.isNull()) idname = GetString(IDS_MTL_NONAME); //az: 042503 - FIGS buf.printf(_T("%s - ( %d )"), idname.data(), mtlIDList[i]+1); int ith = SendMessage(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)buf.data()); SendMessage(GetDlgItem(hWnd, IDC_MTLID_NAMES_COMBO), CB_SETITEMDATA, ith, (LPARAM)mtlIDList[i]); } } return true; }
/* ==================== GatherMesh ==================== */ void G3DMExport::GatherMesh(INode* i_node) { // convert to the triangle type Mesh* i_mesh = NULL; Object* obj = i_node->EvalWorldState(mTime).obj; if(obj && ( obj->SuperClassID() == GEOMOBJECT_CLASS_ID )) { if(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { TriObject *tri_obj = (TriObject*)obj->ConvertToType(mTime, Class_ID(TRIOBJ_CLASS_ID, 0)); MAX_CHECK(tri_obj); i_mesh = &tri_obj->mesh; } } if(i_mesh==NULL||i_mesh->getNumFaces()==0||i_mesh->getNumVerts()==0) return; MESH mesh; // get the mesh name mesh.name = i_node->GetName(); // get the material mesh.texture = "textures/default.tga"; Mtl* mtl = i_node->GetMtl(); if(mtl && (mtl->ClassID()==Class_ID(DMTL_CLASS_ID, 0)) && ((StdMat*)mtl)->MapEnabled(ID_DI)) { Texmap *texmap = mtl->GetSubTexmap(ID_DI); if(texmap && texmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0x00)) { mesh.texture = UnifySlashes(((BitmapTex *)texmap)->GetMapName()); if( !strstr( mesh.texture.c_str(), mPath.c_str() ) ) { G3DAssert("The material(%s) is error : the texture path(%s) is illegal!",mtl->GetName(), mesh.texture.c_str()); return; } else { mesh.texture = strstr(mesh.texture.c_str(),mPath.c_str()) + strlen(mPath.c_str()); } } } // if it has uvs int map_count = i_mesh->getNumMaps(); bool has_uvs = i_mesh->getNumTVerts() && i_mesh->tvFace; if(!(has_uvs&&map_count)) return; // get the transform Matrix3 transform = i_node->GetObjectTM(mTime); // get the points mesh.points.assign(i_mesh->verts, i_mesh->verts+i_mesh->getNumVerts()); // get the triangles for(int i = 0; i < i_mesh->getNumFaces(); i++) { Face& face = i_mesh->faces[i]; TRIANGLE tri; tri.smoothing = face.smGroup; for(int j = 0; j < 3; j++) { VTNIS v; v.pos = transform * i_mesh->verts[face.v[j]]; // get the uv UVVert * map_verts = i_mesh->mapVerts(1); TVFace * map_faces = i_mesh->mapFaces(1); v.uv = reinterpret_cast<Point2&>(map_verts[map_faces[i].t[j]]); v.uv.y = 1 - v.uv.y; // initialize the normal v.normal = Point3::Origin; // get the vertex index v.index = face.v[j]; // get the smoothing group v.smoothing = face.smGroup; // set the index for the triangle tri.index0[j] = v.index; // reassemble the vertex list tri.index1[j] = AddVertex(mesh, v); } // add the triangle to the table mesh.triangles.push_back(tri); } // build the index map for( int i = 0; i < mesh.vertexes.size(); i++ ) { mesh.vertex_index_map[mesh.vertexes[i].index].push_back(i); } // build the normal space BuildNormal(mesh); // calculate the bounding box mesh.box.Init(); for(int i = 0; i < mesh.vertexes.size(); i++) { mesh.box += mesh.vertexes[i].pos; } // add the mesh to the table mMeshes.push_back(mesh); }
void Exporter::DumpMaterial(MaxMaterial *maxm,Mtl* mtl, int mtlID, int subNo, int indentLevel) { int i; TimeValue t = GetStaticFrame(); if (!mtl) return; // for(i=0;i<indentLevel;i++) { log(" "); } // log("material %s adding. type : ",mtl->GetName()); // We know the Standard material, so we can get some extra info if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { // top level & standard material // log("standard \n"); StdMat* std = (StdMat*)mtl; MaxStdMaterial *stdm=new MaxStdMaterial; strcpy(stdm->name,mtl->GetName()); stdm->Ambient=rvector(std->GetAmbient(t)); stdm->Ambient.x=-stdm->Ambient.x; stdm->Diffuse=rvector(std->GetDiffuse(t)); stdm->Diffuse.x=-stdm->Diffuse.x; stdm->Specular=rvector(std->GetSpecular(t)); stdm->Specular.x=-stdm->Specular.x; // 축의 바뀜때문에 만들어 놓은.. 으흑.. stdm->TwoSide=std->GetTwoSided(); if(std->GetTransparencyType()==TRANSP_ADDITIVE) stdm->ShadeMode=RSSHADEMODE_ADD; else stdm->ShadeMode=RSSHADEMODE_NORMAL; if(rsm->MaxStdMaterialList.GetByName(stdm->name)==-1) // 이미 있는 standard material 이면 더하지 않음. { rsm->MaxStdMaterialList.Add(stdm); stdm->RMLIndex=rsm->MaxStdMaterialList.GetCount()-1; for (i=0; i<mtl->NumSubTexmaps(); i++) { Texmap* subTex = mtl->GetSubTexmap(i); float amt = 1.0f; if (subTex) { // If it is a standard material we can see if the map is enabled. if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { if (!((StdMat*)mtl)->MapEnabled(i)) continue; amt = ((StdMat*)mtl)->GetTexmapAmt(i, 0); } DumpTexture(stdm, subTex, mtl->ClassID(), i, amt, indentLevel+1); } } } else { delete stdm; } maxm->nSubMaterial=1; maxm->SubMaterials=new int[1]; maxm->SubMaterials[0]=rsm->MaxStdMaterialList.GetByName(mtl->GetName()); } if (mtl->NumSubMtls() > 0) { // log("multi/sub ( count : %d )\n",mtl->NumSubMtls()); maxm->nSubMaterial=mtl->NumSubMtls(); maxm->SubMaterials=new int[maxm->nSubMaterial]; maxm->pSubMaterials=new MaxMaterial*[maxm->nSubMaterial]; for (i=0; i<mtl->NumSubMtls(); i++) { Mtl* subMtl = mtl->GetSubMtl(i); if (subMtl) { maxm->pSubMaterials[i]=new MaxMaterial; DumpMaterial(maxm->pSubMaterials[i],subMtl, 0, i, indentLevel+1); if(subMtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { maxm->SubMaterials[i]= rsm->MaxStdMaterialList.GetByName(subMtl->GetName()); } else maxm->SubMaterials[i]= maxm->pSubMaterials[i]->SubMaterials[0]; } else { maxm->pSubMaterials[i]=NULL; maxm->SubMaterials[i]=-1; } } } }
void plCompositeMtl::Shade(ShadeContext& sc) { // Get the background color Color backColor, backTrans; //sc.GetBGColor(backColor, backTrans); backColor.Black(); backTrans.White(); Point3 vtxIllum, vtxAlpha; plPassMtl::GetInterpVtxValue(MAP_ALPHA, sc, vtxAlpha); plPassMtl::GetInterpVtxValue(MAP_SHADING, sc, vtxIllum); int count = NumSubMtls(); for (int i = 0; i < count; i++) { if (i > 0 && fPassesPB->GetInt(kCompOn, 0, i - 1) == 0) // Material is unchecked, skip it. continue; Mtl *mtl = GetSubMtl(i); if (mtl == NULL || mtl->ClassID() != PASS_MTL_CLASS_ID) continue; float opacity; if (i == 0) { opacity = 1.0f; } else { int blendMethod = fPassesPB->GetInt(kCompBlend, 0, i - 1); switch(blendMethod) { case kCompBlendVertexAlpha: case kCompBlendInverseVtxAlpha: opacity = vtxAlpha.x; break; case kCompBlendVertexIllumRed: case kCompBlendInverseVtxIllumRed: opacity = vtxIllum.x; break; case kCompBlendVertexIllumGreen: case kCompBlendInverseVtxIllumGreen: opacity = vtxIllum.y; break; case kCompBlendVertexIllumBlue: case kCompBlendInverseVtxIllumBlue: opacity = vtxIllum.z; break; default: opacity = 1.0f; break; } if (IsInverseBlend(blendMethod)) opacity = 1 - opacity; } plPassMtl *passMtl = (plPassMtl*)mtl; passMtl->ShadeWithBackground(sc, backColor, false); // Don't include the vtx alpha, that's OUR job float currTrans = (1 - (1 - sc.out.t.r) * opacity); backTrans *= currTrans; backColor = backColor * currTrans + sc.out.c * opacity; } sc.out.t = backTrans; sc.out.c = backColor; }
//================================================================= // 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; }
//*************************************************************************** // Calculate ambient or diffuse color at each vertex. // Pass in TRUE as the "diffuse" parameter to calculate the diffuse color. // If FALSE is passed in, ambient color is calculated. //*************************************************************************** BOOL calcMixedVertexColors(INode* node, TimeValue t, int lightModel, ColorTab& vxColTab, EvalColProgressCallback* fn) { ObjectState ostate; BOOL deleteTri; Mesh* mesh; SContext sc; DefaultLight dl1, dl2; MtlBaseLib mtls; Matrix3 tm; sc.SetNodeAndTime(node, t); tm = sc.tmAfterWSM; TriObject* tri = GetTriObjectFromNode(node, t, deleteTri); // We will only work on GeomObjects if (!tri) { return FALSE; } // Get the mesh from the object mesh = &tri->GetMesh(); if (!mesh) { return FALSE; } // If the node doesn't have a material attached, // we create a dummy material. Mtl* mtl = node->GetMtl(); if (!mtl) { mtl = new DumMtl(Color(node->GetWireColor())); } mesh->buildRenderNormals(); vxColTab.ZeroCount(); vxColTab.Shrink(); sc.SetMesh(mesh); sc.CalcBoundObj(); // Add the material to the list mtls.AddMtl(mtl); // Setup ambient light if (lightModel == LIGHT_AMBIENT) { sc.SetAmbientLight(Color(1.0f, 1.0f, 1.0f)); } else { sc.SetAmbientLight(Color(0.0f, 0.0f, 0.0f)); } // If we're using the real lights, we need to find them first if (lightModel == LIGHT_SCENELIGHT) { AddSceneLights(&sc, &mtls); // Add default lights if there are no lights in the scene if (sc.lightTab.Count() == 0) { dl1.ls.intens = 1.0f; dl1.ls.color = Color(0.8f, 0.8f, 0.8f); dl1.ls.type = OMNI_LGT; dl1.tm = TransMatrix(1000.0f * Point3(-900.0f, -1000.0f, 1500.0f)); dl2.ls.intens = 1.0f; dl2.ls.color = Color(0.8f, 0.8f, 0.8f); dl2.ls.type = OMNI_LGT; dl2.tm = TransMatrix(-1000.0f * Point3(-900.0f, -1000.0f, 1500.0f)); sc.AddLight(new LightInfo(&dl1)); sc.AddLight(new LightInfo(&dl2)); } sc.SetAmbientLight(GetCOREInterface()->GetAmbient(t, FOREVER)); } sc.UpdateLights(); // Update material mtl->Update(t, FOREVER); int numVerts = mesh->numVerts; for (unsigned int v = 0; v < (unsigned)numVerts; v++) { if (fn) { if (fn->progress(float(v)/float(numVerts))) { if (deleteTri) { delete tri; } mtls.Empty(); if (mtl->ClassID() == DUMMTL_CLASS_ID) { delete mtl; } // What to return here is up for discussion. // 1) We are aborting so FALSE might be in order. // 2) We have calculated some colors. Let's use what we've got so far. return TRUE; } } // Create a new entry Color* vxCol = new Color; Point3 tmpCol(0.0f, 0.0f, 0.0f); int numShades = 0; BitArray faceList; faceList.SetSize(mesh->numFaces, 0); // Get vertex normal // We also pass in a BitArray that will be filled in with // to inform us to which faces this vertex belongs. // We could do this manually, but we need to do it to get // the vertex normal anyway so this is done to speed things // up a bit. Point3 vxNormal = interpVertexNormal(mesh, tm, v, faceList); Point3 viewDir = -vxNormal; Point3 viewPoint = tm*mesh->verts[v] + 5.0f*vxNormal; Point3 lightPos = viewPoint; Point3 viewTarget = tm*mesh->verts[v]; // We now have a viewpoint and a view target. // Now we just have to shade this point on the mesh in order // to get it's color. // Note: // Since materials are assigned on Face basis we need to render each // vertex as many times as it has connecting faces. // the colors collected are mixed to get the resulting // color at each vertex. for (int nf = 0; nf < faceList.GetSize(); nf++) { if (faceList[nf]) { // render vertex for this face. sc.SetViewPoint(viewPoint); sc.SetTargetPoint(viewTarget); sc.SetViewDir(viewDir); sc.SetFaceNum(nf); Face* f = &mesh->faces[nf]; sc.SetMtlNum(f->getMatID()); sc.CalcNormals(); // Setup the barycentric coordinate if (mesh->faces[nf].v[0] == v) sc.SetBaryCoord(Point3(1.0f, 0.0f, 0.0f)); else if (mesh->faces[nf].v[1] == v) sc.SetBaryCoord(Point3(0.0f, 1.0f, 0.0f)); else if (mesh->faces[nf].v[2] == v) sc.SetBaryCoord(Point3(0.0f, 0.0f, 1.0f)); // Use diffuse color instead of ambient // The only difference is that we create a special light // located at the viewpoint and we set the ambient light to black. if (lightModel == LIGHT_DIFFUSE) { dl1.ls.intens = 1.0f; dl1.ls.color = Color(0.8f, 0.8f, 0.8f); dl1.ls.type = OMNI_LGT; dl1.tm = TransMatrix(lightPos); sc.ClearLights(); sc.AddLight(new LightInfo(&dl1)); sc.UpdateLights(); } // Shade the vertex mtl->Shade(sc); tmpCol.x += sc.out.c.r; tmpCol.y += sc.out.c.g; tmpCol.z += sc.out.c.b; numShades++; } } // The color mixes. We just add the colors together and // then divide with as many colors as we added. if (numShades > 0) { tmpCol = tmpCol / (float)numShades; } vxCol->r = tmpCol.x; vxCol->g = tmpCol.y; vxCol->b = tmpCol.z; vxCol->ClampMinMax(); // Append the Color to the table. If the array needs // to be realloc'ed, allocate extra space for 100 points. vxColTab.Append(1, &vxCol, 100); } // Some objects gives us a temporary mesh that we need to delete afterwards. if (deleteTri) { delete tri; } mtls.Empty(); if (mtl->ClassID() == DUMMTL_CLASS_ID) { delete mtl; } return TRUE; }
// --[ Method ]--------------------------------------------------------------- // // - Class : CStravaganzaMaxTools // // - prototype : bool BuildShaders() // // - Purpose : Builds the shader list from MAX's materials. // Preview mode requires texture files to be stored with full // path in order to load them. When we export, we only store the // filename. Another thing is that in the export mode, we copy // all textures into the path specified by the user if that // option is checked. // // ----------------------------------------------------------------------------- bool CStravaganzaMaxTools::BuildShaders() { std::vector<Mtl*>::iterator it; assert(m_vecShaders.empty()); if(!m_bPreview && m_bCopyTextures && m_strTexturePath == "") { CLogger::NotifyWindow("Textures won't be copied\nSpecify a valid output texture path first"); } LOG.Write("\n\n-Building shaders: "); for(it = m_vecMaterials.begin(); it != m_vecMaterials.end(); ++it) { Mtl* pMaxMaterial = *it; assert(pMaxMaterial); LOG.Write("\n %s", pMaxMaterial->GetName().data()); CShaderStandard* pShaderStd = new CShaderStandard; pShaderStd->SetName(pMaxMaterial->GetName().data()); // Properties StdMat2 *pMaxStandardMtl = NULL; StdMat2 *pMaxBakedMtl = NULL; float fAlpha; if(pMaxMaterial->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { pMaxStandardMtl = (StdMat2 *)pMaxMaterial; } else if(pMaxMaterial->ClassID() == Class_ID(BAKE_SHELL_CLASS_ID, 0)) { pMaxStandardMtl = (StdMat2 *)pMaxMaterial->GetSubMtl(0); pMaxBakedMtl = (StdMat2 *)pMaxMaterial->GetSubMtl(1); } if(pMaxStandardMtl) { // Standard material fAlpha = pMaxStandardMtl->GetOpacity(0); Shader* pMaxShader = pMaxStandardMtl->GetShader(); CVector4 v4Specular = ColorToVector4(pMaxStandardMtl->GetSpecular(0), 0.0f) * pMaxShader->GetSpecularLevel(0, 0); pShaderStd->SetAmbient (ColorToVector4(pMaxStandardMtl->GetAmbient(0), 0.0f)); pShaderStd->SetDiffuse (ColorToVector4(pMaxStandardMtl->GetDiffuse(0), fAlpha)); pShaderStd->SetSpecular (v4Specular); pShaderStd->SetShininess(pMaxShader->GetGlossiness(0, 0) * 128.0f); if(pMaxStandardMtl->GetTwoSided() == TRUE) { pShaderStd->SetTwoSided(true); } // Need to cast to StdMat2 in order to get access to IsFaceted(). // ¿Is StdMat2 always the interface for standard materials? if(((StdMat2*)pMaxStandardMtl)->IsFaceted()) { pShaderStd->SetFaceted(true); } if(pMaxStandardMtl->GetWire() == TRUE) { pShaderStd->SetPostWire(true); pShaderStd->SetWireLineThickness(pMaxStandardMtl->GetWireSize(0)); } } else { // Material != Standard fAlpha = 1.0f; // pMaxMaterial->GetXParency(); pShaderStd->SetAmbient (ColorToVector4(pMaxMaterial->GetAmbient(), 0.0f)); pShaderStd->SetDiffuse (ColorToVector4(pMaxMaterial->GetDiffuse(), fAlpha)); pShaderStd->SetSpecular (CVector4(0.0f, 0.0f, 0.0f, 0.0f)); pShaderStd->SetShininess(0.0f); } // Layers if(!pMaxStandardMtl) { m_vecShaders.push_back(pShaderStd); continue; } bool bDiffuseMap32Bits = false; StdMat2 *pStandardMtl; for(int i = 0; i < 3; i++) { int nMap; pStandardMtl = pMaxStandardMtl; // 0 = diffuse, 1 == bump, 2 = lightmap (self illumination slot) or envmap (reflection slot) if(i == 0) { nMap = ID_DI; } else if(i == 1) { nMap = ID_BU; // If its a baked material, get the bump map from there if(pMaxBakedMtl) { pStandardMtl = pMaxBakedMtl; } } else if(i == 2) { bool bBaked = false; // If its a baked material, get the map2 (lightmap) from there if(pMaxBakedMtl) { if(pMaxBakedMtl->GetMapState(ID_SI) == MAXMAPSTATE_ENABLED) { bBaked = true; nMap = ID_SI; pStandardMtl = pMaxBakedMtl; } } if(!bBaked) { if(pStandardMtl->GetMapState(ID_SI) == MAXMAPSTATE_ENABLED) { nMap = ID_SI; } else { nMap = ID_RL; } } } // Check validity if(pStandardMtl->GetMapState(nMap) != MAXMAPSTATE_ENABLED) { if(i == 0) { LOG.Write("\n No diffuse. Skipping."); break; } continue; } Texmap* pMaxTexmap = pStandardMtl->GetSubTexmap(nMap); if(!pMaxTexmap) { if(i == 0) { LOG.Write("\n No diffuse. Skipping."); break; } continue; } // Get texmaps std::vector<std::string> vecTextures, vecPaths; CShaderStandard::SLayerInfo layerInfo; CShaderStandard::SBitmapInfo bitmapInfo; if(pMaxTexmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { BitmapTex* pMaxBitmapTex = (BitmapTex*)pMaxTexmap; Bitmap* pMaxBitmap = pMaxBitmapTex->GetBitmap(SECONDS_TO_TICKS(m_fStartTime)); StdUVGen* pMaxUVGen = pMaxBitmapTex->GetUVGen(); if(!pMaxBitmap) { if(i == 0) { LOG.Write("\n Invalid diffuse. Skipping."); break; } continue; } assert(pMaxUVGen); BitmapInfo bi = pMaxBitmap->Storage()->bi; // bi.Name() returns the full path // bi.Filename() returns just the filename vecTextures.push_back(bi.Filename()); vecPaths. push_back(bi.Name()); LOG.Write("\n Bitmap %s", vecTextures[0].data()); // Check if diffuse texture has alpha channel if(i == 0) { CBitmap bitmap; CInputFile bitmapFile; if(!bitmapFile.Open(bi.Name(), false)) { CLogger::NotifyWindow("WARNING - CStravaganzaMaxTools::BuildShaders():\nUnable to load file %s", bi.Name()); } else { if(!bitmap.Load(&bitmapFile, GetFileExt(bi.Name()))) { CLogger::NotifyWindow("WARNING - CStravaganzaMaxTools::BuildShaders():\nUnable to load bitmap %s", bi.Name()); } else { if(bitmap.GetBpp() == 32) { bDiffuseMap32Bits = true; LOG.Write(" (with alpha channel)"); } bitmap.Free(); } bitmapFile.Close(); } } // Ok, copy properties layerInfo.texInfo.bLoop = false; layerInfo.texInfo.eTextureType = UtilGL::Texturing::CTexture::TEXTURE2D; bitmapInfo.strFile = m_bPreview ? bi.Name() : bi.Filename(); bitmapInfo.bTile = ((pMaxUVGen->GetTextureTiling() & (U_WRAP | V_WRAP)) == (U_WRAP | V_WRAP)) ? true : false; bitmapInfo.fSeconds = 0.0f; bitmapInfo.bForceFiltering = false; bitmapInfo.eFilter = UtilGL::Texturing::FILTER_TRILINEAR; // won't be used (forcefiltering = false) layerInfo.texInfo.m_vecBitmaps.push_back(bitmapInfo); layerInfo.eTexEnv = nMap == ID_RL ? CShaderStandard::TEXENV_ADD : CShaderStandard::TEXENV_MODULATE; layerInfo.eUVGen = pMaxUVGen->GetCoordMapping(0) == UVMAP_SPHERE_ENV ? CShaderStandard::UVGEN_ENVMAPPING : CShaderStandard::UVGEN_EXPLICITMAPPING; layerInfo.uMapChannel = pMaxUVGen->GetMapChannel(); layerInfo.v3ScrollSpeed = CVector3(0.0f, 0.0f, 0.0f); layerInfo.v3RotationSpeed = CVector3(0.0f, 0.0f, 0.0f); layerInfo.v3ScrollOffset = CVector3(pMaxUVGen->GetUOffs(0), pMaxUVGen->GetVOffs(0), 0.0f); layerInfo.v3RotationOffset = CVector3(pMaxUVGen->GetUAng(0), pMaxUVGen->GetVAng(0), pMaxUVGen->GetWAng(0)); } else if(pMaxTexmap->ClassID() == Class_ID(ACUBIC_CLASS_ID, 0)) { ACubic* pMaxCubic = (ACubic*)pMaxTexmap; IParamBlock2* pBlock = pMaxCubic->pblock; Interval validRange = m_pMaxInterface->GetAnimRange(); for(int nFace = 0; nFace < 6; nFace++) { int nMaxFace; switch(nFace) { case 0: nMaxFace = 3; break; case 1: nMaxFace = 2; break; case 2: nMaxFace = 1; break; case 3: nMaxFace = 0; break; case 4: nMaxFace = 5; break; case 5: nMaxFace = 4; break; } TCHAR *name; pBlock->GetValue(acubic_bitmap_names, TICKS_TO_SECONDS(m_fStartTime), name, validRange, nMaxFace); vecPaths.push_back(name); CStr path, file, ext; SplitFilename(CStr(name), &path, &file, &ext); std::string strFile = std::string(file.data()) + ext.data(); vecTextures.push_back(strFile); bitmapInfo.strFile = m_bPreview ? name : strFile; bitmapInfo.bTile = false; bitmapInfo.fSeconds = 0.0f; bitmapInfo.bForceFiltering = false; bitmapInfo.eFilter = UtilGL::Texturing::FILTER_TRILINEAR; layerInfo.texInfo.m_vecBitmaps.push_back(bitmapInfo); } layerInfo.texInfo.bLoop = false; layerInfo.texInfo.eTextureType = UtilGL::Texturing::CTexture::TEXTURECUBEMAP; layerInfo.eTexEnv = nMap == ID_RL ? CShaderStandard::TEXENV_ADD : CShaderStandard::TEXENV_MODULATE; layerInfo.eUVGen = CShaderStandard::UVGEN_ENVMAPPING; layerInfo.uMapChannel = 0; layerInfo.v3ScrollSpeed = CVector3(0.0f, 0.0f, 0.0f); layerInfo.v3RotationSpeed = CVector3(0.0f, 0.0f, 0.0f); layerInfo.v3ScrollOffset = CVector3(0.0f, 0.0f, 0.0f); layerInfo.v3RotationOffset = CVector3(0.0f, 0.0f, 0.0f); } else { if(i == 0) { LOG.Write("\n No diffuse. Skipping."); break; } continue; } if(!m_bPreview && m_bCopyTextures && m_strTexturePath != "") { for(int nTex = 0; nTex != vecTextures.size(); nTex++) { // Copy textures into the specified folder std::string strDestPath = m_strTexturePath; if(strDestPath[strDestPath.length() - 1] != '\\') { strDestPath.append("\\", 1); } strDestPath.append(vecTextures[nTex]); if(!CopyFile(vecPaths[nTex].data(), strDestPath.data(), FALSE)) { CLogger::NotifyWindow("Unable to copy %s to\n%s", vecPaths[i], strDestPath.data()); } } } if(layerInfo.eUVGen == CShaderStandard::UVGEN_ENVMAPPING && i == 1) { CLogger::NotifyWindow("%s : Bump with spheremapping not supported", pShaderStd->GetName().data()); } else { // Add layer switch(i) { case 0: pShaderStd->SetLayer(CShaderStandard::LAYER_DIFF, layerInfo); break; case 1: pShaderStd->SetLayer(CShaderStandard::LAYER_BUMP, layerInfo); break; case 2: pShaderStd->SetLayer(CShaderStandard::LAYER_MAP2, layerInfo); break; } } } // ¿Do we need blending? if(ARE_EQUAL(fAlpha, 1.0f) && !bDiffuseMap32Bits) { pShaderStd->SetBlendSrcFactor(UtilGL::States::BLEND_ONE); pShaderStd->SetBlendDstFactor(UtilGL::States::BLEND_ZERO); } else { pShaderStd->SetBlendSrcFactor(UtilGL::States::BLEND_SRCALPHA); pShaderStd->SetBlendDstFactor(UtilGL::States::BLEND_INVSRCALPHA); } // Add shader m_vecShaders.push_back(pShaderStd); } return true; }
//---------------------------------------------------------------------------- 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)); } } } }
/* ==================== GatherSkin ==================== */ void G3DSExport::GatherSkin(INode* i_node) { SKIN skin; // get the name of the node skin.name = i_node->GetName(); // get the skin interface Modifier *modifier = GetModifier(i_node,SKIN_CLASSID); ISkin* i_skin = (ISkin*)modifier->GetInterface(I_SKIN); MAX_CHECK(i_skin); // convert to the triangle type Mesh* i_mesh = NULL; Object* obj = i_node->EvalWorldState(mTime).obj; if(obj && ( obj->SuperClassID() == GEOMOBJECT_CLASS_ID )) { if(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { TriObject *tri_obj = (TriObject*)obj->ConvertToType(mTime, Class_ID(TRIOBJ_CLASS_ID, 0)); MAX_CHECK(tri_obj); i_mesh = &tri_obj->mesh; } } MAX_CHECK(i_mesh&&i_mesh->getNumFaces()&&i_mesh->getNumVerts()); // get the material skin.texture = "textures/default.tga"; Mtl* mtl = i_node->GetMtl(); if(mtl && (mtl->ClassID()==Class_ID(DMTL_CLASS_ID, 0)) && ((StdMat*)mtl)->MapEnabled(ID_DI)) { Texmap *texmap = mtl->GetSubTexmap(ID_DI); if(texmap && texmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0x00)) { skin.texture = UnifySlashes(((BitmapTex *)texmap)->GetMapName()); if( !strstr( skin.texture.c_str(), mPath.c_str() ) ) { G3DAssert("The material(%s) is error : the texture path(%s) is illegal!",mtl->GetName(), skin.texture.c_str()); } else { skin.texture = strstr(skin.texture.c_str(),mPath.c_str()) + strlen(mPath.c_str()); } } } // if it has uvs int map_count = i_mesh->getNumMaps(); bool has_uvs = i_mesh->getNumTVerts() && i_mesh->tvFace; if(!(has_uvs&&map_count)) { G3DAssert("The skin(%s) has not the uv coordinates.",skin.name.c_str()); return; } // get the transform Matrix3 mesh_matrix = i_node->GetObjectTM(mTime); Matrix3 node_matrix = i_node->GetNodeTM(mTime); Matrix3 transform = mesh_matrix * Inverse(node_matrix); // get the points skin.points.assign(i_mesh->verts, i_mesh->verts+i_mesh->getNumVerts()); // get the triangles for(int i = 0; i < i_mesh->getNumFaces(); i++) { Face& face = i_mesh->faces[i]; TRIANGLE tri; tri.smoothing = face.smGroup; for(int j = 0; j < 3; j++) { VPTNIS v; v.pos = transform * i_mesh->verts[face.v[j]]; // get the uv UVVert * map_verts = i_mesh->mapVerts(1); TVFace * map_faces = i_mesh->mapFaces(1); v.uv = reinterpret_cast<Point2&>(map_verts[map_faces[i].t[j]]); v.uv.y = 1 - v.uv.y; // initialize the normal v.normal = Point3::Origin; // get the vertex index v.index = face.v[j]; // get the smoothing group v.smoothing = face.smGroup; // set the index for the triangle tri.index0[j] = v.index; // reassemble the vertex list tri.index1[j] = AddVertex(skin, v); } // add the triangle to the table skin.triangles.push_back(tri); } // build the index map for( int i = 0; i < skin.vertexes.size(); i++ ) { skin.vertex_index_map[skin.vertexes[i].index].push_back(i); } // get the skin context data ISkinContextData* i_skin_context_data = i_skin->GetContextInterface(i_node); if(i_skin_context_data == NULL) { G3DAssert("The skin(%s) has not the weight.",skin.name.c_str()); return; } // gets the initial matrix of the skinned object Matrix3 initial_object_transform; i_skin->GetSkinInitTM(i_node, initial_object_transform, true); // process the points int num_points = i_skin_context_data->GetNumPoints(); for(int i = 0; i < num_points; i++) { MAX_CHECK(i < skin.points.size()); VPIW viw; // get the initial point viw.pos = initial_object_transform * skin.points[i]; // process the weights std::multimap< float, int > weights; // get the number of bones that control this vertex int num_bones = i_skin_context_data->GetNumAssignedBones(i); if(num_bones>0) { for (int j = 0; j < num_bones; j++) { Matrix3 transform; // get the assigned bone of the point INode* i_bone_node = i_skin->GetBone(i_skin_context_data->GetAssignedBone(i, j)); MAX_CHECK(i_bone_node != NULL); // get the weight of the bone float weight = i_skin_context_data->GetBoneWeight(i, j); // add the weight to the table weights.insert(std::make_pair(weight, AddBone(skin,i_bone_node))); } } else { // add the weight to the table weights.insert(std::make_pair(1.f, AddBone(skin,i_node))); } // recalculate the weights float weight0 = 0.f, weight1 = 0.f, weight2 = 0.f; int index0 = 0, index1 = 0, index2 = 0; std::multimap< float, int >::iterator it = weights.end(); it--; weight0 = it->first; index0 = it->second; if(it != weights.begin()) { it--; weight1 = it->first; index1 = it->second; if(it != weights.begin()) { it--; weight2 = it->first; index2 = it->second; } } float sum_weights = weight0 + weight1 + weight2; // store the skin weights viw.weight[0] = weight0/sum_weights; viw.index[0] = index0; viw.weight[1] = weight1/sum_weights; viw.index[1] = index1; viw.weight[2] = weight2/sum_weights; viw.index[2] = index2; skin.weights.push_back(viw); } // get the initial transforms skin.transforms.resize(skin.bones.size()); for(int i = 0; i < skin.bones.size(); i++) { INode* node = skin.bones[i]; Matrix3 mat; if (SKIN_INVALID_NODE_PTR == i_skin->GetBoneInitTM( node, mat )) { if (SKIN_INVALID_NODE_PTR == i_skin->GetSkinInitTM( node, mat )) { mat.IdentityMatrix(); } } skin.transforms[i] = Inverse(mat); } // there is a 75 bone limit for each skinned object. if(skin.bones.size()>75) { G3DAssert("There are more %d bones in the skin(%s).",skin.bones.size(), i_node->GetName()); return; } // reset the skin vertex position for(int i = 0; i < skin.vertexes.size(); i++) { VPTNIS& v0 = skin.vertexes[i]; VPIW& v1 = skin.weights[v0.index]; v0.pos = v1.pos; } // build the normal space BuildNormal(skin); // calculate the bounding box skin.box.Init(); for(int i = 0; i < skin.vertexes.size(); i++) { Point3 pt = node_matrix * skin.vertexes[i].pos; skin.box += pt; } // add the skin to the table mSkins.push_back(skin); }
//---------------------------------------------------------------------------------- void DumpMaterial(IGameMaterial *pGMaxMat) { m_material *pMat = NULL; if (!pGMaxMat->IsMultiType()) // check not a mix material { pMat = new m_material; // set the name of the material... pMat->name = pGMaxMat->GetMaterialName(); // add the new material to the TOC(Table Of Contants) and set its id... pMat->id = ExporterMAX::GetExporter()->AddMaterial(pGMaxMat, pMat); Mtl *pMaxMaterial = pGMaxMat->GetMaxMaterial(); if (pMaxMaterial->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) { StdMat *pStandardMaterial = (StdMat*)pMaxMaterial; Color col; // diffuse color... col = pStandardMaterial->GetDiffuse(ExporterMAX::GetExporter()->GetStaticFrame()); pMat->diffuse = Vector4f(col.r, col.g, col.b, 1.f); // ambient color... col = pStandardMaterial->GetAmbient(ExporterMAX::GetExporter()->GetStaticFrame()); pMat->ambient = Vector4f(col.r, col.g, col.b, 1.f); // specular color... col = pStandardMaterial->GetSpecular(ExporterMAX::GetExporter()->GetStaticFrame()); pMat->specular = Vector4f(col.r, col.g, col.b, 1.f); // emissive color... pMat->emission = Vector4f(0.f, 0.f, 0.f, 1.f); // level of transparency pMat->transparent = pStandardMaterial->GetOpacity(ExporterMAX::GetExporter()->GetStaticFrame()); // specular exponent... pMat->shininess = pStandardMaterial->GetShininess(ExporterMAX::GetExporter()->GetStaticFrame()); // transparency if (pMat->transparent < 1.f){ pMat->diffuse.z = pMat->transparent; } }// 3dsmax6 HLSL Material support. (IDxMaterial) else if (IsDynamicDxMaterial((MtlBase*)pMaxMaterial)) { IDxMaterial *idxm = (IDxMaterial*)pMaxMaterial->GetInterface(IDXMATERIAL_INTERFACE); int lightParams = idxm->GetNumberOfLightParams(); for (int i = 0; i < lightParams; ++i) { INode *pNode = idxm->GetLightNode(i); if (pNode){ TCHAR *paramName = idxm->GetLightParameterName(i); } } // Other attributes are located in paramblk 0... IParamBlock2 *pParamBlk2 = (IParamBlock2*)(pMaxMaterial->GetParamBlock(0)); TimeValue t0 = ExporterMAX::GetExporter()->GetIGame()->GetSceneStartTime(); TimeValue t1 = ExporterMAX::GetExporter()->GetIGame()->GetSceneEndTime(); TimeValue DeltaTime = ExporterMAX::GetExporter()->GetIGame()->GetSceneTicks(); const int SamplingRate = 1; int numkeys = (t1 - t0) / (DeltaTime * SamplingRate) + 1; for (int i = 0; i < pParamBlk2->NumParams(); ++i) { ParamID id = pParamBlk2->IndextoID(i); ParamDef paramDef = pParamBlk2->GetParamDef(id); // we want the variable name not the UI Name... OutputDebugString(paramDef.int_name); } } //do the textures if they are there DumpTexture(pMat, pGMaxMat); } }