逐梦旅程学习笔记 DirectX开发入门02:旋转的彩色立方体

本文是 系列笔记DirectX部分的第2篇,上一篇参见

逐梦旅程学习笔记 DirectX开发入门01:应用程序基本框架

这个示例增加了一些实际的内容,首先是绘制一个颜色随机变幻的彩色立方体,其二是显示FPS


我录制了一段运行时刻的视频如下(若无法显示请点此跳转



如果不能播放视频,请参考以下截图

因为GIF动态图片只能播放第一帧,所以就分别截取了几个时刻的静态帧图片










以上都是颜色填充模式,按下数字键‘1’后切换到线框模式



按下数字键‘2’切换回颜色填充模式。这个示例比较简单,没有涉及到高级的内容,如果能够理解01篇的话,这个示例应当不算太难。


我们来看看,原始的App类现在改成什么样了

#include <d3d9.h>
#include <d3dx9.h>
#include <Windows.h>

struct CUSTOMVERTEX
{
	FLOAT x, y, z;
	DWORD color;
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

class App
{
public:
	App();
	~App();
public:
	void Create(HWND hwnd);
	void Render(void);
	void CleanUp(void);

	void InitObjects(void);
	void Rotate(void);

	double GetFPS();

private:
	D3DPRESENT_PARAMETERS d3dpp;
	LPDIRECT3DDEVICE9 device;
	ID3DXFont*  pFont;
	char szFPS[32];

	LPDIRECT3DVERTEXBUFFER9		pVertexBuffer = NULL;    //顶点缓冲区对象
	LPDIRECT3DINDEXBUFFER9		pIndexBuffer = NULL;    // 索引缓存对象

	RECT rect;
	RECT clientRect;
	int width, height;
	double fps;
	int frameCount;
	DWORD tickCurrent;
	DWORD tickLast;
};

关于FVF(灵活顶点格式)可以参考这篇文章

3D游戏编程入门(十一)D3D基础之FVF格式


比较上述代码可以发现,App类增加了一些成员变量和3个新的方法。

ID3DXFont* pFont;  //将用作文字输出

char szFPS[32];  //存储用于输出的字符串


余下变量意义正如其名,例如

LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;//顶点缓冲区对象

LPDIRECT3DINDEXBUFFER9 pIndexBuffer = NULL;//索引缓存对象


现在主要关注InitObjects(), Rotate(), GetFPS() 这3个函数


InitObjects用来初始化将要绘制的内容(立方体),具体内容如下


基本上是直接复制浅墨《逐梦旅程》一书中的代码,小作修改

void App::InitObjects()
{
	//创建顶点缓存
	device->CreateVertexBuffer(8 * sizeof(CUSTOMVERTEX),
		0, D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT, &pVertexBuffer, NULL);
	// 创建索引缓存
	device->CreateIndexBuffer(36 * sizeof(WORD), 0,
		D3DFMT_INDEX16, D3DPOOL_DEFAULT, &pIndexBuffer, NULL);
	
	CUSTOMVERTEX Vertices[] =
	{
		{ -20.0f, 20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ -20.0f, 20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ 20.0f, 20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ 20.0f, 20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ -20.0f, -20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ -20.0f, -20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ 20.0f, -20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },
		{ 20.0f, -20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256) },

	};

	//填充顶点缓存
	VOID* pVertices;
	pVertexBuffer->Lock(0, sizeof(Vertices), (void**)&pVertices, 0);
	memcpy(pVertices, Vertices, sizeof(Vertices));
	pVertexBuffer->Unlock();

	// 填充索引数据
	WORD *pIndices = NULL;
	pIndexBuffer->Lock(0, 0, (void**)&pIndices, 0);

	// 顶面
	pIndices[0] = 0, pIndices[1] = 1, pIndices[2] = 2;
	pIndices[3] = 0, pIndices[4] = 2, pIndices[5] = 3;
	// 正面
	pIndices[6] = 0, pIndices[7] = 3, pIndices[8] = 7;
	pIndices[9] = 0, pIndices[10] = 7, pIndices[11] = 4;
	// 左侧面
	pIndices[12] = 0, pIndices[13] = 4, pIndices[14] = 5;
	pIndices[15] = 0, pIndices[16] = 5, pIndices[17] = 1;
	// 右侧面
	pIndices[18] = 2, pIndices[19] = 6, pIndices[20] = 7;
	pIndices[21] = 2, pIndices[22] = 7, pIndices[23] = 3;
	// 背面
	pIndices[24] = 2, pIndices[25] = 5, pIndices[26] = 6;
	pIndices[27] = 2, pIndices[28] = 1, pIndices[29] = 5;
	// 底面
	pIndices[30] = 4, pIndices[31] = 6, pIndices[32] = 5;
	pIndices[33] = 4, pIndices[34] = 7, pIndices[35] = 6;
	pIndexBuffer->Unlock();

	device->SetRenderState(D3DRS_LIGHTING, FALSE);      //关闭光照
	device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);   //开启背面消隐
}

Rotate()是旋转操作,稍后再详细讲解

GetFPS()是获取当前帧率(frame per second)


以下frameCount,tickCurrent,tickLast,fps都是App类的成员变量

double App::GetFPS()
{
	++frameCount;
	tickCurrent = GetTickCount();
	double delta = ((double)(tickCurrent - tickLast)) / 1000.0;
	if (delta > 1.0) 
	{
		fps = ((double)frameCount) / delta;
		tickLast = tickCurrent;
		frameCount = 0;
	}

	return fps;
}

因为GetFPS()函数在每一次执行Render()即绘制操作时都被调用,因此调用GetFPS()的次数就是绘制的次数

这样,如果我们记录调用GetFPS()的时刻和帧数frameCount

当时间间隔达到1秒的时候,这时候计算出这一秒间隔内绘制的frameCount就能得到帧率fps


接下来看看Render()函数的内容

void App::Render()
{
	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 128), 1.0f, 0);
	device->BeginScene();                 

	Rotate();

	if (::GetAsyncKeyState(0x31) & 0x8000f)         // 若数字键1被按下,进行线框填充
		device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	if (::GetAsyncKeyState(0x32) & 0x8000f)         // 若数字键2被按下,进行实体填充
		device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

	device->SetStreamSource(0, pVertexBuffer, 0, sizeof(CUSTOMVERTEX));//把包含的几何体信息的顶点缓存和渲染流水线相关联
	device->SetFVF(D3DFVF_CUSTOMVERTEX);//指定我们使用的灵活顶点格式的宏名称
	device->SetIndices(pIndexBuffer);//设置索引缓存
	device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);//利用索引缓存配合顶点缓存绘制图形

	int ct=sprintf_s(szFPS, 32, "FPS:%08.3f", GetFPS());
	pFont->DrawText(NULL, szFPS, ct, &clientRect, DT_TOP|DT_RIGHT , D3DCOLOR_XRGB(255, 0, 255));
	device->EndScene();
	device->Present(NULL, NULL, NULL, NULL);
}

首先是device->Clear()对画面进行刷新

然后是device->BegineScene()准备绘制流水


接着Rotate()执行旋转操作


期间按照渲染步骤(渲染管线/流水线)进行设置,DX会自动进行后台计算处理


再接着device->EndScene()结束绘制流水


最后device->Present()呈现(根据交换链中当前帧进行填充)


本文原创,部分代码参考了浅墨《逐梦旅程》中的示例


完整代码参见


https://github.com/fengyhack/DirectGame/tree/CubeDemo


博文原始地址


http://blog.csdn.net/fengyhack/article/details/41682143





转载于:https://www.cnblogs.com/fengyhack/p/10603635.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值