⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 export.cpp

📁 3dmax导出3d模型二次开发插件
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			VirtoolsMat = VirtoolsExporter->GetMaterialByKey(mtlKey);

			if (PatchChannelCount>0) {
				VirtoolsPMesh->AddChannel(VirtoolsMat);
			}
			VirtoolsPMesh->SetTVPatchCount(pmesh->numPatches,PatchChannelCount-1);
			VirtoolsPMesh->SetTVCount(pmesh->getNumMapVerts(mp),PatchChannelCount-1);
	
			for (i=0;i<pmesh->numPatches;++i) {

				CKTVPatch Virtoolstvp;
				TVPatch tvp = pmesh->getMapPatch(mp,i);
				
				int MatID = (pmesh->patches[i].flags >> PATCH_MATID_SHIFT) & PATCH_MATID_MASK;
				// No need to research the associated Virtools material if material index is the same
				if (MatID != PreviousMatId) {
					PatchMtl = GetMaterialByIndex(nodeMtl,MatID,mp,mtlKey);
					VirtoolsMat = VirtoolsExporter->GetMaterialByKey(mtlKey);
					useUVGen = GetTextureUvGen(PatchMtl,uvgen);
				}
				PreviousMatId = MatID;

				if (tvp.tv) {
					int nb = (pmesh->patches[i].type == PATCH_TRI) ? 3 : 4;

					for (int j=0;j<nb;++j) {
						VxUV uv;

						CopyUV(&uv,&pmesh->getMapVert(mp,tvp.tv[j]));
						ApplyUvGen(uv,uvgen,useUVGen); 

						Virtoolstvp.tv[j] = tvp.tv[j];
						VirtoolsPMesh->SetTV(tvp.tv[j],uv.u,uv.v,PatchChannelCount-1);
					}
					VirtoolsPMesh->SetTVPatch(i,&Virtoolstvp,PatchChannelCount-1);
				}
			}

			PatchChannelCount++;
		}
	}

	ent->SetCurrentMesh(VirtoolsPMesh);
	InsertNewMeshInstance(os.obj,nodeMtl,VirtoolsPMesh);

	if (needDel) {
		delete patch;
	}
}

Point3 Max2Nmo::GetVertexNormal(Mesh* mesh, int faceNo, RVertex* rv)
{
	Face* f = &mesh->faces[faceNo];
	DWORD smGroup = f->smGroup;
	int numNormals;
	Point3 vertexNormal;
	
	// Is normal specified
	// SPCIFIED is not currently used, but may be used in future versions.
	if (rv->rFlags & SPECIFIED_NORMAL) {
		vertexNormal = rv->rn.getNormal();
	}
	// If normal is not specified it's only available if the face belongs
	// to a smoothing group
	else if ((numNormals = rv->rFlags & NORCT_MASK) && smGroup) {
		// If there is only one vertex is found in the rn member.
		if (numNormals == 1) {
			vertexNormal = rv->rn.getNormal();
		}
		else {
			// If two or more vertices are there you need to step through them
			// and find the vertex with the same smoothing group as the current face.
			// You will find multiple normals in the ern member.
			for (int i = 0; i < numNormals; i++) {
				if (rv->ern[i].getSmGroup() & smGroup) {
					vertexNormal = rv->ern[i].getNormal();
				}
			}
		}
	}
	else {
		// Get the normal from the Face if no smoothing groups are there
		vertexNormal = mesh->getFaceNormal(faceNo);
	}
	
	return vertexNormal;
}



/****************************************************************************

  Material and Texture Export
  
****************************************************************************/
void Max2Nmo::ExportMaterialList()
{
	//--- Initialize the lightmap base materials hash table
	m_lightmapBaseMaterials.Clear();

	//--- Parse all 3dsmax materials
	int numMtls = mtlList.Count();
	for (int i=0; i<numMtls; i++) {
		DumpMaterial(mtlList.GetMtl(i));
	}
}


