分享
 
 
 

DirectX9 3D 快速上手 8

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

DirectX9 3D 快速上手 8

By sssa2000

5/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就全部被设为1

int 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>

/// Summary description for Form1.

/// </summary>

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;

/// <summary>

/// Required designer variable.

/// </summary>

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

}

/// <summary>

/// We will initialize our graphics device here

/// </summary>

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;

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container();

this.Size = new Size(800,600);

this.Text = "Form1";

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

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>

/// Summary description for Form1.

/// </summary>

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;

/// <summary>

/// Required designer variable.

/// </summary>

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

}

/// <summary>

/// We will initialize our graphics device here

/// </summary>

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;

}

/// <summary>

/// Creates a temporary mesh object, and a patch mesh from it

/// </summary>

/// <param name="file">The original mesh to use</param>

/// <param name="tessLevel">The tesselation level</param>

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

}

}

}

/// <summary>

/// Load a mesh from a file and return it

/// </summary>

/// <param name="file">The file to load</param>

/// <returns>The created mesh</returns>

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;

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container();

this.Size = new Size(800,600);

this.Text = "Form1";

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

static void

Main()

{

using (Form1 frm = new Form1())

{

// Show our form and initialize our graphics engine

frm.Show();

frm.InitializeGraphics();

Application.Run(frm);

}

}

}

}

By sssa2000

5/4/2005

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有