热爱互联网

《DirectX游戏编程》第五章——基本图元的绘制实例


三维坐标系
通常说来,3D图形应用程序采用两种坐标系:左手坐标系和右手坐标系。在这两种坐标系中,X轴正坐标朝右,Y轴正坐标朝上。左手坐标系的Z轴正坐标方向确定方法为:伸出左手,手指方向指向X轴正坐标,手掌方向为Y轴正坐标方向,拇指所指向的方向即为Z轴正坐标方向。右手坐标系的Z轴正坐标方向确定方法为:伸出右手,手指方向指向X轴正坐标,手掌方向为Y轴正方向,拇指所指向的方向几位Z轴正坐标方向。
Direct3D采用左手坐标系,基于DirectX的XNA采用的是右手坐标系。将一个左手坐标系的物体坐标转换为右手坐标系坐标的方法是,将物体的坐标Z轴坐标取反。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/** 包含链接的库文件 */
#pragma comment(lib,"dxerr.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3dx9d.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"comctl32.lib")
 
#include<d3d9.h>
#include<windows>
 
// 全局变量
LPDIRECT3D9					g_pD3D = NULL;        //Direct3D对象
LPDIRECT3DDEVICE9			g_pd3dDevice = NULL;  // DirectX3D设备对象
LPD3DXFONT					g_pFont = NULL;		  // 字体对象
WCHAR*						strText = L"请输入要显示的图元的代码:n
									1:	点列表n
									2:	线段列表n
									3:	线段条带n
									4:	三角形列表n
									5:	三角形条带n
									6:	三角形扇n
									ESC 退出";
RECT						clientRect;
LPDIRECT3DVERTEXBUFFER9		g_pVB = NULL;	     //顶点缓存对象
int							g_iType = 1;		 // 图元类型
 
struct CUSTOMVERTEX		//定义顶点结构
{
	FLOAT x,y,z,rhw;
	DWORD color;
};
 
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)     // 与顶点结构对应的 FVF 格式
 
//函数声明
HRESULT InitializeVB();			   // 完成整个顶点初始化操作
HRESULT InitializeD3D(HWND hWnd);  //初始化 DirectX3D
VOID Render();					   // 渲染图形
VOID Cleanup();					  // 释放创建对象
LRESULT WINAPI MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);  //消息处理
 
//函数定义
 
HRESULT InitializeVB()
{
	// 顶点数据
	CUSTOMVERTEX vertices[] =
	{
		{ 50.0f, 250.0f, 0.5f, 1.0f, 0xffff0000 },
		{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000 },
		{ 250.0f, 250.0f, 0.5f, 1.0f, 0xffff0000 },
 
		{ 350.0f, 50.0f, 0.5f, 1.0f, 0xffff0000 },
		{ 450.0f, 250.0f, 0.5f, 1.0f, 0xffff0000 },
		{ 550.0f, 50.0f, 0.5f, 1.0f, 0xffff0000 },
	};
 
	// 创建顶点缓存
	if( FAILED( g_pd3dDevice-&gt;CreateVertexBuffer(6*sizeof(CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,
									D3DPOOL_DEFAULT,&amp;g_pVB,NULL) ) )
	{
		return E_FAIL;
	}
 
	// 填充顶点缓存
	VOID* pVertices;
	if( FAILED( g_pVB-&gt;Lock(0,sizeof(vertices),(void**)&amp;pVertices,0) ) )
		return E_FAIL;
	memcpy( pVertices,vertices,sizeof(vertices) );
	g_pVB-&gt;Unlock();
 
	return S_OK;
}
 
HRESULT InitializeD3D(HWND hWnd)
{
	// 创建 DirectX3D对象,该对象用来创建DirectX3D设备对象
	if( NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
		return FALSE;
 
	// 设置 D3DPRESENT_PARAMETERS 结构,准备创建 DirectX3D设备对象
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&amp;d3dpp,sizeof(d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
 
	// 创建 DirectX3D 设备对象
	if( FAILED(g_pD3D-&gt;CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,&amp;d3dpp,&amp;g_pd3dDevice)) )
	{
		return FALSE;
	}
 
	// 创建字体对象
	if( FAILED(D3DXCreateFont(g_pd3dDevice,0,0,0,0,0,0,0,0,0,TEXT("Arial"),&amp;g_pFont)) )
		return E_FAIL;
 
	// 设置剔除模式为不剔除任何面
	g_pd3dDevice-&gt;SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
 
	// 设置图元填充模式为线框模式
	g_pd3dDevice-&gt;SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
 
	// 获取窗口客户区
	GetClientRect(hWnd,&amp;clientRect);
 
	return TRUE;
}
 
VOID Render()
{
	// 清空后台缓存
	g_pd3dDevice-&gt;Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
 
	// 开始在后台缓存绘制图形
	if( SUCCEEDED(g_pd3dDevice-&gt;BeginScene()) )
	{
		//在此在后台缓存绘制图形
		g_pFont-&gt;DrawText(NULL,strText,(int)wcslen(strText),&amp;clientRect,DT_NOCLIP|DT_LEFT|DT_TOP,0xffffffff);
		g_pd3dDevice-&gt;SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX));
		g_pd3dDevice-&gt;SetFVF(D3DFVF_CUSTOMVERTEX);
 
		// 选择绘制图元的类型
		switch ( g_iType )
		{
		case 1:		//点列表
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_POINTLIST,0,6);
			break;
 
		case 2:		//线段列表
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_LINELIST,0,3);
			break;
 
		case 3:		//线段条带
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_LINESTRIP,0,5);
			break;
 
		case 4:		//三角形列表
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_TRIANGLELIST,0,2);
			break;
 
		case 5:		//三角形条带
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_TRIANGLESTRIP,0,4);
			break;
 
		case 6:		//三角形扇
			g_pd3dDevice-&gt;DrawPrimitive(D3DPT_TRIANGLEFAN,0,4);
			break;
		}
 
		//结束在后台缓存绘制图形
		g_pd3dDevice-&gt;EndScene();
	}
 
	// 将在后台缓存绘制的图形提交到前台缓存显示
	g_pd3dDevice-&gt;Present(NULL,NULL,NULL,NULL);
}
 