void Max2Nmo::DumpMaterial(Mtl* mtl)
{
	Report(REPORT_HLEVEL,"%s...",mtl->GetName());

	if (!mtl) return;
	if (VirtoolsExporter->GetMaterialByKey(mtl)) return ;

	TimeValue t = GetStaticFrame();
	
	// We know the Standard material, so we can get some extra info
	if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) {

		StdMat* std = (StdMat*)mtl;

		VirtoolsMaterial NMat;
		TextureUVGen uvgen;
		BOOL useUVGen = FALSE;
		Color Ambient		= std->GetAmbient(t);
		Color Diffuse		= std->GetDiffuse(t);
		Color Specular		= std->GetSpecular(t);
		float Shininess		= std->GetShininess(t);
		float ShinStr		= std->GetShinStr(t);
		float Transparency	= std->GetXParency(t);
		float selfIllum		= std->GetSelfIllum(0);
		BOOL selfIllumColorOn=FALSE;
		Color Emissive;

		useUVGen = GetTextureUvGen(mtl,uvgen);

		//--- Get self Illumn color information
		StdMat2* stdmat2=(StdMat2*)std;
		if (stdmat2->SupportsShaders()) {
			Shader* shader=stdmat2->GetShader();
			if (shader) {
				selfIllumColorOn=shader->IsSelfIllumClrOn();
				Emissive=shader->GetSelfIllumClr(0);
			}
		}
		NMat.m_Diffuse		= VxColor(Diffuse.r,Diffuse.g,Diffuse.b,1.0f-Transparency);
		NMat.m_Ambient		= VxColor(Ambient.r,Ambient.g,Ambient.b);
		NMat.m_Specular		= VxColor(Specular.r,Specular.g,Specular.b);
		NMat.m_Emissive		= selfIllum*NMat.m_Diffuse;
		NMat.m_TwoSided		= std->GetTwoSided();
		NMat.m_FillMode		= std->GetWire() ? VXFILL_WIREFRAME : VXFILL_SOLID;
		NMat.m_ShadeMode	= std->GetShading() == SHADE_CONST ?  VXSHADE_FLAT : VXSHADE_GOURAUD;
		if (selfIllumColorOn) 
			NMat.m_Emissive		= VxColor(Emissive.r,Emissive.g,Emissive.b);
		if (Transparency) {
			NMat.m_AlphaBlending	= TRUE;
			NMat.m_SrcBlendFactor	= VXBLEND_SRCALPHA;
			NMat.m_DstBlendFactor	= VXBLEND_INVSRCALPHA;
			NMat.m_ZWriteEnable		= FALSE;
		}

		// TODO
		switch (std->GetTransparencyType()) {
			case TRANSP_FILTER:			break;
			case TRANSP_SUBTRACTIVE:	break;
			case TRANSP_ADDITIVE:		break;
		}

		//--- Look for texture (diffuse only) 
		Texmap*		pTexmap;
		BitmapTex*  pBmpTex;
		BOOL TexValid = FALSE;
		BOOL OpacityValid = FALSE;
		int TexWidth = 0;
		int TexHeight = 0;

#ifdef MAX51		
		//--- Araya: If the material has a lightmap shader in the viewport
		///// then use the lightmap base texture instead of the diffusemap texture
		///// and add a new material/texture, the lightmap.
		if( LM::ShaderEnabled(mtl) ){
			
			VxColor white( 1.0f, 1.0f, 1.0f, 1.0f );
			VxColor black( 0.0f, 0.0f, 0.0f, 1.0f );

			BOOL baseMaterialAlreadyExists = FALSE;

			//--- Add base texture
			if( LM::BaseTextureEnabled(mtl) ){
				
				XString baseTextureFilename = LM::BaseTextureFilename(mtl);
				CKPathSplitter psplitter( baseTextureFilename.Str() );
				//--- Note: the texture is added only if there's no texture with
				///// the same filename already added.
				NMat.m_Texture  = VirtoolsExporter->AddTexture( 
					baseTextureFilename.CStr(), 
					(const char *)psplitter.GetName() );
				NMat.m_Emissive = white;

				//--- If there's a similar material already added, then use it,
				///// it must be the first created lightmap diffuse map 
				///// refering to the same texture
				XHashTable< Mtl*, XString, XHashFun<XString> >::Iterator it = 
					m_lightmapBaseMaterials.Find( baseTextureFilename );

				if( it!=m_lightmapBaseMaterials.End() ){
					baseMaterialAlreadyExists = TRUE;
				} else {
					//--- Else, add this material to the list of unique lightmap base textures 
					m_lightmapBaseMaterials.Insert( baseTextureFilename, mtl );
				}
			}
			//--- Add lightmap texture
			if( LM::LightmapTextureEnabled(mtl) ){
				
				VirtoolsMaterial LMMat;
				XString lightTextureFilename = LM::LightmapTextureFilename(mtl);
				CKPathSplitter psplitter( lightTextureFilename.Str() );
				LMMat.m_Texture  = VirtoolsExporter->AddTexture( 
					lightTextureFilename.CStr(), 
					(const char *)psplitter.GetName() );
				LMMat.m_TextureBlendMode =  VXTEXTUREBLEND_MODULATEALPHA;
				
				LMMat.m_Diffuse			= white;
				LMMat.m_Ambient			= white;
				LMMat.m_Specular		= black;
				LMMat.m_Emissive		= white;
				LMMat.m_TwoSided		= NMat.m_TwoSided;
				LMMat.m_FillMode		= NMat.m_FillMode;
				LMMat.m_ShadeMode		= NMat.m_ShadeMode;

				//--- ~ little trick for lightmap material
				void* keyToFindBackMaterial = (void*)~(DWORD)mtl;
				CKMaterial* mat = VirtoolsExporter->AddMaterial( &LMMat, 
					(const char *)psplitter.GetName(),
					keyToFindBackMaterial );
				mat->SetTextureAddressMode( VXTEXTURE_ADDRESSCLAMP );
			}
		
			if( baseMaterialAlreadyExists ) return;

		//--- Material is standard (without any shader effect)
		} else 
#endif			
		{
			if(std->MapEnabled(ID_DI) || std->MapEnabled(ID_SI)) {
				int MapToRetrieve = std->MapEnabled(ID_DI) ? ID_DI : ID_SI;
				
				float MixAmount = std->GetTexmapAmt(MapToRetrieve,0);
				// If Amount is 100 % the diffuse color is not taken into account
				// (equivalent to DECAL_MODE) in Virtools
				//  14.11.200 Removed since people are most of the time 
				// waiting for a modulate mode
				//			if (MixAmount<1) NMat.m_TextureBlendMode =  VXTEXTUREBLEND_MODULATEALPHA;
				//				else		 NMat.m_TextureBlendMode = 	VXTEXTUREBLEND_DECAL;


				NMat.m_TextureBlendMode =  VXTEXTUREBLEND_MODULATEALPHA;
				
				if(pTexmap = std->GetSubTexmap(MapToRetrieve)) {
					if(pTexmap->ClassID()==Class_ID(BMTEX_CLASS_ID,0)) {
						pBmpTex = (BitmapTex*)pTexmap;
						Bitmap* bm=pBmpTex->GetBitmap(0);

						XString diffuseFileName=pBmpTex->GetMapName();
						CKPathSplitter psplitter(diffuseFileName.Str());
						NMat.m_Texture  = VirtoolsExporter->AddTexture(diffuseFileName.CStr(),(const char *)psplitter.GetName(),pBmpTex);

						// Check if texture is valid for Virtools
						int flg=0;
						
					
						if(bm==NULL)  {
							Report(REPORT_HLEVEL,"\r\n%s : file not found...\r\n",pBmpTex->GetMapName());
						} else	{ // Test power of 2 
							TexValid = TRUE;
							TexWidth = bm->Width();
							TexHeight = bm->Height();
							DWORD w=(DWORD)bm->Width();
							DWORD h=(DWORD)bm->Height();
						
							DWORD mask;
							mask=0xFFFFFFFF;
							mask>>=(32-GetMSB(w));
							mask=w&mask;
							if(mask) flg=1;
						
							mask=0xFFFFFFFF;
							mask>>=(32-GetMSB(h));
							mask=h&mask;
							if(mask) flg=1;
						
							if(flg) {
								Report(REPORT_HLEVEL,"\r\nWarning %s :w:%d - h:%d\r\nThe width and height of the bitmap must be a power of 2 (2,4,8 ... 256,512)\r\n",pBmpTex->GetMapName(),w,h);
							}
						}
					}
				}
			}

			if(NMat.m_Texture && TexValid && std->MapEnabled(ID_OP)) {
				if (pTexmap = std->GetSubTexmap(ID_OP)) {
					if(pTexmap->ClassID()==Class_ID(BMTEX_CLASS_ID,0)) {
						pBmpTex = (BitmapTex*)pTexmap;
						Bitmap* bm = pBmpTex->GetBitmap(0);
						if (bm) {
							Report(REPORT_LLEVEL,"\r\nGenerating alpha from opacity map : %s\r\n",pBmpTex->GetMapName());
							int BmpWidth	= bm->Width();
							int BmpHeight	= bm->Height();
							if ((BmpWidth == TexWidth) &&  (BmpHeight == TexHeight)) {
								int Stride		= BmpWidth*sizeof(DWORD);
								BYTE* ptr = NMat.m_Texture->LockSurfacePtr();
								
								if (ptr) {
									// Go to alpha value 
									ptr+=3;
									XArray<WORD> Pixels;
									Pixels.Resize(BmpWidth);

									for (int i=0; i< BmpHeight; ++i,ptr+=Stride) {
										int res = bm->Get16Gray(0,i,BmpWidth,Pixels.Begin());
										BYTE* pix =  (BYTE *)Pixels.Begin();
										++pix;
										BYTE* tptr = ptr; 
										for (int j=0;j<BmpWidth;++j,pix+=2,tptr+=4) {
											*tptr = *pix;
										}
									}

									OpacityValid = TRUE;
									NMat.m_AlphaBlending	= TRUE;
									NMat.m_SrcBlendFactor	= VXBLEND_SRCALPHA;
									NMat.m_DstBlendFactor	= VXBLEND_INVSRCALPHA;
									NMat.m_Diffuse.a		= 1.0f; // Opacity value is not taken when 
									// giving a opacity map
								}
							} else {
								Report(REPORT_HLEVEL,"\r\nOpacity map : %s must be the same size than the diffuse texture...\r\n",pBmpTex->GetMapName());
							}
						} else {
							Report(REPORT_HLEVEL,"\r\nOpacity map : %s not found...\r\n",pBmpTex->GetMapName());
						} 
					}
				}
			}
		}
		
		CKMaterial* mat = VirtoolsExporter->AddMaterial(&NMat,mtl->GetName(),mtl);	
		//if (!(uvgen.MirrorU	|| uvgen.TileU || uvgen.MirrorV || uvgen.TileV))
		//	mat->SetTextureAddressMode(VXTEXTURE_ADDRESSCLAMP);
		//else 
		if( useUVGen ){
			if (uvgen.MirrorU	&& uvgen.MirrorV)
				mat->SetTextureAddressMode(VXTEXTURE_ADDRESSMIRROR); // Will this be supported by video card in Virtools ????

			if (uvgen.UOffset!=0 || uvgen.UScale!=1.0f || uvgen.VOffset!=0 || uvgen.VScale!=1.0f) {
				if (uvgen.Cropping && (uvgen.UOffset!=0  || uvgen.UScale!=1.0f || uvgen.VOffset!=0 || uvgen.VScale!=1.0)) {
					// Cropping and (tiling/mirroring) are used together warn the
					// user that the conversion may not work 
					Report(REPORT_HLEVEL,"\r\nCropping and (tiling or mirroring) are used on this texture\r\n and may generate incorrect results in Virtools\r\n");
				}
			}
		}
		
		// Opacity map is valid , we enable Alpha testing
		// 
		if (OpacityValid) {
			mat->EnableAlphaTest(TRUE);
			mat->SetAlphaRef(1);
			mat->SetAlphaFunc(VXCMP_GREATER);
			// At least 1 bit of alpha should be here for 
			// the display to be correct
			NMat.m_Texture->SetDesiredVideoFormat(_16_ARGB1555);
		}

	}
	Report(REPORT_HLEVEL,"Done\r\n");
