DirectX3D开发之绘制第一个图形

欢迎访问EasyLiu的博客!

在前一章节我们已经创建了我们的第一个DirectX3D项目,但是只是显示一个灰色的窗口而已,并没有进行相应的

绘图操作。那么今天,我们就来让窗口变得更漂亮一些。

今天主要讲通过顶点缓冲区绘制图形。什么是顶点缓冲区?顶点缓冲区就是用来保存顶点数据的内存缓冲区,在DirectX3D中由COM接口IDirectVertexBuffer9表示,顶点缓冲区中顶点的数据就决定了渲染到屏幕上的效果。

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices

顶点数据可以包含坐标、颜色等属性,而具体使用什么属性,可以使用灵活顶点格式(FVF)规定顶点的格式。FVF中包含了多种属性,我们可以根据我们的需要来定义我们的顶点数据格式,以逻辑或(|)连接即可,如下:

// A structure for our custom vertex type
struct CUSTOMVERTEX
{
	FLOAT x, y, z, rhw; // The transformed position for the vertex
	DWORD color;        // The vertex color
};

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

这里我们定义了自己的顶点格式,其中包括D3DFVF_XYZRHW(经过转换后的坐标)和D3DFVF_DIFFUSE(漫反射)。在顶点结构体中没有RHW时,Direct3D将执行视、投影、世界等变换以及进行光线计算,之后你才能在窗口中得到你所绘制的物体,这个在下一节仔细讲。当顶点结构体中有RHW时,告知Direct3D使用的顶点已经在屏幕坐标系中了,不再执行视图、投影、世界等变换和光线计算,因为D3DFVF_XYZRHW标志告诉它顶点已经经过了这些处理,并直接将顶点进行光栅操作,任何用SetTransform进行的转换都对其无效。不过这时的原点就在客户区的左上角了,其中x向右为正,y向下为正,而z的意义已经变为z-buffer的象素深度。值得注意的是D3DFVF_XYZRHW和D3DFVF_XYZ、D3DFVF_NORMAL不能共存,因为后两个标志与前一个矛盾。

定义了顶点格式之后,我们就来初始化我们的顶点缓冲区。这里,定义了一个初始化函数InitVB:

HRESULT InitVB()
{
	// Initialize three vertices for rendering a triangle
	CUSTOMVERTEX vertices[] =
	{
		{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
		{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00,},
		{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
	};

	// Create the vertex buffer. Here we are allocating enough memory
	// (from the default pool) to hold all our 3 custom vertices. We also
	// specify the FVF, so the vertex buffer knows what data it contains.
	if (FAILED(g_pd3dDevice->CreateVertexBuffer(3 * sizeof(CUSTOMVERTEX),
		0, D3DFVF_CUSTOMVERTEX,
		D3DPOOL_DEFAULT, &g_pVB, NULL)))
	{
		return E_FAIL;
	}

	// Now we fill the vertex buffer. To do this, we need to Lock() the VB to
	// gain access to the vertices. This mechanism is required becuase vertex
	// buffers may be in device memory.
	VOID* pVertices;
	if (FAILED(g_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
		return E_FAIL;
	memcpy(pVertices, vertices, sizeof(vertices));
	g_pVB->Unlock();
	return S_OK;
}

在InitVB中,首先定义图形的顶点,在此我们初始化了一个三角形的三个顶点,存放在vertices数组中(注意:顶点的填充顺序与裁剪方式有关,默认是顺时针,可以通过g_pDevice->SetRenderState(…)进行设置,以后我们会进行讲解)。g_pDevice是有效的DirectX3D设备指针,CreateVertexBuffer方法就是创建顶点缓冲区的方法,第一个参数表示要创建的顶点缓冲区的大小(字节数),在此我们设置为数组的大小;第二个参数表示顶点缓冲区的属性,在此设置为0;第三个参数表示灵活顶点格式,设置为定义好的CUSTOMVERTEX;第四个参数表示顶点缓冲区内存类型,从枚举类型D3DPOOL(内存池)中选择,在此选择默认类型D3DPOOL_DEFAULT();第五个参数就是顶点缓冲区接口的地址;第六个参数是保留参数,在此设置为NULL。

顶点缓冲区创建好了之后,我们需要将vertexes中的数据填充进去,这时,我们需要两个函数:Lock()、Unlock()。在对顶点缓冲区进行修改时,必须先后调用加锁与解锁方法,然后通过memcpy方法,将数据拷贝到缓冲区中即可。

到此,顶点缓冲区就初始化完毕了。然后在消息循环之前调用此方法以使顶点缓冲区有效。

再就是Render()方法,

VOID Render()
{
	// Clear the backbuffer to a blue color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	// Begin the scene
	if (SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		// Draw the triangles in the vertex buffer. This is broken into a few
		// steps. We are passing the vertices down a "stream", so first we need
		// to specify the source of that stream, which is our vertex buffer. Then
		// we need to let D3D know what vertex shader to use. Full, custom vertex
		// shaders are an advanced topic, but in most cases the vertex shader is
		// just the FVF, so that D3D knows what type of vertices we are dealing
		// with. Finally, we call DrawPrimitive() which does the actual rendering
		// of our geometry (in this case, just one triangle).
		g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
		//The first parameter accepted by DrawPrimitive is a flag that tells Direct3D what type of primitives to draw
		//This sample uses the flag D3DPT_TRIANGLELIST to specify a list of triangles.
		//The second parameter is the index of the first vertex to load.
		//The third parameter tells the number of primitives to draw.
		//Because this sample draws only one triangle, this value is set to 1.
		//g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

		// End the scene
		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

Render()方法主要调用了三个方法SetStreamSource、SetFVF、DrawPrimitive。

SetStreamSource方法的作用是将顶点缓冲区与渲染数据流连接起来,第一个参数表示与顶点缓冲区链接的渲染数据流的编号(>=0);第二个参数表示顶点缓冲区接口指针;第三个参数表示渲染数据流的起始位置;第四个参数表示相邻顶点距离的字节数,在此为VERTEX结构体CUSTOMVERTEX的大小。

SetFVF方法设置渲染数据流的灵活顶点格式,在此设置自己定义的CUSTOMVERTEX。

DrawPrimitive就是用来绘制渲染数据流中图元的方法。其中有三个参数,分别为,第一个参数表示渲染的图元类型,在此为D3DPT_TRIANGLELIST(三角形列表);第二个参数表示从顶点缓冲区的第几个顶点开始绘制;第三个参数表示绘制的图元的数量。

最后别忘了在Cleanup方法中将g_pVB接口Release掉,

VOID Cleanup()
{
	if (g_pVB != NULL)
		g_pVB->Release();

	if (g_pd3dDevice != NULL)
		g_pd3dDevice->Release();

	if (g_pD3D != NULL)
		g_pD3D->Release();
}

保存修改,按Ctrl+F5运行项目,效果如下:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 05:38:42

DirectX3D开发之绘制第一个图形的相关文章

DirectX3D开发之绘制流水线(一)

欢迎来到EasyLiu的博客 ! 参考:directxtutorial.com   DirectX.9.0.3D游戏开发编程基础 In the last lesson you built a simple, flat triangle lit with simple diffuse lighting. This triangle was not 3D, it was flat. If you managed to change it, you found it was a 2D triangle

绘制一些基本图形(例如矩形,圆形,椭圆,多边形)

drawRect:矩形 drawCircle:绘制圆形 drawOval:椭圆 drawPath:任意多边形 drawLine:直线 drawPoint:绘制点 代码示例 第一种 package com.example.examples_05_05; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graph

iOS开发-边线绘制控件及虚线绘制原理

最近的项目设计稿中,出现了虚线分割线这种东西,想起之前自己做的一个用于绘制各种边线效果的控件YRBorderView,但是只支持实线条,立刻对其进行了升级. 支持四条边线不同颜色,不同粗细,不同弧度,支持裁剪掉边线外部,支持虚线. 效果图: 需要试试这控件的请戳:YRBorderView 关于简单的线条和图形绘制请看我之前的CoreGraphics系列博客: http://blog.csdn.net/u010124617/article/details/9222753 这里再说明下虚线的绘制,利

Cacti 是一套基于PHP,MySQL,SNMP及RRDTool开发的网络流量监测图形分析工具

Cacti 是一套基于PHP,MySQL,SNMP及RRDTool开发的网络流量监测图形分析工具. mysqlreport是mysql性能监测时最常用的工具,对了解mysql运行状态和配置调整都有很大的帮助. mysqlsla是hackmysql.com推出的一款MySQL的日志分析工具,功能非常强大. 数据报表,非常有利于分析慢查询的原因, 包括执行频率, 数据量, 查询消耗等. http://www.kxtry.com/archives/338

Android开发艺术探索——第一章:Activity的生命周期和启动模式

Android开发艺术探索--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activity搬上来了,也确实,和Activity打交道的次数基本上是最多的,而且他的内容和知识点也是很多的,非常值得我们优先把他掌握,Activity中文翻译过来就是"活动"的意思,但是主席觉得这样翻译有些生硬,直接翻译成"界面"可能更好,的确,Activity主要也是用于UI效

微软Azure云计算开发实战(1):第一步申请注册Azure账号

,这个系列文章来系统介绍Azure的相关开发知识,包括账号申请,部署网站,开发虚拟机服务器,安装SQL数控,Hadoop对接,NoSQL安全,负载均衡等知识. 作为系列的第一课<微软Azure云计算开发实战(1):第一步注册Azure账号>我们先说一下如何申请微软Azure账号, 无论开发人员,还是企业,都想在正式使用之前,体验一下Aure的功能.第一步就是申请微软的Azure账号. 账号的申请比较简单,因为Azure的配置比较高,所以测试账号在国内一直比较抢手,完全免费的测试账号基本也是10

产品级敏捷开发关键的第一步: 制订版本发布的节奏

前言: 产品级敏捷开发主要的目的是要达到: 以最少的产出, 却能对客户产生最大的正面影响? PI(Program Increment) 则是制定版本发布的节奏, 以使团队能在最短的版本开发周期内, 产出对客户最有价值的产品特性或功能? 所以, 产品级敏捷开发关键的第一步便是: 依照产品质量与团队人员能力的现况, 制订出合理且能满足外部客户要求的PI (Program Increment)? 本文: 制订出合理且能满足外部客户要求的PI (Program Increment), 便需综合产品质量的

转游戏开发做的第一款手机网游的经历和体会

转游戏开发大半年以来,做过的游戏不多,刚开始就写单机版的游戏,不过也不多.后来就接触手机版网游,第一款游戏就是超级英雄,目前这款游戏还在升级维护当中,首次发布就是五月初,第一个月的收入就过千万.关于这款游戏直接看截图效果吧! 以上就是有关该款游戏的截图,有喜欢这款游戏可以下载试玩下,有想学的也可以下载看看交流下经验. 我以前是学C#,主要做桌面类型的软件会的语言也不多,也用过C++.在去年年底就接触到了cocos2d-x,了解到它是跨平台的然后就决心转手游开发了,初期阶段就看书,自己做些东西,也

学习OpenGL(三)绘制螺旋状图形

学习OpenGL(三)绘制螺旋状图形 [email protected] http://blog.csdn.net/kezunhai 在OpenGl中,图形都是有一些基本的图元组成的,图元是把一组定点或顶点列表解释为屏幕上绘制的某些图形,OpenGL中的最小图元就是点.在OpenGL中有10中图元,可以实现从空间中绘制的简单的点到任意变数的封闭多边形,这十种图元分别是: 绘制图形的格式如下: glBegin("图元类型"); glVertex3f(GLfloat x, GLfloat