【原创】《DirectX 9 3D 图形程序设计》 Tutorial 05 光照系统
1
#include
<
D3DX9.h
>
2
#include
<
string
>
3
typedef std::
string
String;
4
#define
SAFE_RELEASE(o) {if(o){o->Release();o = 0;}}
5
6
7
LPDIRECT3D9 g_pD3D
=
0
;
//
D3D Driver
8
LPDIRECT3DDEVICE9 g_pd3dDevice
=
0
;
//
D3D 设备
9
D3DCAPS9 g_Caps
=
{(D3DDEVTYPE) 0 }
;
//
D3D 的帽子
10
LPDIRECT3DVERTEXBUFFER9 g_pVB
=
0
;
//
顶点缓冲区
11
LPDIRECT3DINDEXBUFFER9 g_pIB
=
0
;
//
索引缓冲区
12
13
//
顶点定义
14
#define
D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL )
15
struct
CUSTOMVERTEX
16
{
17
D3DXVECTOR3 position;
18
D3DXVECTOR3 normal;
19
}
;
20
21
//
错误记录
22
void
D3DErr(String strMsg)
23
{
24
MessageBox( 0 , strMsg.c_str() , " 错误 " , MB_OK);
25
}
26
27
//
初始化顶点缓冲区
28
HRESULT InitVB()
29
{
30
// 创建顶点缓冲区
31
if (FAILED(g_pd3dDevice -> CreateVertexBuffer( 50 * 2 * sizeof (CUSTOMVERTEX) , 0 , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & g_pVB , 0 )))
32
return E_FAIL;
33
34
CUSTOMVERTEX * pVertecies;
35
// 锁定缓冲区
36
if (SUCCEEDED(g_pVB -> Lock( 0 , 0 , ( void ** ) & pVertecies , 0 )))
37
{
38
for ( int i = 0 ; i < 100 ; i += 2 )
39
{
40
float theta = 2 * D3DX_PI * i / ( 50 - 1 );
41
// 根据圆的方程 x = x' + r * sin(θ)
42
// y = y' + r * cos(θ)
43
// 求解圆
44
pVertecies[i].position = D3DXVECTOR3(sinf(theta) , 1 , cosf(theta));
45
pVertecies[i].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
46
47
pVertecies[i + 1 ].position = D3DXVECTOR3(sinf(theta) , - 1 , cosf(theta));
48
pVertecies[i + 1 ].normal = D3DXVECTOR3(sinf(theta) , 0 , cosf(theta));
49
50
}
51
g_pVB -> Unlock();
52
}
53
else
54
{
55
return E_FAIL;
56
}
57
return S_OK;
58
}
59
60
//
初始化模型
61
HRESULT InitGeometry()
62
{
63
// 创建顶点缓冲区
64
if (FAILED(InitVB()))
65
return E_FAIL;
66
return S_OK;
67
}
68
69
//
设置矩阵变换
70
void
SetTransform()
71
{
72
73
// 世界变换
74
D3DXMATRIX matWorld , matT1 , matT2 , matR;
75
D3DXMatrixIdentity( & matWorld);
76
DWORD dwTime = timeGetTime();
77
// 角度
78
float fAngle = 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f ;
79
80
// 平移到原点
81
D3DXMatrixTranslation( & matT1 , - 0.5 , - 1 , 0 );
82
// Z旋转
83
D3DXMatrixRotationZ( & matR , sin(fAngle));
84
// 移动到原来的位置
85
D3DXMatrixTranslation( & matT2 , 0.5 /**/ /* - 3 * (dwTime % 5000) / 5000.0f */ , 1 , 0 );
86
// 平移到原点再旋转
87
matWorld = matT1 * matR;
88
// 平移回原来的位置
89
matWorld *= matT2;
90
91
92
// 放大缩小
93
D3DXMatrixScaling( & matWorld , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )) , abs(sin( 2 * D3DX_PI * (dwTime % 3000 ) / 3000.0f )));
94
// 设置缩放点
95
matWorld._41 = ( 1.0f - matWorld._11) * 0.5 ; // x
96
matWorld._42 = ( 1.0f - matWorld._22) * 0.5 ; // y
97
matWorld._43 = ( 1.0f - matWorld._33) * 0 ; // z
98
99
100
// 设置世界矩阵
101
g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);
102
// Set up our view matrix. A view matrix can be defined given an eye point,
103
// a point to lookat, and a direction for which way is up. Here, we set the
104
// eye five units back along the z-axis and up three units, look at the
105
// origin, and define "up" to be in the y-direction.
106
// 视口变换
107
D3DXMATRIX matView;
108
D3DXMatrixLookAtLH( & matView , & D3DXVECTOR3( 0 , 3 , - 5 )
109
, & D3DXVECTOR3( 0 , 0 , 0 )
110
, & D3DXVECTOR3( 0 , 1 , 0 ));
111
g_pd3dDevice -> SetTransform(D3DTS_VIEW , & matView);
112
// For the projection matrix, we set up a perspective transform (which
113
// transforms geometry from 3D view space to 2D viewport space, with
114
// a perspective divide making objects smaller in the distance). To build
115
// a perpsective transform, we need the field of view (1/4 pi is common),
116
// the aspect ratio, and the near and far clipping planes (which define at
117
// what distances geometry should be no longer be rendered).
118
D3DXMATRIXA16 matProj;
119
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 1.0f , 1.0f , 100.0f );
120
g_pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );
121
}
122
123
//
设置灯光
124
void
SetupLight()
125
{
126
// Set up a material. The material here just has the diffuse and ambient
127
// colors set to yellow. Note that only one material can be used at a time.
128
// set up lights
129
D3DXVECTOR3 vecDir;
130
// 创建一个平行光
131
D3DLIGHT9 light;
132
ZeroMemory( & light, sizeof (D3DLIGHT9) );
133
light.Type = D3DLIGHT_DIRECTIONAL; // 平行光
134
light.Diffuse.r = 0.0f ;
135
light.Diffuse.g = 1.0f ; // 红色
136
light.Diffuse.b = 0.0f ;
137
vecDir = D3DXVECTOR3( 10 , 10 , - 10 ); // 方向是从0,0,0指向10,10,-10
138
139
// 正规化向量,就是说把向量长度正规化成1,方向不变!好处是光照运算时的误差会降到最小(纯属我的理解,不知道正确与否)
140
D3DXVec3Normalize( (D3DXVECTOR3 * ) & light.Direction, & vecDir );
141
// 设置0号光照为此灯光参数
142
g_pd3dDevice -> SetLight( 0 , & light );
143
144
// 开启0号光照
145
g_pd3dDevice -> LightEnable( 0 , TRUE );
146
// 开启光照系统
147
g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
148
149
D3DXVECTOR3 vecPos2;
150
// 一个点光源
151
D3DLIGHT9 light2;
152
ZeroMemory( & light2, sizeof (D3DLIGHT9) );
153
light2.Type = D3DLIGHT_POINT; // 点光源
154
light2.Diffuse.r = 0.9f ; // 红色
155
light2.Diffuse.g = 0.0f ;
156
light2.Diffuse.b = 0.0f ;
157
158
// 位置,随着时间的推移,围绕Y轴周围的圆圈旋转,根据圆的方程来建立的sinf和cosf函数
159
light2.Position = D3DXVECTOR3( 10 * sinf(timeGetTime() / 350.0f ) ,
160
10 ,
161
10 * cosf(timeGetTime() / 350.0f ) );
162
163
light2.Range = 15 ;
164
light2.Attenuation0 = 1.0f ;
165
g_pd3dDevice -> SetLight( 1 , & light2 );
166
g_pd3dDevice -> LightEnable( 1 , TRUE );
167
168
// 开启光照系统(纯属多余!开启一次就行了!)
169
g_pd3dDevice -> SetRenderState( D3DRS_LIGHTING, TRUE );
170
171
// 最后,开启环境光
172
g_pd3dDevice -> SetRenderState( D3DRS_AMBIENT, 0x00202020 );
173
174
D3DMATERIAL9 mtrl;
175
ZeroMemory( & mtrl, sizeof (D3DMATERIAL9) );
176
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f ;
177
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f ;
178
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f ;
179
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f ;
180
// 设置物体的材质
181
g_pd3dDevice -> SetMaterial( & mtrl );
182
183
}
184
185
//
渲染场景
186
void
Render()
187
{
188
if (g_pd3dDevice)
189
{
190
// 清空场景
191
g_pd3dDevice -> Clear( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0 , 0 , 0 ) , 1 , 0 );
192
// 开始渲染
193
if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
194
{
195
SetTransform();
196
SetupLight();
197
g_pd3dDevice -> SetRenderState(D3DRS_AMBIENT , D3DCOLOR_XRGB( 64 , 64 , 64 ));
198
g_pd3dDevice -> SetStreamSource( 0 , g_pVB , 0 , sizeof (CUSTOMVERTEX));
199
g_pd3dDevice -> SetFVF(D3DFVF_CUSTOMVERTEX);
200
g_pd3dDevice -> DrawPrimitive(D3DPT_TRIANGLESTRIP , 0 , 2 * 50 - 2 );
201
g_pd3dDevice -> EndScene();
202
}
203
// 显示
204
g_pd3dDevice -> Present( 0 , 0 , 0 , 0 );
205
}
206
}
207
208
//
初始化 D3D 设备
209
HRESULT InitD3D(HWND hWnd)
210
{
211
// 创建 D3D Driver
212
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
213
{
214
D3DErr( " 无法创建Direct3D9设备 " );
215
return E_FAIL;
216
}
217
// 获取当前显示模式
218
D3DDISPLAYMODE d3ddm;
219
if (FAILED(g_pD3D -> GetAdapterDisplayMode(D3DADAPTER_DEFAULT , & d3ddm)))
220
{
221
D3DErr( " 无法获取D3D显示器模式 " );
222
return E_FAIL;
223
}
224
225
// 获取窗口的大小
226
RECT rect;
227
GetClientRect(hWnd , & rect);
228
229
// 填充参数
230
D3DPRESENT_PARAMETERS d3dpp;
231
memset( & d3dpp , 0 , sizeof (d3dpp));
232
d3dpp.BackBufferFormat = d3ddm.Format;
233
d3dpp.BackBufferWidth = rect.right - rect.left;
234
d3dpp.BackBufferHeight = rect.bottom - rect.top;
235
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
236
d3dpp.Windowed = true ;
237
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
238
d3dpp.EnableAutoDepthStencil = TRUE;
239
240
// 获取帽子
241
if (FAILED(g_pD3D -> GetDeviceCaps(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , & g_Caps)))
242
{
243
D3DErr( " 获取D3D 帽子时发生错误 " );
244
return E_FAIL;
245
}
246
247
// 创建D3D设备
248
if (FAILED(g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT
249
, D3DDEVTYPE_HAL
250
, hWnd
251
// 检查是否支持硬件顶点处理
252
, g_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING
253
, & d3dpp
254
, & g_pd3dDevice
255
)
256
))
257
{
258
D3DErr( " 创建D3D设备时发生错误 " );
259
return E_FAIL;
260
}
261
g_pd3dDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
262
g_pd3dDevice -> SetRenderState( D3DRS_ZENABLE, TRUE );
263
264
if (FAILED(InitGeometry()))
265
return E_FAIL;
266
return S_OK;
267
}
268
269
//
清空所有占用的资源
270
void
CleanUp()
271
{
272
SAFE_RELEASE(g_pIB);
273
SAFE_RELEASE(g_pVB);
274
SAFE_RELEASE(g_pd3dDevice);
275
SAFE_RELEASE(g_pD3D);
276
}
277
278
279
//
消息处理
280
LRESULT WINAPI MsgProc(HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam)
281
{
282
switch (message)
283
{
284
case WM_DESTROY:
285
CleanUp();
286
PostQuitMessage( 0 );
287
break ;
288
}
289
return ::DefWindowProc(hWnd, message , wParam , lParam);
290
}
291
292
//
Windows 入口
293
int
WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN
int
nShowCmd )
294
{
295
WNDCLASS wndClass;
296
memset( & wndClass , 0 , sizeof (wndClass));
297
wndClass.hInstance = hInstance;
298
wndClass.lpszClassName = " Tutorial02 " ;
299
wndClass.lpfnWndProc = MsgProc;
300
RegisterClass( & wndClass);
301
302
// 创建窗口
303
HWND hWnd = CreateWindow( " Tutorial02 " , " Tutorial02 Lighting "
304
, WS_OVERLAPPEDWINDOW , 0 , 0 , 512 , 512 , GetDesktopWindow()
305
, 0 , wndClass.hInstance , 0 );
306
// 显示窗口
307
ShowWindow(hWnd , SW_SHOWDEFAULT);
308
UpdateWindow(hWnd);
309
310
// 初始化 D3D 设备
311
if (SUCCEEDED(InitD3D(hWnd)))
312
{
313
// 消息处理循环
314
MSG msg;
315
memset( & msg , 0 , sizeof (msg));
316
while (msg.message != WM_QUIT)
317
{
318
if (PeekMessage( & msg , 0 , 0 , 0 , PM_REMOVE))
319
{
320
TranslateMessage( & msg);
321
DispatchMessage( & msg);
322
}
323
else
324
{
325
Render();
326
}
327
}
328
}
329
// 清空场景
330
CleanUp();
331
332
UnregisterClass( " Tutorial02 " , wndClass.hInstance);
333
334
return 0 ;
335
}
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335