王朝网络
分享
 
 
 

DirectX9 3D 快速上手 2

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

DirectX9 3D 快速上手 2

By sssa2000

4/13/2005

按照通用教程,将完了设备的建立,就该讲到Vertices(顶点),当然这也是很重要的概念,不得不学啊。

看看SDK的Tutorial2,这个例子也很简单在例子1的基础上画了一个三角形,用渐进色填充了一下。如下图:

首先看看Vertices 怎么建立。

CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

CustomVertex.TransformedColored包含了经过变换的顶点和颜色值的数据,为什么要变换?这个和DX使用的坐标系统有关系。要说的话一两句说清楚也困难,这里使用变换过的顶点,指定坐标就是在屏幕的坐标,很直观,再度感受到RAD的好处。当然CustomVertex还包括了很多其他的结构体,适用于其他的需要,有兴趣的可以去看看。

其中Rhw表示齐次w坐标的倒数,仅仅适用于变换过的顶点。

注意,不同版本的DirectX9 ,语法上会有些不一样,注意参考一下文档,我的是DirectX9.0c (October 2004).

事实上,现在已经可以渲染,但是这个时候的效率比较低。每次渲染场景时,都要分配新的顶点列表,并且所有东西存储在系统内存里。现代显卡集成了足够的显存,把顶点数据存放在显存可以获得大幅的新能提升:存放在系统内存里的数据,渲染每一帧时都要拷贝到显卡,这会带来极大的损失。只有移除每帧时的这种分配才能帮助我们提高性能。

所以我们需要缓冲,于是就有了Vertex Buffers。以下是常用的2个构造函数:

public VertexBuffer( Device device, int sizeOfBufferInBytes, Usage usage, VertexFormats vertexFormat, Pool pool)

public VertexBuffer( Type typeVertexType, int numVerts, Device device, Usage usage,VertexFormats vertexFormat, Pool pool);

以下是各参数的意义:

device——用来创建顶点缓冲的device,创建的顶点缓冲只能被这个device使用;

sizeOfBufferInBytes——所创建的顶点缓冲大小,以字节为单位。使用带有这个参数的构造函数创建的顶点缓冲可以存放任何类型的顶点;

typeVertexType——如果去要创建的顶点缓冲只储存一种类型的顶点,则使用这个参数。它的值可以是CustomVertex类中的顶点结构类型,也可以是自定义的顶点类型。且这个值不能为null;

numVert——指定了顶点缓冲的储存类型之后,也必须指定缓冲储存的顶点数量最大值。这个值必须大于0;

usage——定义如何使用顶点缓冲。并不会是所有Usage类型的成员都能使用,只有一下几个是正确的参数:DoNotClip,Dynamic, Npatches, Points, PTPatches, SoftwareProcessing, WriteOnly;

vertexFormat—— 定义储存在顶点缓冲中的顶点格式。,如果创建的为通用缓冲的话,则使用VertexFormat.None;

pool——定位顶点缓冲使用的内存池位置,可以指定一下几个内存池位置:

Default, Managed, SystemMemory, Scratch。

让我们看看在SDK的这个例子里面它是怎么做的:

public void OnCreateDevice(object sender, EventArgs e)

{

Device dev = (Device)sender;

vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);

vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

this.OnCreateVertexBuffer(vertexBuffer, null);

}

和预期的完全一样,并且,还有添加了一个事件:vertexBuffer.Created,在这个事件里面我们就可以把每个顶点的值写入,就像我们前面写的那样。大家不嫌啰嗦的话我们不妨再看看:

public void OnCreateVertexBuffer(object sender, EventArgs e)

{

VertexBuffer vb = (VertexBuffer)sender;

GraphicsStream stm = vb.Lock(0, 0, 0);

CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

stm.Write(verts);

vb.Unlock();

}

为了理解简单,我们可以理解,如果需要使用VertexBuffer就必须使用GraphicsStream 当然,使用IndexBuffer也需要用到它,这个我们后面自然会讲到。

这里为了避免多处同时读写的情况,使用了Lock()这个方法,事实上,在以后很多地方都要接触到这个方法。看看Lock方法的原形:

public GraphicsStream Lock(

int offsetToLock,//偏移量,设为0表示全部的数据

int sizeToLock,//设置为0表示全部数据

LockFlags flags//一般设置为0,当然你也可以由其他的选择,参看SDK文档

);

