c#开发环境下用Directx载入3D模型

来源:互联网 发布:python 创建临时文件 编辑:程序博客网 时间:2024/05/27 10:44

Direcx一般都是用VC++开发环境,而c#相关的资料比较少,最近做的一个项目中需要用到一个3D模型,而开发环境是visual c#,没办法,就四处搜集资料,查找相关的资料,然后找到了几篇相关的博文,不过这些博文说的都不太仔细,有些内容又丢失了一些关键代码,这个时候就需要我们自己搜集资料,自己学习来补全这些关键代码了。

废话少说,我们直接说说步骤吧。

.首先要准备一个3D模型,现在3D模型都是.max或者.obj或者别的格式的,不过因为我用的是Directx9.0开发环境,因此载入3D模型的时候需要把文件转换为.X格式,没有关系,我们可以下载一个3dsMax软件,然后装上微软的panda插件,这个软件就能把.max格式的3d文件转换为.x格式输出。这一步我们最主要的目的就是为了得到一个.x格式的3D模型。

.接下来就是下载Directx9.0Sdk了,下载完成之后安装这个开发工具。

.接下来进入项目,新建一个Visual c# winform窗体程序,然后点击确定,我们的编程工作就开始了。

          首先,项目需要用到Directx开发包,因此我们需要给项目添加引用,右键单击项目,选择添加引用,然后在引用的对话框中选择浏览,这里引用的位置是:C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0,注意最后的应用的文件夹是1.0.2902.0,我们引用这里面的三个文件:DirectX.dll ,DirectX3D.dll 和DirectX3DX.dll,选择这三项之后点击确定,之后就添加了引用,然后我们还需要在窗体代码中添加如下引用:

[csharp] view plain copy
  1. using Microsoft.DirectX;  
  2. using Microsoft.DirectX.Direct3D;   
之后我们的引用工作算是完成了。

因为我准备把3D模型显示在一个控件上,我选择了一个Panel控件放到主窗口上,我们的模型待会儿就会显示在这个panel上。首先在Form中设置如下几个全局变量:

[csharp] view plain copy
  1. #region  
  2.         //保存3D文件  
  3.         private Mesh mesh = null;  
  4.           
  5.         //设备  
  6.         private Device device = null;  
  7.         //材质  
  8.         private Material[] meshMaterials;  
  9.     private Texture[] meshTextures;   
  10.           
  11.         //获取当前程序的Debug路径  
  12.         string path = System.Windows.Forms.Application.StartupPath;   
  13.          
  14.         //角度   
  15.         private float angle = 0.0f;   
  16.     #endregion  

然后写出我们的初始化图形设备的函数:

[csharp] view plain copy
  1. <span style="font-size:14px;">        //初始化图形设备  
  2.         public void InitializeGraphics()  
  3.         {  
  4.             //设置变量  
  5.             PresentParameters presentParams = new PresentParameters();  
  6.             //设置在窗口模式下运行  
  7.             presentParams.Windowed = true;  
  8.             //设置交换效果为Discard  
  9.             presentParams.SwapEffect = SwapEffect.Discard;  
  10.             presentParams.AutoDepthStencilFormat = DepthFormat.D16;  
  11.             presentParams.EnableAutoDepthStencil = true;  
  12.             //创建设备  
  13.             //因为我显示在panel1中,所以device中的第三个变量是panel的名字  
  14.             device = new Device(0, DeviceType.Hardware, panel1,  
  15.                 CreateFlags.SoftwareVertexProcessing, presentParams);  
  16.             //我的3D文件在Debug中的Model文件中,因此temp获取了3D模型的地址  
  17.             string temp = path;  
  18.             temp = temp + "\\Model\\Model.X";  
  19.             //这个函数用于载入3D模型并且保存在mesh中  
  20.             LoadMesh(temp);  
  21.         }</span>  

然后是载入3D模型的LoadMesh(string file) 函数

