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();
}
}
}