现在我们已经准备好了一切,现在我们可以来画图了DrawPrimitives将会绘制来自数据流源里的几何体。DrawPrimitives有三个参数

public void DrawPrimitives(

PrimitiveType primitiveType,//几何体的种类

int startVertex,// 表示流里的起始顶点

int primitiveCount//所要绘制的几何体个数

);

下面看看Render()函数

private void Render()

{

if (device == null)

return;

//Clear the backbuffer to a blue color (ARGB = 000000ff)

device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

//Begin the scene

device.BeginScene();

device.SetStreamSource( 0, vertexBuffer, 0);

device.VertexFormat = CustomVertex.TransformedColored.Format;//指定格式

device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);//绘制一个3角形

//End the scene

device.EndScene();

device.Present();

}

SetStreamSource的作用是让Direct3D绘图的时候读取顶点缓冲。使用这个方法当然是为了配合前面说过的DrawPrimitives()。这个方法有以下两种重载:

public void SetStreamSource(int streamNumber, VertexBuffer streamData, int offsetInBytes, int stride);

public void SetStreamSource( int streamNumber, VertexBuffer streamData, int offsetInBytes);

两个函数的不同之处在于其中一个多了表示(数据)流步幅大小(stride size of the stream)的参数。

第一个参数是这段数据所使用流的数量。现在,把它设置为0即可;

第二个参数是作为数据源的顶点缓冲,

第三个则是顶点缓冲里需要DirectX绘制的数据的偏移量(以字节为单位)。stride则是缓冲里每一个顶点的大小。如果是用特定类型创建的顶点缓冲,则不需要这个参数。

好了现在可以编译运行了,效果还不错吧。下次我们就要真正的步入3D的世界了。

OK,为了方便阅读,附上Tutorial2的完整代码:

//-----------------------------------------------------------------------------

// File: Vertices.cs

//

// Desc: In this tutorial, we are rendering some vertices. This introduces the

// concept of the vertex buffer, a Direct3D object used to store

// vertices. Vertices can be defined any way we want by defining a

// custom structure and a custom FVF (flexible vertex format). In this

// tutorial, we are using vertices that are transformed (meaning they

// are already in 2D window coordinates) and lit (meaning we are not

// using Direct3D lighting, but are supplying our own colors).

//

// Copyright (c) Microsoft Corporation. All rights reserved.

//-----------------------------------------------------------------------------

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

namespace VerticesTutorial

{

public class Vertices : Form

{

// Our global variables for this project

Device device = null; // Our rendering device

VertexBuffer vertexBuffer = null;

public Vertices()

{

// Set the initial size of our form

this.ClientSize = new System.Drawing.Size(300,300);

// And its caption

this.Text = "Direct3D Tutorial 2 - Vertices";

}

public bool InitializeGraphics()

{

try

{

// Now let's setup our D3D stuff

PresentParameters presentParams = new PresentParameters();

presentParams.Windowed=true;

presentParams.SwapEffect = SwapEffect.Discard;

device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);

this.OnCreateDevice(device, null);

return true;

}

catch (DirectXException)

{

return false;

}

}

public void OnCreateDevice(object sender, EventArgs e)

{

Device dev = (Device)sender;

// Now Create the VB

vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);

vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

this.OnCreateVertexBuffer(vertexBuffer, null);

}

public void OnCreateVertexBuffer(object sender, EventArgs e)

{

VertexBuffer vb = (VertexBuffer)sender;

GraphicsStream stm = vb.Lock(0, 0, 0);

CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

stm.Write(verts);

vb.Unlock();

}

private void Render()

{

if (device == null)

return;

//Clear the backbuffer to a blue color (ARGB = 000000ff)

device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

//Begin the scene

device.BeginScene();

device.SetStreamSource( 0, vertexBuffer, 0);

device.VertexFormat = CustomVertex.TransformedColored.Format;

device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

//End the scene

device.EndScene();

device.Present();

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

{

this.Render(); // Render on painting

}

protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)

{

if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)

this.Close(); // Esc was pressed

}

/// <summary>

/// The main entry point for the application.

/// </summary>

static void Main

()

{

using (Vertices frm = new Vertices())

{

if (!frm.InitializeGraphics()) // Initialize Direct3D

{

MessageBox.Show("Could not initialize Direct3D. This tutorial will exit.");

return;

}

frm.Show();

// While the form is still valid, render and process messages

while(frm.Created)

{

frm.Render();

Application.DoEvents();

}

}

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝网络 版权所有