#ifdef MAX51	
	// Baked Shell Material
	if( mtl->ClassID() == Class_ID(BAKE_SHELL_CLASS_ID, 0)){
		if( mtl->NumSubMtls() >= 2 ){
			Mtl* bakedMaterial = mtl->GetSubMtl(1);

			//If baked material is only configured to use
			//self illum we must certainly also consider the first material
			if (bakedMaterial && bakedMaterial->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) {
				StdMat* std = (StdMat*)bakedMaterial;
				if (!std->MapEnabled(ID_DI) && std->MapEnabled(ID_SI)) {
					DumpMaterial( mtl->GetSubMtl(0));	
				}
			}
			if( bakedMaterial ){
				DumpMaterial( bakedMaterial );
			}
		}
	} else 
#endif
	// Sub Materials	
	if (mtl->NumSubMtls() > 0)  {
		for (int i=0; i<mtl->NumSubMtls(); i++) {
			Mtl* subMtl = mtl->GetSubMtl(i);
			if (subMtl) {
				DumpMaterial(subMtl);
			}
		}
	}

	
}



/****************************************************************************

  Misc Utility functions
  
****************************************************************************/


// Determine is the node has negative scaling.
// This is used for mirrored objects for example. They have a negative scale factor
// so when calculating the normal we should take the vertices counter clockwise.
// If we don't compensate for this the objects will be 'inverted'.
// But People should never use Mirror !!!! 
BOOL Max2Nmo::TMNegParity(Matrix3 &m)
{
	return (DotProd(CrossProd(m.GetRow(0),m.GetRow(1)),m.GetRow(2))<0.0)?1:0;
}

// Return a pointer to a TriObject given an INode or return NULL
// if the node cannot be converted to a TriObject
TriObject* Max2Nmo::GetTriObjectFromNode(INode *node, TimeValue t, int &deleteIt)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -