Mesh类中定义了若干个3D模型,比如说立方体、圆柱、茶壶等。对于一些复杂的模型可以使用专业的软件比如说3D Max等设计,再利用DirectX提供的插件,将复杂的3D模型保存为.x文件。用Mesh类对象可以加载.x文件,并显示.x文件中的3D模型。Mesh类位于Direct 3D的扩展库中,为了使用Mesh类必须引用Microsoft.DirectX.Direct3DX组件。
可以用Mesh类创建一个茶壶,
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace 显示茶壶 { public partial class Form1 : Form { private Device device = null; bool pause = false; Mesh mesh = null; Material meshMaterials; float Angle = 0, ViewZ = -5.0f; public Form1() { InitializeComponent(); } public bool InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; //不是全屏显示,在一个窗口显示 presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式 presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试 //深度缓冲区单元为16位二进制数 presentParams.AutoDepthStencilFormat = DepthFormat.D16; device = new Device(0, DeviceType.Hardware, this, //建立设备类对象 CreateFlags.SoftwareVertexProcessing, presentParams); //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice device.DeviceReset += new System.EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null);//自定义方法,初始化Device的工作放到这个方法中 this.OnResetDevice(device, null);//调用设备重置事件(device.DeviceReset)事件函数 } //设备重置事件函数要设置Device参数,初始函数中必须调用该函数 catch (DirectXException) { return false; } return true; } public void OnCreateDevice(object sender, EventArgs e) { mesh = Mesh.Teapot(device); meshMaterials = new Material(); meshMaterials.Ambient = System.Drawing.Color.White; //材质如何反射环境光 meshMaterials.Diffuse = System.Drawing.Color.White; //材质如何反射灯光 } public void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; dev.RenderState.ZBufferEnable = true; //允许使用深度缓冲 dev.RenderState.Ambient = Color.Black; //环境光为深蓝色 dev.Lights[0].Type = LightType.Directional; //设置灯光类型 dev.Lights[0].Diffuse = Color.White; //设置灯光颜色 dev.Lights[0].Direction = new Vector3(0, -1, 1); //设置灯光位置 dev.Lights[0].Update(); //更新灯光设置,创建第一盏灯光 dev.Lights[0].Enabled = true; //使设置有效 dev.Material = meshMaterials; //指定设备的材质 } public void Render() //渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架 { if (device == null) //如果未建立设备对象,退出 return; if (pause) return; device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0); device.BeginScene(); //开始渲染 SetupMatrices(); //矩阵变换 mesh.DrawSubset(0); //显示茶壶,见5.12.6节 device.EndScene(); //渲染结束 device.Present(); //更新显示区域,把后备缓存的3D图形送到图形卡的屏幕显示区中显示 } private void Form1_Paint(object sender, PaintEventArgs e) { this.Render(); } private void Form1_Resize(object sender, EventArgs e) { pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible); } void SetupMatrices() { device.Transform.World = Matrix.RotationYawPitchRoll(Angle, Angle, 0);//世界变换 device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 1.0f, ViewZ),//观察变换矩阵 new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); device.Transform.Projection = Matrix.PerspectiveFovLH( //设置投影变换矩阵 (float)(Math.PI / 4), 1.33f, 1.0f, 100.0f); } private void Form1_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) //e.KeyCode是键盘每个键的编号 { case Keys.Left: //Keys.Left是左箭头键编号,茶壶左移 Angle += 0.1F; break; case Keys.Right: //茶壶右移 Angle -= 0.1F; break; case Keys.Down: //茶壶下移 ViewZ += 1; break; case Keys.Up: //茶壶上移 ViewZ -= 1; break; } } private void Form1_Load(object sender, EventArgs e) { InitializeGraphics(); this.Show(); Render(); } } }
建模时创建的3D模型可以多次使用,在渲染前按照3D模型在世界空间中的摆放位置修改为Device类的世界变换矩阵,然后调用3D模型的渲染函数,就可以把3D模型场景中的不同位置。使用Mesh类也可以创建立方体模型,但是立方体模型顶点并不具有纹理坐标,为了给立方体的六个面增加纹理,可以克隆一个新的立方体模型,让这个克隆的立方体模型具有纹理坐标,然后为纹理坐标赋值,在渲染函数中渲染这个克隆的3D模型,就可以实现纹理的效果。利用Mesh类还可以创建3D字体。也可以利用Mesh类对象从.x文件中读入模型,下面给出一个从.x文件读取立体化老虎的例子。立体老虎保存在tiger.x中,纹理保存在tiger.bmp中。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Mesh读取x文件 { public partial class Form1 : Form { private Device device = null; bool pause = false; Mesh mesh = null; Material meshMaterials; Texture[] meshTextures; Microsoft.DirectX.Direct3D.Material[] meshMaterials1; float Angle = 0, ViewZ = -5.0f; public Form1() { InitializeComponent(); } public bool InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; //不是全屏显示,在一个窗口显示 presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式 presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试 //深度缓冲区单元为16位二进制数 presentParams.AutoDepthStencilFormat = DepthFormat.D16; device = new Device(0, DeviceType.Hardware, this, //建立设备类对象 CreateFlags.SoftwareVertexProcessing, presentParams); //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice device.DeviceReset += new System.EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null);//自定义方法,初始化Device的工作放到这个方法中 this.OnResetDevice(device, null);//调用设备重置事件(device.DeviceReset)事件函数 } //设备重置事件函数要设置Device参数,初始函数中必须调用该函数 catch (DirectXException) { return false; } return true; } public void OnCreateDevice(object sender, EventArgs e) { meshMaterials = new Material(); meshMaterials.Ambient = System.Drawing.Color.White; //材质如何反射环境光 meshMaterials.Diffuse = System.Drawing.Color.White; //材质如何反射灯光 ExtendedMaterial[] materials = null; //下句从tiger.x文件中读入3D图形(立体老虎) mesh = Mesh.FromFile(@"..\..\..\tiger.x", MeshFlags.SystemMemory, device, out materials); if (meshTextures == null)//如果还未设置纹理,为3D图形增加纹理和材质 { meshTextures = new Texture[materials.Length];//纹理数组 meshMaterials1 = new Microsoft.DirectX.Direct3D.Material[materials.Length];//材质数组 for (int i = 0; i < materials.Length; i++)//读入纹理和材质 { meshMaterials1[i] = materials[i].Material3D; meshMaterials1[i].Ambient = meshMaterials1[i].Diffuse; meshTextures[i] = TextureLoader.FromFile(device, @"..\..\..\" + materials[i].TextureFilename); } } } public void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; dev.RenderState.ZBufferEnable = true; //允许使用深度缓冲 dev.RenderState.Ambient = System.Drawing.Color.White;//设定环境光为白色 dev.Lights[0].Type = LightType.Directional; //设置灯光类型 dev.Lights[0].Diffuse = Color.White; //设置灯光颜色 dev.Lights[0].Direction = new Vector3(0, -1, 0); //设置灯光位置 dev.Lights[0].Update(); //更新灯光设置,创建第一盏灯光 dev.Lights[0].Enabled = true; //使设置有效 dev.Material = meshMaterials; //指定设备的材质 } public void Render() //渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架 { if (device == null) return; device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0); device.BeginScene(); SetupMatrices(); for (int i = 0; i < meshMaterials1.Length; i++)//Mesh中可能有多个3D图形,逐一显示 { device.Material = meshMaterials1[i];//设定3D图形的材质 device.SetTexture(0, meshTextures[i]);//设定3D图形的纹理 mesh.DrawSubset(i);//显示该3D图形 } device.EndScene(); device.Present(); } private void Form1_Paint(object sender, PaintEventArgs e) { this.Render(); } private void Form1_Resize(object sender, EventArgs e) { pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible); } void SetupMatrices() { device.Transform.World = Matrix.RotationY(Angle);//世界变换,下条为观察变换矩阵 device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 3.0f, ViewZ), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); device.Transform.Projection = Matrix.PerspectiveFovLH((float)(Math.PI / 4), 1.0f, 1.0f, 100.0f); //设置投影变换矩阵 } private void Form1_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) //e.KeyCode是键盘每个键的编号 { case Keys.Left: //Keys.Left是左箭头键编号,老虎左移 Angle += 0.1F; break; case Keys.Right: //老虎右移 Angle -= 0.1F; break; case Keys.Down: //老虎变小 ViewZ += 1; break; case Keys.Up: //老虎变大 ViewZ -= 1; break; } } private void Form1_Load(object sender, EventArgs e) { InitializeGraphics(); this.Show(); Render(); } } }
也可以Mesh类模拟地形图。地形的模拟分为两类,一类是真实地形,另一类是模拟地形。必须使用采集自真实世界的具体数据来构造。要生成地形图,首先在XZ平面上生成一副平面图,然后根据数字高程数据,逐点修改XZ平面上每一点的Y坐标。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace 地形 { public partial class Form1 : Form { private Device device = null; bool pause = false; Mesh mesh = null; Material[] meshMaterials1; Texture[] meshTextures; public Form1() { InitializeComponent(); } public bool InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; //不是全屏显示,在一个窗口显示 presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式 presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试 //深度缓冲区单元为16位二进制数 presentParams.AutoDepthStencilFormat = DepthFormat.D16; device = new Device(0, DeviceType.Hardware, this, //建立设备类对象 CreateFlags.SoftwareVertexProcessing, presentParams); //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice device.DeviceReset += new System.EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null);//自定义方法,初始化Device的工作放到这个方法中 this.OnResetDevice(device, null);//调用设备重置事件(device.DeviceReset)事件函数 } //设备重置事件函数要设置Device参数,初始函数中必须调用该函数 catch (DirectXException) { return false; } return true; } public void OnCreateDevice(object sender, EventArgs e) { Device dev = (Device)sender; ExtendedMaterial[] materials = null; mesh = Mesh.FromFile(@"..\..\..\seafloor.x", MeshFlags.SystemMemory, device, out materials); if (meshTextures == null) //如果还未设置纹理,为D图形增加纹理和材质 { meshTextures = new Texture[materials.Length]; //纹理数组 meshMaterials1 = new Material[materials.Length]; //材质数组 for (int i = 0; i < materials.Length; i++) //读入纹理和材质 { meshMaterials1[i] = materials[i].Material3D; meshMaterials1[i].Ambient = meshMaterials1[i].Diffuse; meshTextures[i] = TextureLoader.FromFile(device, @"..\..\..\" + materials[i].TextureFilename); } } //下条语句克隆mesh对象,使其包含位置、法线和纹理坐标 Mesh mesh1 = mesh.Clone(mesh.Options.Value, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture0 | VertexFormats.Texture1, mesh.Device); using (VertexBuffer vb = mesh1.VertexBuffer) //得到mesh1记录顶点的缓冲区引用 { CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[]) vb.Lock(0, typeof(CustomVertex.PositionNormalTextured), LockFlags.None, mesh1.NumberVertices); try { for (int i = 0; i < verts.Length; i++) { verts[i].Y = HeightField(verts[i].X, verts[i].Z); } mesh = mesh1; } finally { vb.Unlock(); } } } public void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; dev.RenderState.ZBufferEnable = true; //允许使用深度缓冲,意义见.12.5节 dev.RenderState.Ambient = Color.FromArgb(255, 200, 200, 200); //环境光为黑色 dev.RenderState.Lighting = true; dev.TextureState[0].ColorArgument1 = TextureArgument.TextureColor; dev.TextureState[0].ColorOperation = TextureOperation.SelectArg1; dev.SamplerState[0].MinFilter = TextureFilter.Linear; dev.SamplerState[0].MagFilter = TextureFilter.Linear; SetupMatrices(); } public void Render() //渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架 { if (device == null) //如果未建立设备对象,退出 return; int iTime = Environment.TickCount % 100000; float Angle = iTime * (2.0f * (float)Math.PI) / 100000.0f; device.Transform.World = Matrix.RotationY(Angle); device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Blue, 1.0f, 0); device.BeginScene();//开始渲染 for (int i = 0; i < meshMaterials1.Length; i++) //Mesh中可能有多个D图形,逐一显示 { device.Material = meshMaterials1[i]; //设定D图形的材质 device.SetTexture(0, meshTextures[i]); //设定D图形的纹理 mesh.DrawSubset(i); //显示该D图形 } device.EndScene();//渲染结束 device.Present();//更新显示区域,把后备缓存的D图形送到显卡的显存中显示 } private void Form1_Paint(object sender, PaintEventArgs e) { this.Render(); } private void Form1_Resize(object sender, EventArgs e) { pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible); } private void SetupMatrices() { device.Transform.World = Matrix.Identity; //世界坐标 device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 30.0f, -100.0f), //观察变换 new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 200.0f); //投影变换 } float HeightField(float x, float z) //参数为图形某点的X、Z轴坐标 { float y = 0.0f; y += (float)(10.0f * Math.Cos(0.051f * x + 0.0f) * Math.Sin(0.055f * x + 0.0f)); y += (float)(10.0f * Math.Cos(0.053f * z + 0.0f) * Math.Sin(0.057f * z + 0.0f)); y += (float)(2.0f * Math.Cos(0.101f * x + 0.0f) * Math.Sin(0.105f * x + 0.0f)); y += (float)(2.0f * Math.Cos(0.103f * z + 0.0f) * Math.Sin(0.107f * z + 0.0f)); y += (float)(2.0f * Math.Cos(0.251f * x + 0.0f) * Math.Sin(0.255f * x + 0.0f)); y += (float)(2.0f * Math.Cos(0.253f * z + 0.0f) * Math.Sin(0.257f * z + 0.0f)); return y; //返回修改后的Y轴方向上的坐标 } private void Form1_Load(object sender, EventArgs e) { InitializeGraphics(); this.Show(); Render(); } } }
当观察者距离物体较远时,3D物体需要较少的细节,也就是说这个3D物体所需的顶点数和面数应该较少。使用Direct 3D中的ProgressiveMesh类可以解决这个问题。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; using System.IO; namespace 层次细节Mesh { public partial class Form1 : Form { private Device device = null; bool pause = false; Mesh mesh = null; Material meshMaterials; Texture[] meshTextures; Microsoft.DirectX.Direct3D.Material[] meshMaterials1; float Angle = 0, ViewZ = -5.0f; Mesh mesh1 = null; int key; ProgressiveMesh mesh2; public Form1() { InitializeComponent(); } public bool InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; //不是全屏显示,在一个窗口显示 presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式 presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试 //深度缓冲区单元为16位二进制数 presentParams.AutoDepthStencilFormat = DepthFormat.D16; device = new Device(0, DeviceType.Hardware, this, //建立设备类对象 CreateFlags.SoftwareVertexProcessing, presentParams); //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice device.DeviceReset += new System.EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null);//自定义方法,初始化Device的工作放到这个方法中 this.OnResetDevice(device, null);//调用设备重置事件(device.DeviceReset)事件函数 } //设备重置事件函数要设置Device参数,初始函数中必须调用该函数 catch (DirectXException) { return false; } return true; } public void OnCreateDevice(object sender, EventArgs e) { ExtendedMaterial[] materials = null; //设定运行程序所在目录的上两级目录为当前默认目录 Directory.SetCurrentDirectory(Application.StartupPath + @"\..\..\..\"); //下句从tiger.x文件中读入3D图形(立体老虎) GraphicsStream adjacency; mesh = Mesh.FromFile("tiger.x", MeshFlags.Managed, device, out adjacency, out materials); if (meshTextures == null) //如果还未设置纹理,为3D图形增加纹理和材质 { meshTextures = new Texture[materials.Length]; //纹理数组 meshMaterials1 = new Material[materials.Length]; //材质数组 for (int i = 0; i < materials.Length; i++) //读入纹理和材质 { meshMaterials1[i] = materials[i].Material3D; meshMaterials1[i].Ambient = meshMaterials1[i].Diffuse; meshTextures[i] = TextureLoader.FromFile(device, materials[i].TextureFilename); } } //下边首先清理Mesh,然后简化Mesh mesh1 = Mesh.Clean(CleanType.Simplification, mesh, adjacency, adjacency); mesh2 = new ProgressiveMesh(mesh1, adjacency, null, 1, MeshFlags.SimplifyVertex); mesh2.NumberVertices = 1000; mesh2.NumberFaces = 1000; } public void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; dev.RenderState.ZBufferEnable = true; //允许深度缓冲 dev.RenderState.Ambient = System.Drawing.Color.White; dev.RenderState.FillMode = FillMode.WireFrame; //只显示3D图形顶点之间的连线 } public void Render() //渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架 { if (device == null) return; device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0); device.BeginScene(); SetupMatrices(); for (int i = 0; i < meshMaterials1.Length; i++) //Mesh中可能有多个3D图形,逐一显示 { device.Material = meshMaterials1[i]; //设定3D图形的材质 device.SetTexture(0, meshTextures[i]); //设定3D图形的纹理 mesh2.DrawSubset(i); //显示该3D图形 } device.EndScene(); device.Present(); } private void Form1_Paint(object sender, PaintEventArgs e) { this.Render(); } private void Form1_Resize(object sender, EventArgs e) { pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible); } void SetupMatrices() { device.Transform.World = Matrix.RotationY(Angle);//世界变换,下条为观察变换矩阵 device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 3.0f, ViewZ), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); device.Transform.Projection = Matrix.PerspectiveFovLH((float)(Math.PI / 4), 1.0f, 1.0f, 100.0f); //设置投影变换矩阵 } private void Form1_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) //e.KeyCode是键盘每个键的编号 { case Keys.Left: //Keys.Left是左箭头键编号,老虎顺时针转动 Angle += 0.1F; break; case Keys.Right: //老虎逆时针转动 Angle -= 0.1F; break; case Keys.Down: //老虎变近 ViewZ += 1; break; case Keys.Up: //老虎变远 ViewZ -= 1; break; case Keys.D0: //使用未优化Mesh mesh2.NumberVertices = 1000; mesh2.NumberFaces = 1000; break; case Keys.D1: //使用优化Mesh mesh2.NumberVertices = 100; mesh2.NumberFaces = 100; break; } } private void Form1_Load(object sender, EventArgs e) { InitializeGraphics(); this.Show(); Render(); } } }
P.S.这里给出光照的另外一个例子,加载DirectX下面的一个.x模型的例子,
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; using System.IO; namespace 光照立方体 { public partial class Form1 : Form { private Device device = null; bool pause = false; VertexBuffer vertexBuffer = null; Material mtrl; Mesh mesh = null; float Angle = 0, ViewZ = -6.0f; //额外对象 private List<Material[]> m_meshMaterials = new List<Material[]>(); //定义网格材质对象 private List<Texture[]> m_meshTextures = new List<Texture[]>(); // 定义网格贴图对象 private List<Mesh> m_meshLst = new List<Mesh>(); public Form1() { InitializeComponent(); } public bool InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; //不是全屏显示,在一个窗口显示 presentParams.SwapEffect = SwapEffect.Discard; //后备缓存交换的方式 presentParams.EnableAutoDepthStencil = true; //允许使用自动深度模板测试 //深度缓冲区单元为16位二进制数 presentParams.AutoDepthStencilFormat = DepthFormat.D16; device = new Device(0, DeviceType.Hardware, this, //建立设备类对象 CreateFlags.SoftwareVertexProcessing, presentParams); //设置设备重置事件(device.DeviceReset)事件函数为this.OnResetDevice device.DeviceReset += new System.EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null);//自定义方法,初始化Device的工作放到这个方法中 this.OnResetDevice(device, null);//调用设备重置事件(device.DeviceReset)事件函数 } //设备重置事件函数要设置Device参数,初始函数中必须调用该函数 catch (DirectXException) { return false; } return true; } //添加网格 public long AddMesh(string filePath) { if (device == null) return 0; if (File.Exists(filePath) == false) return 0; //加载顶点集合 ExtendedMaterial[] materials = null; Mesh meshObj = Mesh.FromFile(filePath, MeshFlags.SystemMemory, device, out materials); if (meshObj == null) return 0; //加载纹理和材质 Texture[] meshTextures = new Texture[materials.Length]; Material[] meshMaterials = new Material[materials.Length]; for (int i = 0; i < materials.Length; i++) { meshMaterials[i] = materials[i].Material3D; meshMaterials[i].Ambient = meshMaterials[i].Diffuse; // 创建贴图 if (materials[i].TextureFilename != null) meshTextures[i] = TextureLoader.FromFile(device, filePath.Substring(0, filePath.LastIndexOf('\\')) + "\\" + materials[i].TextureFilename); else meshTextures[i] = null; } //加入缓冲 m_meshMaterials.Add(meshMaterials); m_meshTextures.Add(meshTextures); m_meshLst.Add(meshObj); return m_meshLst.Count; } public void OnCreateDevice(object sender, EventArgs e) { Device dev = (Device)sender; //注意阴影部分,正方形有6个顶点 vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionNormal), 6, dev, 0, CustomVertex.PositionNormal.Format, Pool.Default); vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer); this.OnCreateVertexBuffer(vertexBuffer, null); mtrl = new Material(); mtrl.Diffuse = System.Drawing.Color.Yellow; //物体的颜色 mtrl.Ambient = System.Drawing.Color.Red; //反射环境光的颜色 //mesh = Mesh.FromFile(@"..\..\..\Dwarf.x", MeshFlags.SystemMemory, device); AddMesh(@"D:\\Microsoft DirectX SDK (June 2010)\\Samples\\Media\\Dwarf\\Dwarf.x"); } public void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; dev.RenderState.CullMode = Cull.CounterClockwise; //背面剔除 device.RenderState.ZBufferEnable = true; //打开Z缓冲 device.RenderState.Lighting = true; //打开灯光 mtrl = new Material(); mtrl.Diffuse = System.Drawing.Color.Yellow; //物体的颜色 mtrl.Ambient = System.Drawing.Color.Red; //反射环境光的颜色 SetupLights(); Render(); } public void Render() //渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架 { if (device == null) //如果未建立设备对象,退出 return; if (pause) return; device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0); device.BeginScene(); //开始渲染 SetupMatrices(); // device.SetStreamSource(0, vertexBuffer, 0); // device.VertexFormat = CustomVertex.PositionNormal.Format; // device.Transform.World = Matrix.Translation(0, 0, -1); // //以下和6.6节例子渲染方法Render中内容相同 // device.Transform.World = Matrix.Translation(0, 0, -1);//沿Z轴向观察者方向移动1个单位 // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制正前面 // //旋转180度是为了从外侧看,按顺时针方向绘制三角形,因背面剔除打开,内侧不被看到 // device.Transform.World = Matrix.RotationY((float)Math.PI) * Matrix.Translation(0, 0, 1); // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制正后面 // device.Transform.World = // Matrix.RotationY(-(float)Math.PI / 2) * Matrix.Translation(1, 0, 0); // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制右侧面 // device.Transform.World = // Matrix.RotationY((float)Math.PI / 2) * Matrix.Translation(-1, 0, 0); // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制左侧面 // device.Transform.World = // Matrix.RotationX((float)Math.PI / 2) * Matrix.Translation(0, 1, 0); // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制下面 // device.Transform.World = // Matrix.RotationX(-(float)Math.PI / 2) * Matrix.Translation(0, -1, 0); // device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); //绘制上面 //渲染Mesh for (int i = 0; i < m_meshLst.Count; i++) { for (int j = 0; j < m_meshMaterials[i].Length; j++) { // m_device.Transform.World = Matrix.Scaling(0.2f, 0.2f, 0.2f) * // Matrix.RotationX((float)Math.PI / 2) * // Matrix.Translation(300, 100, 200); //设置网格子集的材质和贴图 device.Material = m_meshMaterials[i][j]; device.SetTexture(0, m_meshTextures[i][j]); //绘制网格子集 m_meshLst[i].DrawSubset(j); } } device.EndScene(); //渲染结束 device.Present(); //更新显示区域,把后备缓存的D图形送到图形卡的显存中显示 } private void Form1_Paint(object sender, PaintEventArgs e) { this.Render(); } private void Form1_Resize(object sender, EventArgs e) { pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible); } public void OnCreateVertexBuffer(object sender, EventArgs e) { CustomVertex.PositionNormal[] verts = (CustomVertex.PositionNormal[])vertexBuffer.Lock(0, 0); verts[0].Position = new Vector3(-1.0f, -1.0f, 0.0f); //顶点0位置,注意为Vector3 verts[0].Normal = new Vector3(0, 0, -1); //顶点0法线 verts[1].Position = new Vector3(1.0f, 1.0f, 0.0f); //顶点1位置 verts[1].Normal = new Vector3(0, 0, -1); //顶点1法线 verts[2].Position = new Vector3(1.0f, -1.0f, 0.0f); //顶点2位置 verts[2].Normal = new Vector3(0, 0, -1); verts[3].Position = new Vector3(-1.0f, -1.0f, 0.0f); //顶点3位置 verts[3].Normal = new Vector3(0, 0, -1); //顶点3法线 verts[4].Position = new Vector3(-1.0f, 1.0f, 0.0f); //顶点4位置 verts[4].Normal = new Vector3(0, 0, -1); verts[5].Position = new Vector3(1.0f, 1.0f, 0.0f); //顶点5位置 verts[5].Normal = new Vector3(0, 0, -1); vertexBuffer.Unlock(); } private void SetupMatrices() //注意世界变换和观察变换参数可能要改变 { device.Transform.World = Matrix.RotationY(0); //世界变换矩阵 Vector3 v1 = new Vector3(0.0f, 0.0f, -5.0f); //下句使v1点分别沿Y轴和X轴旋转 v1.TransformCoordinate(Matrix.RotationYawPitchRoll(Angle, ViewZ, 0)); // device.Transform.View = Matrix.LookAtLH(v1, new Vector3(0.0f, 0.0f, 0.0f), // new Vector3(0.0f, 1.0f, 0.0f)); //观察变换矩阵 device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 0.0f,-5.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); //观察变换矩阵 device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)this.Width/(float)this.Height, 1.0f, 100.0f); //投影变换矩阵 }//需要实时计算(float)this.Width/(float)this.Height private void SetupLights() { device.Material = mtrl; device.Lights[0].Type = LightType.Directional; device.Lights[0].Diffuse = System.Drawing.Color.White; //光的颜色为白色 device.Lights[0].Direction = new Vector3(0, -2, 4);//灯光方向从观察者上方指向屏幕下方 device.Lights[0].Update(); //更新灯光设置,创建第一盏灯光 device.Lights[0].Enabled = true; //使设置有效,下句设置环境光为白色 device.RenderState.Ambient = System.Drawing.Color.FromArgb(0x808080); } private void Form1_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) //e.KeyCode是键盘每个键的编号 { case Keys.Left: //Keys.Left是左箭头键编号,三角形沿Y轴左转 Angle += 0.1F; break; case Keys.Right: //三角形沿Y轴右转 Angle -= 0.1F; break; case Keys.Down: //三角形离观察者越来越远 ViewZ += 0.1F; break; case Keys.Up: //三角形离观察者越来越近 ViewZ -= 0.1F; break; } } private void Form1_Load(object sender, EventArgs e) { InitializeGraphics(); this.Show(); Render(); } } }