所属类别:.NET
文章作者:未知
特别推荐:免费发布信息 承包关键词~~抢爆了!HOT!
DirectX9 3D 快速上手8By sssa20005/4/2005上一次中途结束了本来应该讲到的控制Mesh的细节程度的方法的,这一次补上。我们这里使用的是简单的方法,并没有涉及到场景剔出等等复杂的方法,我这里主要还是用DX9提供给我们的类库,progressive meshe。progressive meshes主要的优点就是允许我们控制顶点和面的数目,这样我们就可以灵活的控制mesh细节的显示程度。和Mesh一样,progressive meshe也都是继承自BaseMesh这个类。比较重要的属性主要有2个NumberFaces和NumberVertices。从字面我们就可以看出两个属性的含义。有了前面的基础在使用progressive mesh上也变得十分的简单,首先我们需要声明一个progressive mesh的变量,然后我们看看progressive mesh的构造函数:public ProgressiveMesh(Mesh mesh,GraphicsStream adjacency,GraphicsStream vertexWeights, //顶点的权值,越高越不容易被剔出,如果设为null就全部被设为1int minValue, //设定被简化的最小值MeshFlags options);以下就是核心的代码:private void LoadMesh(string file){
ExtendedMaterial[] mtrl;
GraphicsStream adj;
// Load our mesh
using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device,
out adj, out mtrl))
{
// If we have any materials, store them
if ((mtrl != null) && (mtrl.Length > 0))
{
meshMaterials = new Material[mtrl.Length];
meshTextures = new Texture[mtrl.Length];
// Store each material and texture
for (int i = 0; i < mtrl.Length; i++)
{
meshMaterials[i] = mtrl[i].Material3D;
if ((mtrl[i].TextureFilename != null) &&
(mtrl[i].TextureFilename != string.Empty))
{
// We have a texture, try to load it
meshTextures[i] = TextureLoader.FromFile(device,
@"..\..\" + mtrl[i].TextureFilename);
}
}
}
// Clean our main mesh
using(Mesh tempMesh = Mesh.Clean(mesh, adj, adj))
{
// Create our progressive mesh
progressiveMesh = new ProgressiveMesh(tempMesh, adj,
null, 1, MeshFlags.SimplifyVertex);
// Set the initial mesh to the max
progressiveMesh.NumberFaces = progressiveMesh.MaxFaces;
progressiveMesh.NumberVertices = progressiveMesh.MaxVertices;
}
}}其实这里大部分代码和前面的关于Mesh那一节的代码差不多,关于progressiveMesh,微软的SDK也有一个例子,不过那个例子太过于庞大,大部分都是在处理UI方面,真正涉及到progressiveMesh的部分还是很少的。以下是代码的事例图和完整代码:这个例子里可以切换线框渲染模式和实体作色模式。using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;namespace progressiveMesh{ /// /// Summary description for Form1. /// public class Form1 : System.Windows.Forms.Form { private Device device = null; private ProgressiveMesh progressiveMesh = null; private Material[] meshMaterials; private Texture[] meshTextures; private Microsoft.DirectX.Direct3D.Font font = null; private float cameraPos = 8.0f; private const int MoveAmount = 2; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private float angle = 0.0f; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); this.SetStyle(ControlStyles.AllPaintingInWmPaint ControlStyles.Opaque, true); } /// /// We will initialize our graphics device here /// public void InitializeGraphics() { // Set our presentation parameters PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; presentParams.AutoDepthStencilFormat = DepthFormat.D16; presentParams.EnableAutoDepthStencil = true; // Create our device device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams); // Load our mesh LoadMesh(@"..\..\SprintRacer.x"); // Create our font font = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font ("Arial", 14.0f, FontStyle.Bold FontStyle.Italic)); } private void LoadMesh(string file) { ExtendedMaterial[] mtrl; GraphicsStream adj; // Load our mesh using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out adj, out mtrl)) { // If we have any materials, store them if ((mtrl != null) && (mtrl.Length > 0)) { meshMaterials = new Material[mtrl.Length]; meshTextures = new Texture[mtrl.Length]; // Store each material and texture for (int i = 0; i < mtrl.Length; i++) { meshMaterials[i] = mtrl[i].Material3D; if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty)) { // We have a texture, try to load it meshTextures[i] = TextureLoader.FromFile(device, @"..\..\" + mtrl[i].TextureFilename); } } } // Clean our main mesh using(Mesh tempMesh = Mesh.Clean(CleanType.Simplification ,mesh, adj, adj)) { // Create our progressive mesh progressiveMesh = new ProgressiveMesh(tempMesh, adj, null, 1, MeshFlags.SimplifyVertex); // Set the initial mesh to the max progressiveMesh.NumberFaces = progressiveMesh.MaxFaces; progressiveMesh.NumberVertices = progressiveMesh.MaxVertices; } } } private void SetupCamera() { device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 10000.0f); device.Transform.View = Matrix.LookAtLH(new Vector3(0,0, cameraPos), new Vector3(), new Vector3(0,1,0)); device.RenderState.Ambient = Color.Blue; device.Lights[0].Type = LightType.Directional; device.Lights[0].Diffuse = Color.White; device.Lights[0].Direction = new Vector3(0, -1, -1); device.Lights[0].Update(); device.Lights[0].Enabled = true; } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { device.Clear(ClearFlags.Target ClearFlags.ZBuffer, Color.Blue , 1.0f, 0); SetupCamera(); device.BeginScene(); // Draw our Mesh DrawMesh(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI / 4.0f, 0.0f, 0.0f, 0.0f); font.DrawText(null, string.Format("Number vertices in mesh: {0}", ((BaseMesh)progressiveMesh).NumberVertices), new Rectangle(10, 10, 0, 0), DrawTextFormat.NoClip, Color.BlanchedAlmond); font.DrawText(null, string.Format("Number faces in mesh: {0}", ((BaseMesh)progressiveMesh).NumberFaces), new Rectangle(10, 30, 0, 0), DrawTextFormat.NoClip, Color.BlanchedAlmond); device.EndScene(); device.Present(); this.Invalidate(); } private void DrawMesh(float yaw, float pitch, float roll, float x, float y, float z) { angle += 0.11f; device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z); for (int i = 0; i < meshMaterials.Length; i++) { device.Material = meshMaterials[i]; device.SetTexture(0, meshTextures[i]); progressiveMesh.DrawSubset(i); } } protected override void OnKeyPress(KeyPressEventArgs e) { if (e.KeyChar == '+') { cameraPos += (MoveAmount * 2); progressiveMesh.NumberVertices = ((BaseMesh)progressiveMesh).NumberVertices - MoveAmount; progressiveMesh.NumberFaces = ((BaseMesh)progressiveMesh).NumberFaces - MoveAmount; } if (e.KeyChar == '-') { cameraPos -= (MoveAmount * 2); progressiveMesh.NumberVertices = ((BaseMesh)progressiveMesh).NumberVertices + MoveAmount; progressiveMesh.NumberFaces = ((BaseMesh)progressiveMesh).NumberFaces + MoveAmount; } if (e.KeyChar == 'w') device.RenderState.FillMode = FillMode.WireFrame; if (e.KeyChar == 's') device.RenderState.FillMode = FillMode.Solid; } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.Size = new Size(800,600); this.Text = "Form1"; } #endregion /// /// The main entry point for the application. /// static void Main() { using (Form1 frm = new Form1()) { // Show our form and initialize our graphics engine frm.Show(); frm.InitializeGraphics(); Application.Run(frm); } } }}这里我们已经实现了能自由控制显示的细节问题,通过progressiveMesh 我们可以很方便的完成这一点,接下来,顺着这个话题我们来讨论一下如何增加细节的显示程度,也就是说我们将要把读入的Mesh的细节程度增多。这里我们部探讨原理,因为我数学也是很差,我们可以借助Patch Meshes 来实现。Patch Meshes通过增加读入的Mesh的顶点来对细节程度进行增加。public PatchMesh(ID3DXPatchMesh); 这就是PathMesh的构造函数,只要传入一个读入的Mesh就可以了。接下来我们将用一个例子展示怎么增加显示的细节程度private void CreatePatchMesh(string file, float tessLevel){
if (tessLevel < 1.0f) //如果小于默认的值,不再增加,直接返回
return;
if (mesh != null)
mesh.Dispose();
using (Mesh tempmesh = LoadMesh(file))
{
using (PatchMesh patch = PatchMesh.CreateNPatchMesh(tempmesh))
{
// Calculate the new number of faces/vertices
int numberFaces = (int)(tempmesh.NumberFaces
* Math.Pow(tessLevel, 3));
int numberVerts = (int)(tempmesh.NumberVertices
* Math.Pow(tessLevel, 3));
mesh = new Mesh(numberFaces, numberVerts, MeshFlags.Managed
MeshFlags.Use32Bit, tempmesh.VertexFormat, device);
// Tessellate the patched mesh
patch.Tessellate(tessLevel, mesh); //在tessLevel的基础上把mesh分成小方格
}
}} private Mesh LoadMesh(string file){……………………….略if ((mesh.VertexFormat & VertexFormats.Normal) != VertexFormats.Normal)//如果没有法线信息,就要计算法线,发现信息会在上面的Tessellate方法中被用到。
{
// We must have normals for our patch meshes
Mesh tempMesh = mesh.Clone(mesh.Options.Value,
mesh.VertexFormat VertexFormats.Normal, device);
tempMesh.ComputeNormals();
mesh.Dispose();
mesh = tempMesh;
}
return mesh;} 以下就是运行的图例可以明显地看出,我们的程序还是有明显的效果的,不过对于增加的细节,程序将变得十分的缓慢。以下是全部的代码:using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;namespace PathMesh{ /// /// Summary description for Form1. /// public class Form1 : System.Windows.Forms.Form { private Device device = null; private Mesh mesh = null; private Material[] meshMaterials; private Texture[] meshTextures; private float tessLevel = 1.0f; private const float tessIncrement = 1.0f; private string filename = @"..\..\sphere.x"; private Microsoft.DirectX.Direct3D.Font font = null; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private float angle = 0.0f; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); this.SetStyle(ControlStyles.AllPaintingInWmPaint ControlStyles.Opaque, true); } /// /// We will initialize our graphics device here /// public void InitializeGraphics() { // Set our presentation parameters PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; presentParams.AutoDepthStencilFormat = DepthFormat.D16; presentParams.EnableAutoDepthStencil = true; // Create our device device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams); // Create our patch mesh CreatePatchMesh(filename, tessLevel); // Create our font font = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font ("Arial", 14.0f, FontStyle.Bold FontStyle.Italic)); // Default to wireframe mode first device.RenderState.FillMode = FillMode.WireFrame; } /// /// Creates a temporary mesh object, and a patch mesh from it /// /// The original mesh to use /// The tesselation level private void CreatePatchMesh(string file, float tessLevel) { if (tessLevel < 1.0f) // Nothing to do return; if (mesh != null) mesh.Dispose(); using (Mesh tempmesh = LoadMesh(file)) { using (PatchMesh patch = PatchMesh.CreateNPatchMesh(tempmesh)) { // Calculate the new number of faces/vertices int numberFaces = (int)(tempmesh.NumberFaces * Math.Pow(tessLevel, 3)); int numberVerts = (int)(tempmesh.NumberVertices * Math.Pow(tessLevel, 3)); mesh = new Mesh(numberFaces, numberVerts, MeshFlags.Managed MeshFlags.Use32Bit, tempmesh.VertexFormat, device); // Tessellate the patched mesh patch.Tessellate(tessLevel, mesh); } } } /// /// Load a mesh from a file and return it /// /// The file to load /// The created mesh private Mesh LoadMesh(string file) { ExtendedMaterial[] mtrl; // Load our mesh Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl); // If we have any materials, store them if ((mtrl != null) && (mtrl.Length > 0)) { meshMaterials = new Material[mtrl.Length]; meshTextures = new Texture[mtrl.Length]; // Store each material and texture for (int i = 0; i < mtrl.Length; i++) { meshMaterials[i] = mtrl[i].Material3D; if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty)) { // We have a texture, try to load it meshTextures[i] = TextureLoader.FromFile(device, @"..\..\" + mtrl[i].TextureFilename); } } } if ((mesh.VertexFormat & VertexFormats.Normal) != VertexFormats.Normal) { // We must have normals for our patch meshes Mesh tempMesh = mesh.Clone(mesh.Options.Value, mesh.VertexFormat VertexFormats.Normal, device); tempMesh.ComputeNormals(); mesh.Dispose(); mesh = tempMesh; } return mesh; } private void SetupCamera() { device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, this.Width / this.Height, 1.0f, 100.0f); device.Transform.View = Matrix.LookAtLH(new Vector3(0,0, 5.0f), new Vector3(), new Vector3(0,1,0)); device.Lights[0].Type = LightType.Directional; device.Lights[0].Diffuse = Color.DarkKhaki; device.Lights[0].Direction = new Vector3(0, 0, -1); device.Lights[0].Update(); device.Lights[0].Enabled = true; } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { device.Clear(ClearFlags.Target ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0); SetupCamera(); device.BeginScene(); // Draw our Mesh DrawMesh(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI / 4.0f, 0.0f, 0.0f, 0.0f); font.DrawText(null, string.Format ("Number Vertices: {0}\r\nNumber Faces: {1}", mesh.NumberVertices, mesh.NumberFaces), new Rectangle(10,10,0,0), DrawTextFormat.NoClip, Color.Black); device.EndScene(); device.Present(); this.Invalidate(); } private void DrawMesh(float yaw, float pitch, float roll, float x, float y, float z) { angle += 0.01f; device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z); for (int i = 0; i < meshMaterials.Length; i++) { device.Material = meshMaterials[i]; device.SetTexture(0, meshTextures[i]); mesh.DrawSubset(i); } } protected override void OnKeyPress(KeyPressEventArgs e) { if (e.KeyChar == '+') { tessLevel += tessIncrement; CreatePatchMesh(filename, tessLevel); } if (e.KeyChar == '-') { tessLevel -= tessIncrement; CreatePatchMesh(filename, tessLevel); } if (e.KeyChar == 'c') { filename = @"..\..\cube.x"; tessLevel = 1.0f; CreatePatchMesh(filename, tessLevel); } if (e.KeyChar == 'o') { filename = @"..\..\sphere.x"; tessLevel = 1.0f; CreatePatchMesh(filename, tessLevel); } if (e.KeyChar == 't') { filename = @"..\..\tiger.x"; tessLevel = 1.0f; CreatePatchMesh(filename, tessLevel); } if (e.KeyChar == 'w') device.RenderState.FillMode = FillMode.WireFrame; if (e.KeyChar == 's') device.RenderState.FillMode = FillMode.Solid; } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.Size = new Size(800,600); this.Text = "Form1"; } #endregion /// /// The main entry point for the application. /// static void Main() { using (Form1 frm = new Form1()) { // Show our form and initialize our graphics engine frm.Show(); frm.InitializeGraphics(); Application.Run(frm); } } }}By sssa20005/4/2005关闭本页
相关信息· asp:如何在Form域中Post大于100K字节的数据?我的方法如下:
· Songbird 1.0 发布
· 让Win2K系统达到最佳性能
· 轻松使用IP过滤进行网络管理
14151
82006