VOID Cleanup()
{
	// 释放 DirectX3D设备对象
	if( g_pd3dDevice )
		g_pd3dDevice-&gt;Release();
 
	// 释放 DirectX3D对象
	if( g_pD3D )
		g_pD3D-&gt;Release();
 
	// 释放字体对象
	if( g_pFont )
		g_pFont-&gt;Release();
 
	// 释放顶点缓存对象
	if( g_pVB )
		g_pVB-&gt;Release();
}
 
LRESULT WINAPI MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch ( msg )
	{
	case  WM_DESTROY:
		Cleanup();
		PostQuitMessage(0);
		return 0;
 
	case WM_KEYUP:
		switch( wParam )
		{
		case 49:  	// '1' 键, ASCII值为 49
		case 50:    // '2'
		case 51:    // '3'
		case 52:	// '4'
		case 53:	// '5'
		case 54:	// '6'
			{
				g_iType = (int)wParam-48;  //设置渲染图元类型
			}
			break;
 
		case VK_ESCAPE:
			{
				Cleanup();
				PostQuitMessage(0);
			}
			break;
		}
		break;
	}
 
	return DefWindowProc(hWnd,msg,wParam,lParam);
}
 
//程序入口
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,INT)
{
	// 注册窗口类
	WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,MsgProc,0L,0L,GetModuleHandle(NULL),
		NULL,NULL,NULL,NULL,L"ClassName",NULL };
 
	RegisterClassEx(&amp;wc);
 
	//创建窗口
	HWND hWnd = CreateWindow(L"ClassName",L"基本图元",WS_OVERLAPPEDWINDOW,
		200,100,600,500,NULL,NULL,wc.hInstance,NULL);
 
	// 初始化 Direct3D
	if( SUCCEEDED(InitializeD3D(hWnd)) )
	{
		if( FAILED(InitializeVB()) )
		{
			MessageBox(hWnd,L"fuck",NULL,MB_OK);
			PostMessage(hWnd,WM_KEYUP,VK_ESCAPE,NULL);
		}
 
		//显示窗口
		ShowWindow(hWnd,SW_SHOWDEFAULT);
		UpdateWindow(hWnd);
 
		//进入消息循环
		MSG msg;
		ZeroMemory(&amp;msg,sizeof(msg));
		while( msg.message != WM_QUIT )
		{
			if(PeekMessage(&amp;msg,NULL,0U,0U,PM_REMOVE))
			{
				TranslateMessage(&amp;msg);
				DispatchMessage(&amp;msg);
			}
			else
			{
				Render();  //渲染图形
			}
		}
	}
 
	UnregisterClass(L"ClassName",wc.hInstance);
	return 0;
}

One Comment

Post a Comment

Your email is kept private. Required fields are marked *