光照
1.首先需要定义这样的顶点结构
struct CUSTOMVERTEX { D3DXVECTOR3position; // 顶点 D3DXVECTOR3normal; // 法向量 }; // Custom flexible vertex format (FVF). #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
2.然后创建一个圆柱体顶点模型
// Create the vertex buffer. if( FAILED(g_pd3dDevice->CreateVertexBuffer(50 * 2 * sizeof( CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL ) )) { return E_FAIL; } // Fill the vertex buffer. We arealgorithmically generating a cylinder // here, including the normals, which are usedfor lighting. CUSTOMVERTEX* pVertices; if( FAILED(g_pVB->Lock(0, 0, ( void** )&pVertices,0 ) ) ) return E_FAIL; for( DWORDi = 0; i< 50; i++ ) { FLOAT theta= ( 2 * D3DX_PI * i) / ( 50 - 1 ); pVertices[2 * i + 0].position = D3DXVECTOR3( sinf(theta ), -1.0f, cosf(theta ) ); pVertices[2 * i + 0].normal = D3DXVECTOR3( sinf(theta ), 0.0f, cosf(theta ) ); pVertices[2 * i + 1].position = D3DXVECTOR3( sinf(theta ), 1.0f, cosf(theta ) ); pVertices[2 * i + 1].normal = D3DXVECTOR3( sinf(theta ), 0.0f, cosf(theta ) ); } g_pVB->Unlock();
3.创建灯光
// Set up a material. The material here just has thediffuse and ambient // colors set to yellow. Note that only onematerial can be used at a time. D3DMATERIAL9 mtrl; //因为有光照,所以需要创建一个材质来接受 ZeroMemory( &mtrl, sizeof( D3DMATERIAL9 ) ); mtrl.Diffuse.r = mtrl.Ambient.r =1.0f; mtrl.Diffuse.g = mtrl.Ambient.g =1.0f; mtrl.Diffuse.b = mtrl.Ambient.b =0.0f; mtrl.Diffuse.a = mtrl.Ambient.a =1.0f; g_pd3dDevice->SetMaterial( &mtrl); // Set up a white, directional light, with anoscillating direction. // Note that many lights may be active at atime (but each one slows down // the rendering of our scene). However, herewe are just using one. Also, // we need to set the D3DRS_LIGHTINGrenderstate to enable lighting D3DXVECTOR3 vecDir; D3DLIGHT9 light;//创建灯光 ZeroMemory( &light, sizeof( D3DLIGHT9 ) ); light.Type= D3DLIGHT_DIRECTIONAL; //设置为平行光 light.Diffuse.r = 1.0f; light.Diffuse.g = 1.0f; light.Diffuse.b = 1.0f; vecDir = D3DXVECTOR3(cosf( timeGetTime()/ 350.0f ), //方向随时间变化 1.0f, sinf( timeGetTime()/ 350.0f ) ); D3DXVec3Normalize( ( D3DXVECTOR3* )&light.Direction, &vecDir); //单位化方向 light.Range= 1000.0f;//方向光这个参数无效 g_pd3dDevice->SetLight( 0, &light); g_pd3dDevice->LightEnable( 0, TRUE); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING,TRUE ); //开启光照 // Finally, turn on some ambient light. g_pd3dDevice->SetRenderState( D3DRS_AMBIENT,0x00202020 ); //设置环境光
比较简单,
全部代码:
//----------------------------------------------------------------------------- // File: Lights.cpp // // Desc: Rendering 3D geometry is much more interesting when dynamic lighting // is added to the scene. To use lighting in D3D, you must create one or // lights, setup a material, and make sure your geometry contains surface // normals. Lights may have a position, a color, and be of a certain type // such as directional (light comes from one direction), point (light // comes from a specific x,y,z coordinate and radiates in all directions) // or spotlight. Materials describe the surface of your geometry, // specifically, how it gets lit (diffuse color, ambient color, etc.). // Surface normals are part of a vertex, and are needed for the D3D's // internal lighting calculations. // // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #include <Windows.h> #include <mmsystem.h> #include <d3dx9.h> #pragma warning( disable : 4996 ) // disable deprecated warning #include <strsafe.h> #pragma warning( default : 4996 ) //----------------------------------------------------------------------------- // Global variables //----------------------------------------------------------------------------- LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices // A structure for our custom vertex type. We added a normal, and omitted the // color (which is provided by the material) struct CUSTOMVERTEX { D3DXVECTOR3 position; // The 3D position for the vertex D3DXVECTOR3 normal; // The surface normal for the vertex }; // Our custom FVF, which describes our custom vertex structure #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL) //----------------------------------------------------------------------------- // Name: InitD3D() // Desc: Initializes Direct3D //----------------------------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { // Create the D3D object. if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; // Set up the structure used to create the D3DDevice. Since we are now // using more complex geometry, we will create a device with a zbuffer. D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // Create the D3DDevice if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } // Turn off culling g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); // Turn on the zbuffer g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); return S_OK; } //----------------------------------------------------------------------------- // Name: InitGeometry() // Desc: Creates the scene geometry //----------------------------------------------------------------------------- HRESULT InitGeometry() { // Create the vertex buffer. if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50 * 2 * sizeof( CUSTOMVERTEX ), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL ) ) ) { return E_FAIL; } // Fill the vertex buffer. We are algorithmically generating a cylinder // here, including the normals, which are used for lighting. CUSTOMVERTEX* pVertices; if( FAILED( g_pVB->Lock( 0, 0, ( void** )&pVertices, 0 ) ) ) return E_FAIL; for( DWORD i = 0; i < 50; i++ ) { FLOAT theta = ( 2 * D3DX_PI * i ) / ( 50 - 1 ); pVertices[2 * i + 0].position = D3DXVECTOR3( sinf( theta ), -1.0f, cosf( theta ) ); pVertices[2 * i + 0].normal = D3DXVECTOR3( sinf( theta ), 0.0f, cosf( theta ) ); pVertices[2 * i + 1].position = D3DXVECTOR3( sinf( theta ), 1.0f, cosf( theta ) ); pVertices[2 * i + 1].normal = D3DXVECTOR3( sinf( theta ), 0.0f, cosf( theta ) ); } g_pVB->Unlock(); return S_OK; } //----------------------------------------------------------------------------- // Name: Cleanup() // Desc: Releases all previously initialized objects //----------------------------------------------------------------------------- VOID Cleanup() { if( g_pVB != NULL ) g_pVB->Release(); if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); if( g_pD3D != NULL ) g_pD3D->Release(); } //----------------------------------------------------------------------------- // Name: SetupMatrices() // Desc: Sets up the world, view, and projection transform matrices. //----------------------------------------------------------------------------- VOID SetupMatrices() { // Set up world matrix D3DXMATRIXA16 matWorld; D3DXMatrixIdentity( &matWorld ); D3DXMatrixRotationX( &matWorld, D3DX_PI/4); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); // Set up our view matrix. A view matrix can be defined given an eye point, // a point to lookat, and a direction for which way is up. Here, we set the // eye five units back along the z-axis and up three units, look at the // origin, and define "up" to be in the y-direction. D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); // For the projection matrix, we set up a perspective transform (which // transforms geometry from 3D view space to 2D viewport space, with // a perspective divide making objects smaller in the distance). To build // a perpsective transform, we need the field of view (1/4 pi is common), // the aspect ratio, and the near and far clipping planes (which define at // what distances geometry should be no longer be rendered). D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } //----------------------------------------------------------------------------- // Name: SetupLights() // Desc: Sets up the lights and materials for the scene. //----------------------------------------------------------------------------- VOID SetupLights() { // Set up a material. The material here just has the diffuse and ambient // colors set to yellow. Note that only one material can be used at a time. D3DMATERIAL9 mtrl; ZeroMemory( &mtrl, sizeof( D3DMATERIAL9 ) ); mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f; mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f; mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f; mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f; g_pd3dDevice->SetMaterial( &mtrl ); // Set up a white, directional light, with an oscillating direction. // Note that many lights may be active at a time (but each one slows down // the rendering of our scene). However, here we are just using one. Also, // we need to set the D3DRS_LIGHTING renderstate to enable lighting D3DXVECTOR3 vecDir; D3DLIGHT9 light; ZeroMemory( &light, sizeof( D3DLIGHT9 ) ); light.Type = D3DLIGHT_DIRECTIONAL; light.Diffuse.r = 1.0f; light.Diffuse.g = 1.0f; light.Diffuse.b = 1.0f; vecDir = D3DXVECTOR3( cosf( timeGetTime() / 350.0f ), 1.0f, sinf( timeGetTime() / 350.0f ) ); D3DXVec3Normalize( ( D3DXVECTOR3* )&light.Direction, &vecDir ); light.Range = 1000.0f; g_pd3dDevice->SetLight( 0, &light ); g_pd3dDevice->LightEnable( 0, TRUE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); // Finally, turn on some ambient light. g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 ); } //----------------------------------------------------------------------------- // Name: Render() // Desc: Draws the scene //----------------------------------------------------------------------------- VOID Render() { // Clear the backbuffer and the zbuffer g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 ); // Begin the scene if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { // Setup the lights and materials SetupLights(); // Setup the world, view, and projection matrices SetupMatrices(); // Render the vertex buffer contents g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2 ); // End the scene g_pd3dDevice->EndScene(); } // Present the backbuffer contents to the display g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT ) { UNREFERENCED_PARAMETER( hInst ); // Register the window class WNDCLASSEX wc = { sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, L"D3D Tutorial", NULL }; RegisterClassEx( &wc ); // Create the application's window HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 04: Lights", WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, wc.hInstance, NULL ); // Initialize Direct3D if( SUCCEEDED( InitD3D( hWnd ) ) ) { // Create the geometry if( SUCCEEDED( InitGeometry() ) ) { // Show the window ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); // Enter the message loop MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else Render(); } } } UnregisterClass( L"D3D Tutorial", wc.hInstance ); return 0; }