【原创】《DirectX 9 3D 图形程序设计》 Tutorial 05 光照系统

【原创】《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 }

你可能感兴趣的:(【原创】《DirectX 9 3D 图形程序设计》 Tutorial 05 光照系统)