[csharp] view plain copy
  1. private void LoadMesh(string file)  
  2. {  
  3.     ExtendedMaterial[] mtrl = null;  
  4.     //载入  
  5.     try  
  6.     {  
  7.         mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl);  
  8.         //有材质的话,则载入  
  9.         if ((mtrl != null) && (mtrl.Length > 0))  
  10.         {  
  11.             //这两个就是前面定义的全局变量,保存材质和纹理  
  12.             meshMaterials = new Material[mtrl.Length];  
  13.             meshTextures = new Texture[mtrl.Length];  
  14.   
  15.             for (int i = 0; i < mtrl.Length; ++i)  
  16.             {  
  17.                 /*当前的temp是Debug下的Model文件, 
  18.                 *Model文件中有保存纹理和材质的文件 
  19.                  */  
  20.                 string temp = path + "\\Model\\";  
  21.                 meshMaterials[i] = mtrl[i].Material3D;  
  22.                 if ((mtrl[i].TextureFilename != null)  
  23.                     && mtrl[i].TextureFilename != string.Empty)  
  24.                 {  
  25.                     meshTextures[i] = TextureLoader.FromFile(device, temp + mtrl[i].TextureFilename);  
  26.                 }  
  27.             }  
  28.         }  
  29.     }  
  30.     catch (Direct3DXException ex)  
  31.     {  
  32.         MessageBox.Show(ex.ToString());  
  33.         return;  
  34.     }  
  35. }  



载入模型之后就需要将模型画出来,因此,还需要一个画模型的函数:

[csharp] view plain copy
  1. //绘制mesh的材质和纹理  
  2.  private void DrawMesh(float yaw, float pitch, float roll, float x, float y, float z)  
  3.  {  
  4.      angle += 0.01f;  
  5.      device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z);  
  6.      for (int i = 0; i < meshMaterials.Length; ++i)  
  7.      {  
  8.          //设置材质  
  9.          device.Material = meshMaterials[i];  
  10.          //设置纹理  
  11.          device.SetTexture(0, meshTextures[i]);  
  12.          //绘制  
  13.          mesh.DrawSubset(i);  
  14.      }  
  15.  }  

最后还差一个摄影灯光的设置了,这个用于灯光的角度:

[csharp] view plain copy
  1. //设置摄像头  
  2. private void SetupCamera()  
  3. {  
  4.     //(float)Math.PI/12设置对象大小  
  5.     device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 12, this.Width / this.Height, 0.80f, 10000.0f);  
  6.     device.Transform.View = Matrix.LookAtLH(new Vector3(-400, -100, 600.0f), new Vector3(), new Vector3(0, 1, 0));  
  7.     device.RenderState.Ambient = Color.Black;  
  8.     device.Lights[0].Type = LightType.Directional;  
  9.     device.Lights[0].Diffuse = Color.AntiqueWhite;  
  10.     device.Lights[0].Direction = new Vector3(0, 1, 0);  
  11.     device.Lights[0].Update();  
  12.     device.Lights[0].Enabled = true;  
  13. }  


至此,基本大功告成,最后的是逐步调用这几个函数,然后显示出来,我采用panel这个控件绘画的时候调用这些函数,如下:

[csharp] view plain copy
  1. //panelPaint是我自己起的名字,对应的事件是Paint  
  2. private void panelPaint(object sender, PaintEventArgs e)  
  3. {  
  4.     InitializeGraphics();  
  5.     device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.SkyBlue, 1.0f, 1);  
  6.     SetupCamera();  
  7.     device.Present();  
  8.     device.BeginScene();  
  9.     // Draw our Mesh  
  10.     DrawMesh(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI / 4.0f, 0.0f, 0.0f, 0.0f);  
  11.     device.EndScene();  
  12.     //Render();  
  13.     device.Present();  
  14.    // this.Invalidate();  
  15. }  

最后贴出来一个效果图:


至此,基本大功告成。不过这里还有几个问题要说明:

1.程序编译过程中或许会遇到一个问题:

混合模式程序集是针对“v1.1.4322”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。

这个问题解决办法就是打开文件中的app.config文件,注释掉原来的内容,改成以下内容:

[html] view plain copy
  1. <span style="font-size:14px;"><span style="font-family:'Microsoft YaHei';"><?xml version="1.0"?>  
  2. <configuration>  
  3.   <startup useLegacyV2RuntimeActivationPolicy="true">  
  4.     <supportedRuntime version="v4.0"/>  
  5.   </startup>  
  6. </configuration></span></span>  
程序应该就不会有问题了。

2.如果你自己在导入自己的3D模型的时候,采用3dsmax中导入的panda控件转换模型文件为.x文件的时候,有个选项,就是XFileSetting的设置一定要设置为Binary,如果设置为Text的话,Directx在读入文件的时候会不识别。截图如下:

能遇到的问题基本就这些了,这里附上源代码链接:

http://download.csdn.net/detail/t46414704152abc/8709251

恩,基本就这样了!希望能帮助到大家!

原创粉丝点击