首先向大家道歉自3出了以后隔这么久才出4,一方面过年期间我天天在外面走亲戚,另一方面我最近确实有些消沉,我不是个会太监的人,却总是有时会陷入一种消沉的状态,因为想从软件行业转型,碰了许多壁,关起门来看龙书和算法导论,基本保持不上网状态,偶尔手机上上人人网分享点日志。
我也知道我的文章并不是多么的不可或缺,没了这个翻译大家照样过,目前为止基本都是些入门类的东西,有时候我会想到曾小贤的午夜节目,那个夜晚被胡一非痛骂才明白原来自己做的并不是没有意义,消沉的这段时间,看到陆续还有几个网友留言鼓励我,我真的非常感谢你们,我不是什么大神,也不是什么天才,我高数重修了两遍才过,非是不努力而是真的智力不足学起来比别人要多花几倍的时间,但我只是一直努力着,欠了38个学分的时候我没有选择提前留级(如果学年结束时欠了36分以上会退学),我苦行僧般地过了下半学年勉强保住不留级(24学分),刚来上海的时候我是C盲(之前一直搞WEB),没有数据结构的基础不懂STL但我还是撑过来了,四个月以后轻松地完成工作,八个月以后我觉得我们的代码到处是问题,不管遇到怎样的困境,我从来没有放弃过,就像我经常消沉但我总会走出来结束太监状态,希望在看这篇翻译的你,无论在技术还是生活上,永远不要轻言放弃,不管在怎样的困境,只要有1%的希望,就值得我们拼尽全力去争取,人之所以能战胜神,是因为我们相信着的奇迹。
课程概述
有一个简单的方式来学习的DirectX。杯具的是,简单的方法往往有很多功能上的限制,即使没有,在一个比较大型的游戏使用它仍然会很麻烦。当然,更简单的 方法是,努力地学习,本教程会尽量写得更易于编程,以便不使理论的部分太艰深晦涩。
在本节中,您将学习如何在屏幕上画一个三角形。我们将通过创造一系列顶点来构建三角并通过Direct3D设备在屏幕上绘制之。
首先,我们将涵盖如何工作的,那么我们将在代码本身和生成程序的理论。
灵活顶点格式(Flexible Vertex Formats)
如果您完成了第3课中的学习,你会记得顶点的定义:一个确定在在三维空间中的点的精确位置和属性。位置只包含三个坐标数值以描述顶点在空间中的位置。顶点的属性也用数值定义。
Direct3D使用一种称为灵活顶点格式(Flexible Vertex Format简称FVF)的技术。该技术中一个顶点格式包含一个顶点的位置和多个属性数据。一个FVF顶点会是一个格式化的数据,您可以根据您的需要修改和设置。让我们来看看究竟丫是如何工作的。
顶点可以用一个结构体来描述,它包含所有与创建该3D图像有关的数据。为了展示这个图像,我们要把所有的信息复制到视频RAM,然后让Direct3D来复制数据到后台缓冲区。然而,如果我们不得不把一个顶点所有可能需要的数据发送过去会怎样呢?如下图所示。
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/dx9B4-1.PNG)
Image 4.1 - 一个顶点格式包含了所有的信息
当然,你可能不会马上看到这儿有什么问题,但让我们不得不说我们只需要这些信息中的两块。我们可以看到将其发送到视频RAM会快得多,就像这样:
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/dx9B4-2.PNG)
Image 4.2 – FVF格式会快得多
这就是在我们使用FVF时发生的。我们选择我们要使用的信息,并发送之,这样就可以使我们在每帧之间发送更多的顶点。
FVF 代码
在Direct3D中,每个顶点都是预先设定好的顶点格式。正如标题声称,这种格式是灵活的,是使用的Direct3D提供的某些元素。这些元素通过使用特殊标识来设置,比如何时逻辑或在一起,创建一个顶点的定义,或一个告诉Direct3D顶点格式代码的。
让我们来看看它如何做到这一点。比方说,我们希望包括位置和我们的顶点漫反射颜色。我们将建立一个代码:
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
稍后,我们将简单地使用CUSTOMFVF,而不是每次都输出整个FVF代码。我们将在一分钟后来看这样的一个例子。
我们可以在这个表达式里添加各种标识。以下是一组贯穿本套教程始终的标识表,以及他们做什么的说明。
[Table 4.1 - FVF Code Flags]
标识
|
描述
|
参数类型
|
D3DFVF_XYZ
|
表示该顶点格式包括X,Y和Z的一个未转换的顶点坐标。未转化意味着顶点尚未转化为屏幕坐标。
|
float, float, float
|
D3DFVF_XYZRHW
|
表示该顶点格式包括X,Y和Z坐标以及一个转换过的额外的RHW值。这意味着顶点已经在屏幕坐标系。Z和RHW会在构建软件引擎时使用,我们不会进入。
|
float, float, float, float
|
D3DFVF_DIFFUSE
|
表示顶点格式包含一个32位颜色代码,用于表示漫射光颜色。
|
DWORD
|
D3DFVF_SPECULAR
|
表示顶点格式包含一个32位颜色代码,用于镜面高亮使用的颜色。
|
DWORD
|
D3DFVF_TEX0 through D3DFVF_TEX8
|
表示顶点格式包含任何将被应用到模型纹理坐标。
|
float, float
|
[Close Table]
|
|
|
当然了,还有更多的标识没有被提及,它们已经是包含在DirectX文档中了。而我们只需要本教程中使用到的这些标识。
创建顶点
现在我们需要使用我们的新格式创建顶点。我们不使用任何新函数或诸如此类的东西,我们通过建立一个简单的结构体装入FVF代码中包含的变量。
例如,我们用在上面的例子用D3DFVF_XYZRHW和D3DFVF_DIFFUSE两个标识一起的话,我们应该建立如下结构:
struct CUSTOMVERTEX
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag
DWORD color; // from the D3DFVF_DIFFUSE flag
}
如你所见,前四个浮点数是D3DFVF_XYZRHW标识的值,而DWORD是D3DFVF_DIFFUSE标识的值。如果您看看上表,你会发现这其中的变量类型与FVF标识。
现在,让我们使用我们的新CUSTOMVERTEX结构来构建一个实际的顶点。我们可以像下面这样做:
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
CUSTOMVERTEX OurVertex =
{320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255)};
当然了,你也可以弄个顶点数组,就像这样:
CUSTOMVERTEX OurVertices[] =
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255),},
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{520.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),},
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{120.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0),},
};
结果会是一个三角形,我们很快会在屏幕上看到。
这仅仅是一个灵活顶点格式的示例。我们稍后会继续就如何建立更复杂的顶点格式,恩,就从现在开始吧。
顶点缓存
现在,我们已经完成了两件事情。首先,我们建立了FVF代码。第二,我们已经创建了一个三角形。现在我们需要得到那个三角形以准备给Direct3D使用。要做到这一点,我们创建了所谓的顶点缓冲区。
一个顶点缓冲区是一个简单的接口,它存储在一段内存中(显存或内存),以持有你的游戏中顶点或模型的信息。我们通过函数CreateVertexBuffer()来创建这个接口。不过它的参数有点复杂。下面是函数原型:
HRESULT CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool,
LPDIRECT3DVERTEXBUFFER9 ppVertexBuffer,
HANDLE* pSharedHandle);
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
我们来逐个分析一下这些个参数
UINT Length,
这个参数包含将要创建的顶点缓存的大小。我们得到将存储在缓冲区中的顶点数目乘以一个顶点大小的结果。例如,一个三角形包含三个顶点,因此该三角形的缓冲区大小是:3* sizeof(CUSTOMVERTEX)。
DWORD Usage,
有时候,有些特殊的方法能改变DirectX处理的顶点集。在本教程我们不会深入讨论这些。这个参数可以包含标志表明这些特殊的方式。因为我们不会使用任何所以我们只要把它设置为0。
DWORD FVF,
这是FVF代码中我们接触得比较早的。我们只需填写CUSTOMFVF。如果我们要改变FVF代码,这部分也将改变(改变那个#define)。这是告诉DirectX顶点是什么格式了,这个参数很重要。
D3DPOOL Pool,
这个参数告诉Direct3D在哪创建顶点缓存以及如何创建之。以下是一个表,说明该参数的可能的条目。在本教程中,我们将使用标志D3DPOOL_MANAGED。
[Table 4.2 - D3DPOOL Values]
值
|
描述
|
D3DPOOL_DEFAULT
|
此标志表示该缓存应该创建在最适当的内存以便设置和资源可用。然而,强加一些限制并不总是对游戏有好处。
|
D3DPOOL_MANAGED
|
这表明,缓冲将在位于显存
|
D3DPOOL_SYSTEMMEM
|
这表明,缓存将在系统内存中。顶点缓存设在这里通常不能由Direct3D设备访问,但可以通过其他更高级的手段访问。
|
D3DPOOL_SCRATCH
|
这也表明了缓存将坐落在系统内存中,但是,又没有办法让显存访问它。这种类型一般用于存储图像信息,现在我们用不到(但稍后将使用),比如屏幕已经转到另一个地图但角色暂时还没有到达(不久后就到)。
|
[Close Table]
|
|
LPDIRECT3DVERTEXBUFFER9 ppVertexBuffer,
如果你理解它,那我告诉你它是我们正在创建的顶点缓存的接口。我们给这个参数一个空指针,函数会给他赋值。
HANDLE* pSharedHandle
文档里说过这个参数,我引述一下:“保留。设置这个参数为NULL。“我不能说肯定,但显然微软希望我们将其设置为NULL。就这样吧。我们将它设置为NULL。
看完这些参数,让我们来看看这个功能在我们的程序中如何写:
LPDIRECT3DVERTEXBUFFER9 v_buffer;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&v_buffer,
NULL);
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
现在您已经创建了顶点缓存,下面你需要把顶点加载进去。你用一个简单的函数memcpy()就可以完成。但是,在您访问到顶点缓存之前,你需要将其锁定。
基于两个原因,你需要锁定这个缓存。首先,你需要告诉Direct3D你需要内存的完全控制权。换句话说,它不应该由任何可能的其他进程使用。第二,你需要告诉视频硬件别动它。否则可没法保证显存保持不动。锁定告诉显存与内存当你正在使用它时别干蠢事儿。
要锁定一个缓冲区,可以使用函数Lock(),它有四个参数,但都相当简单:
HRESULT Lock(UINT OffsetToLock,
UINT SizeToLock,
VOID** ppbData,
DWORD Flags);
让我们来看看这些参数:
UINT OffsetToLock, UINT SizeToLock,
如果我们只是想锁定我们的顶点缓冲的一部分,我们将表明在这两个参数。第一个指示自缓存的起始点到开始锁定位置的偏移量,以字节为单位。第二个表示多少字节被锁定。因为我们现在要锁定整个缓冲区,所以我们将设置这些都为0。
VOID** ppbData,
除非你是至少中等水平以上的C+ +,否则这个参数您老还是别动了。基本上这是一个void*指针并且没有指向特定类型的变量。例如,一个**double,而一个int*指向一个int。每个指针类型都有它自己的格式,因此它不能转换不会丢失数据为另一种类型。但是一个void *指针,却可以转换为任何类型。
在这里,我们有一个空指针*.这个指针被锁定的存数去起始位置的指针。顶点缓冲区接口会处理其细节,但我们在下一步会需要这个指针。所以函数lock()函数将填充恰当的地址给这个指针。有一个在下面的例子,看看我们如何填补这个参数。
DWORD Flags
这是一个很高级的参数,我们不会在本教程中深入。本上它提供特殊的方式来处锁定内存。如果你是真正感兴趣的,它们可以研究在DirectX文档。现在,我们只是将它设置为0。
让我们来补完这个函数,看看它的样子:
VOID* pVoid; // the void* we were talking about
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
v_buffer->Lock(0, 0, (void**)&pVoid, 0); // locks v_buffer, the buffer we made earlier
接下来,我们调用memcpy()复制顶点到顶点缓存。
memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy vertices to the vertex buffer
最后,我们还有一个非常复杂的函数:Unlock()。这个函数没有参数。它所做的是告诉Direct3D,跟内存搞完了,解开束缚吧。写起来像这样:
v_buffer->Unlock(); // unlock v_buffer
由于我们刚刚得知命令的数量,我们要把我们自己创建的功能放进一个单独的函数里init_graphics()。
void init_graphics(void)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
// create three vertices using the CUSTOMVERTEX struct built earlier
CUSTOMVERTEX vertices[] =
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 520.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 120.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
// create the vertex and store the pointer into v_buffer, which is created globally
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&v_buffer,
NULL);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
VOID* pVoid; // the void pointer
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer
memcpy(pVoid, vertices, sizeof(vertices)); // copy the vertices to the locked buffer
v_buffer->Unlock(); // unlock the vertex buffer
}
在这里,我建议您多读几次以确保你彻底明白了这一切。这是3D编程中一个相当关键的的部分,我们将在教程的休息时间使用和修改它。
绘制图元
现在,我们实际上已经获得屏幕上的内容!但在此发生之前我们有三个非常简单的函数要认识一下。每一个被从Direct3D设备接口调用。让我们来看看。
SetFVF()
这些函数的第一个是SetFVF()。 SetFVF()是一种告诉Direct3D使用当前使用什么样的FVF代码的函数。我们当然可以有多个FVF代码并使用在两个不同的三维场景。在我们开始画之前,我们只需要告诉我们的Direct3D使用的是哪一个。这个函数写出来是这样的:
d3ddev->SetFVF(CUSTOMFVF);
SetStreamSource()
下一步,我们的函数SetStreamSource(),它告诉Direct3D我们从哪个顶点缓冲取顶点。这其中有一对参数,让我们来看看函数原型:
HRESULT SetStreamSource(UINT StreamNumber,
LPDIRECT3DVERTEXBUFFER9 pStreamData,
UINT OffsetInBytes,
UINT Stride);
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
第一个参数是要用的顶点缓存的序号。我们稍后深入它的工作原理,但现在将它设置为0,因为我们只有一个顶点缓冲区。
第二个参数是指向我们先前创建的顶点缓存的指针。
第三个参数指应该从顶点缓冲的第几个字节开始。这通常是0。
最后一个参数是每个顶点的大小。我们填写如下: SizeOf(CUSTOMVERTEX)。
让我们来看看在函数怎样被调用:
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
DrawPrimitive()
现在我们已经告诉Direct3D我们正在使用哪种格式的顶点以及哪里得到它们,我们告诉它请绘制我们已经建立的顶点。这个函数绘制在选定的顶点缓存的图元到屏幕上。这里是函数原型:
HRESULT DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount);
第一个参数是使用的图元类型。这些在第3课已经讲过了,但所用的代码在这里:
[Table 4.3 - D3DPRIMITIVETYPE Values]
Value
|
Description
|
D3DPT_POINTLIST
|
点阵
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/r_pointlst.gif)
|
D3DPT_LINELIST
|
线列表
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/r_linelst.gif)
|
D3DPT_LINESTRIP
|
线带
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/r_linstrip.gif)
|
D3DPT_TRIANGLELIST
|
三角形列表
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/o_trilist.gif)
|
D3DPT_TRIANGLESTRIP
|
三角形带
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/r_strstrip.gif)
|
D3DPT_TRIANGLEFAN
|
三角扇形
![](http://www.cppblog.com/images/cppblog_com/dfghj44444/r_trifan.gif)
|
[Close Table]
|
|
第二个参数是我们要绘制在屏幕上的第一个顶点的序号。如果我们愿意,我们可以在顶点缓冲区的中间开始。但是,现在我们希望绘制整个缓冲区,因此我们将在这里把0。
第三个也是最后一个参数是我们要绘制图元的数量。如果我们要画一个三角形,我们设1(只有一个三角形)。如果我们画点,我们会设为3,有三点。画线条也是设为3。
现在让我们来看看整个render_frame()函数,现在我们已经修改了它。
// this is the function used to render a single frame
void render_frame(void)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
d3ddev->BeginScene();
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
// select which vertex format we are using
d3ddev->SetFVF(CUSTOMFVF);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
// select the vertex buffer to display
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
// copy the vertex buffer to the back buffer
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
d3ddev->EndScene();
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
d3ddev->Present(NULL, NULL, NULL, NULL);
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
在看整个程序之前,先来看看最后一个步骤是很有必要的。
释放顶点缓存
就像Direct3D设备和Direct3D一样,顶点缓冲区也必须在程序关闭之前被释放。
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
v_buffer->Release(); // close and release the vertex buffer
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
现在让我们来看看整个程序,看看我们都干了什么。
最终代码
好吧,让我们来看看这个三角长啥样。如果你从来没有见过三角形,这将是一个教育的经验。否则你可以看到一个三角形是made in Direct3D。
无论如何,让我们来看看最后的DirectX代码。在本课程中所涵盖的新的部分像往常是加粗的。
1
// include the basic windows header files and the Direct3D header file
2
#include <windows.h>
3
#include <windowsx.h>
4
#include <d3d9.h>
5![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
6
// define the screen resolution
7
#define SCREEN_WIDTH 800
8
#define SCREEN_HEIGHT 600
9![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
10
// include the Direct3D Library file
11
#pragma comment (lib, "d3d9.lib")
12![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
13
// global declarations
14
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
15
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
16
LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; // the pointer to the vertex buffer
17![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
18
// function prototypes
19
void initD3D(HWND hWnd); // sets up and initializes Direct3D
20
void render_frame(void); // renders a single frame
21
void cleanD3D(void); // closes Direct3D and releases memory
22
void init_graphics(void); // 3D declarations
23![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
24![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
struct CUSTOMVERTEX
{FLOAT X, Y, Z, RHW; DWORD COLOR;};
25
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
26![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
27
// the WindowProc function prototype
28
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
29![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
30![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
31
// the entry point for any Windows program
32
int WINAPI WinMain(HINSTANCE hInstance,
33
HINSTANCE hPrevInstance,
34
LPSTR lpCmdLine,
35
int nCmdShow)
36![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
37
HWND hWnd;
38
WNDCLASSEX wc;
39![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
40
ZeroMemory(&wc, sizeof(WNDCLASSEX));
41![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
42
wc.cbSize = sizeof(WNDCLASSEX);
43
wc.style = CS_HREDRAW | CS_VREDRAW;
44
wc.lpfnWndProc = WindowProc;
45
wc.hInstance = hInstance;
46
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
47
wc.lpszClassName = L"WindowClass";
48![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
49
RegisterClassEx(&wc);
50![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
51
hWnd = CreateWindowEx(NULL,
52
L"WindowClass",
53
L"Our Direct3D Program",
54
WS_OVERLAPPEDWINDOW,
55
0, 0,
56
SCREEN_WIDTH, SCREEN_HEIGHT,
57
NULL,
58
NULL,
59
hInstance,
60
NULL);
61![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
62
ShowWindow(hWnd, nCmdShow);
63![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
64
// set up and initialize Direct3D
65
initD3D(hWnd);
66![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
67
// enter the main loop:
68![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
69
MSG msg;
70![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
71
while(TRUE)
72![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
73
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
74![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
75
TranslateMessage(&msg);
76
DispatchMessage(&msg);
77
}
78![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
79
if(msg.message == WM_QUIT)
80
break;
81![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
82
render_frame();
83
}
84![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
85
// clean up DirectX and COM
86
cleanD3D();
87![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
88
return msg.wParam;
89
}
90![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
91![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
92
// this is the main message handler for the program
93
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
94![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
95
switch(message)
96![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
97
case WM_DESTROY:
98![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
99
PostQuitMessage(0);
100
return 0;
101
} break;
102
}
103![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
104
return DefWindowProc (hWnd, message, wParam, lParam);
105
}
106![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
107![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
108
// this function initializes and prepares Direct3D for use
109
void initD3D(HWND hWnd)
110![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
111
d3d = Direct3DCreate9(D3D_SDK_VERSION);
112![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
113
D3DPRESENT_PARAMETERS d3dpp;
114![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
115
ZeroMemory(&d3dpp, sizeof(d3dpp));
116
d3dpp.Windowed = TRUE;
117
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
118
d3dpp.hDeviceWindow = hWnd;
119
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
120
d3dpp.BackBufferWidth = SCREEN_WIDTH;
121
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
122![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
123
// create a device class using this information and the info from the d3dpp stuct
124
d3d->CreateDevice(D3DADAPTER_DEFAULT,
125
D3DDEVTYPE_HAL,
126
hWnd,
127
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
128
&d3dpp,
129
&d3ddev);
130![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
131
init_graphics(); // call the function to initialize the triangle
132
}
133![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
134![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
135
// this is the function used to render a single frame
136
void render_frame(void)
137![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
138
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
139![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
140
d3ddev->BeginScene();
141![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
142
// select which vertex format we are using
143
d3ddev->SetFVF(CUSTOMFVF);
144![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
145
// select the vertex buffer to display
146
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
147![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
148
// copy the vertex buffer to the back buffer
149
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
150![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
151
d3ddev->EndScene();
152![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
153
d3ddev->Present(NULL, NULL, NULL, NULL);
154
}
155![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
156![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
157
// this is the function that cleans up Direct3D and COM
158
void cleanD3D(void)
159![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
160
v_buffer->Release(); // close and release the vertex buffer
161
d3ddev->Release(); // close and release the 3D device
162
d3d->Release(); // close and release Direct3D
163
}
164![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
165![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
166
// this is the function that puts the 3D models into video RAM
167
void init_graphics(void)
168![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
169
// create the vertices using the CUSTOMVERTEX struct
170
CUSTOMVERTEX vertices[] =
171![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
172![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 400.0f, 62.5f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
173![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 650.0f, 500.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
174![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 150.0f, 500.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
175
};
176![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
177
// create a vertex buffer interface called v_buffer
178
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
179
0,
180
CUSTOMFVF,
181
D3DPOOL_MANAGED,
182
&v_buffer,
183
NULL);
184![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
185
VOID* pVoid; // a void pointer
186![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
187
// lock v_buffer and load the vertices into it
188
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
189
memcpy(pVoid, vertices, sizeof(vertices));
190
v_buffer->Unlock();
191
}
192![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
来吧,更新您的程序,让我们看看我们得到的。如果你运行这个,你应该在屏幕上看到以下内容:
如果你看到这样的三角,那么恭喜你!你成功了。当然,后面还有更多,在开始下一课之前我建议你试着做做下面的小练习,更可让你更熟悉程序。
1。改变三角形的颜色。
2。在程序运行时改变三角的形状。
3。将一个点的颜色褪色成另一个点的颜色。
当然,你可能会失望地发现,这一个三角形算哪门子三维啊?让我们继续下一课的学习,并使其通过旋转,调整大小和移动让你感觉到它确确实实在三维空间中。
下一课:转变顶点
Translate By 王大宝(OneDouble.net)
posted on 2011-02-24 00:46
叫我老王吧 阅读(3868)
评论(4) 编辑 收藏 引用 所属分类:
DierectX