光照与材质(5)

光照与材质(5)

多光源光照示例程序

在示例程序MultiLights中一共使用了三个光源,分别是漫反射方向光光源、漫反射点光源、镜面反射方向光光源,而且可以控制分别使用三个光源和同时使用三个光源的显示效果。为了测试不同光源的光照效果,在示例程序中通过键盘上的数字键来控制3个光源的启用。

 

按下数字键1,开启1号光源,关闭2号和3号光源,从而可以观察方向光漫反射效果。

光照与材质(5)_第1张图片

 


按下数字键2,开启2号光源,关闭1号和3号光源,从而可以观察点光源漫反射效果。

光照与材质(5)_第2张图片

 


按下数字键3,开启3号光源,关闭1号和1号光源,从而可以观察方向光镜面反射效果。

光照与材质(5)_第3张图片


 

按下数字键4,同时开启3个光源,可以观察同时使用多个光源的效果。

光照与材质(5)_第4张图片


按下数字键0,返回默认状态,只启用环境光,关闭所有光源。

光照与材质(5)_第5张图片


按下数字键5,启用FLAT着色模式。

光照与材质(5)_第6张图片


按下数字键6,启用GOURAUD着色模式(默认着色模式)。
 

源程序:

#include  < d3dx9.h >

#pragma warning(disable : 
4127 )

#define  CLASS_NAME    "GameApp"

#define  release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

IDirect3D9
*                 g_d3d;
IDirect3DDevice9
*         g_device;
IDirect3DVertexBuffer9
*  g_vertex_buffer;

struct  sCustomVertex
{
    D3DXVECTOR3    position;
    D3DXVECTOR3    normal;
};

#define  D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL) 

void  init_geometry()
{    
    g_device
-> CreateVertexBuffer( 50   *   2   *   sizeof (sCustomVertex),  0 , D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, 
                                 
& g_vertex_buffer, NULL);

    sCustomVertex
*  vertices;

    g_vertex_buffer
-> Lock( 0 0 , ( void ** ) & vertices,  0 );

    
for ( int  i  =   0 ; i  <   50 ; i ++ )
    {
        
float  theta  =  ( 2   *  D3DX_PI  *  i)  /  ( 50   -   1 );

        vertices[
2   *  i  +   0 ].position  =  D3DXVECTOR3(sin(theta),  - 1.0f , cos(theta));
        vertices[
2   *  i  +   0 ].normal    =  D3DXVECTOR3(sin(theta),   0.0f , cos(theta));
        vertices[
2   *  i  +   1 ].position  =  D3DXVECTOR3(sin(theta),   1.0f , cos(theta));
        vertices[
2   *  i  +   1 ].normal    =  D3DXVECTOR3(sin(theta),   0.0f , cos(theta));
    }
    
    g_vertex_buffer
-> Unlock();
}

void  setup_matrices()
{
    
//  build world matrix
    
    D3DXMATRIX mat_world;
    D3DXMatrixIdentity(
& mat_world);
    g_device
-> SetTransform(D3DTS_WORLD,  & mat_world);

    
//  setup view matrix

    D3DXVECTOR3 eye(
0.0f 3.0f - 5.0f );
    D3DXVECTOR3 at(
0.0f 0.0f 0.0f );
    D3DXVECTOR3 up(
0.0f 1.0f 0.0f );

    D3DXMATRIX mat_view;
    D3DXMatrixLookAtLH(
& mat_view,  & eye,  & at,  & up);
    g_device
-> SetTransform(D3DTS_VIEW,  & mat_view);

    
//  setup projection matrix

    D3DXMATRIX mat_proj;
    D3DXMatrixPerspectiveFovLH(
& mat_proj, D3DX_PI / 4 1.33f 1.0f 100.0f );
    g_device
-> SetTransform(D3DTS_PROJECTION,  & mat_proj);
}

bool  init_d3d(HWND hwnd)
{
    g_d3d 
=  Direct3DCreate9(D3D_SDK_VERSION);

    
if (g_d3d  ==  NULL)
        
return   false ;

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(
& d3dpp,  sizeof (d3dpp));

    d3dpp.Windowed                    
=  TRUE;
    d3dpp.SwapEffect                
=  D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat            
=  D3DFMT_UNKNOWN;
    d3dpp.EnableAutoDepthStencil    
=  TRUE;             //  Direct3D will manage depth buffers for the application
    d3dpp.AutoDepthStencilFormat     =  D3DFMT_D16;     //  16-bit z-buffer bit depth

    
if (FAILED(g_d3d -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                  
& d3dpp,  & g_device)))
    {
        
return   false ;
    }
    
    init_geometry();
    setup_matrices();

    g_device
-> SetRenderState(D3DRS_ZENABLE,            TRUE);
    g_device
-> SetRenderState(D3DRS_SPECULARENABLE,  TRUE);    
    g_device
-> SetRenderState(D3DRS_CULLMODE,        D3DCULL_NONE);        
    
    
return   true ;
}

void  cleanup()
{
    release_com(g_vertex_buffer);
    release_com(g_device);
    release_com(g_d3d);
}

void  setup_material_light()
{
    
//  setup material

    D3DMATERIAL9 material;
    ZeroMemory(
& material,  sizeof (material));

    material.Diffuse.r 
=  material.Ambient.r  =  material.Specular.r  =   0.3f ;
    material.Diffuse.g 
=  material.Ambient.g  =  material.Specular.g  =   1.0f ;
    material.Diffuse.b 
=  material.Ambient.b  =  material.Specular.b  =   1.0f ;
    material.Diffuse.a 
=  material.Ambient.a  =  material.Specular.a  =   1.0f ;

    g_device
-> SetMaterial( & material);

    
//  setup light1

    D3DLIGHT9 light1;
    ZeroMemory(
& light1,  sizeof (light1));

    light1.Type        
=  D3DLIGHT_DIRECTIONAL;
    light1.Diffuse.r 
=   1.0f ;
    light1.Diffuse.g 
=   0.8f ;
    light1.Diffuse.b 
=   1.0f ;    
    light1.Direction 
=  D3DXVECTOR3( - 10 0 10 );
    
    g_device
-> SetLight( 0 & light1);
    
    
//  setup light2

    D3DLIGHT9 light2;
    ZeroMemory(
& light2,  sizeof (light2));

    light2.Type         
=  D3DLIGHT_POINT;
    light2.Diffuse.r 
=   1.0f ;
    light2.Diffuse.g 
=   1.0f ;
    light2.Diffuse.b 
=   0.0f ;

    
float  time  =  timeGetTime()  /   350.0f ;
    light2.Position 
=  D3DXVECTOR3( 10   *  sin(time),  0 10   *  cos(time));

    light2.Range        
=   100.0f ;
    light2.Attenuation0 
=   1.0f ;

    g_device
-> SetLight( 1 & light2);

    
//  setup light3

    D3DLIGHT9 light3;
    ZeroMemory(
& light3,  sizeof (light3));

    light3.Type          
=  D3DLIGHT_DIRECTIONAL;
    light3.Specular.r 
=   1.0f ;
    light3.Specular.g 
=   0.5f ;
    light3.Specular.b 
=   0.5f ;
    light3.Specular.a 
=   1.0f ;

    light3.Direction 
=  D3DXVECTOR3( - 10 0 10 );

    g_device
-> SetLight( 2 & light3);

    g_device
-> SetRenderState(D3DRS_AMBIENT,  0x00777777 );    
}

void  render()
{
    g_device
-> Clear( 0 , NULL, D3DCLEAR_TARGET  |  D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 5 5 5 ),  1.0f 0 );

    g_device
-> BeginScene();

    setup_material_light();

    g_device
-> SetStreamSource( 0 , g_vertex_buffer,  0 sizeof (sCustomVertex));
    g_device
-> SetFVF(D3DFVF_CUSTOM_VERTEX);
    g_device
-> DrawPrimitive(D3DPT_TRIANGLESTRIP,  0 2   *   50   -   2 );

    g_device
-> EndScene();

    g_device
-> Present(NULL, NULL, NULL, NULL);
}

LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    
switch (msg)
    {
    
case  WM_KEYDOWN:
        
switch (wParam)
        {
        
case  VK_ESCAPE:
            DestroyWindow(hwnd);
            
return   0 ;

        
case   48 :     //  key "0", disalbe all lights, only use ambient light.
            g_device -> LightEnable( 0 , FALSE);
            g_device
-> LightEnable( 1 , FALSE);
            g_device
-> LightEnable( 2 , FALSE);
            
break ;

        
case   49 :     //  key "1", enable lights 1, disable other lights.
            g_device -> LightEnable( 0 , TRUE);
            g_device
-> LightEnable( 1 , FALSE);
            g_device
-> LightEnable( 2 , FALSE);
            
break ;

        
case   50 :     //  key "2", enable lights 2, disable other lights.
            g_device -> LightEnable( 0 , FALSE);
            g_device
-> LightEnable( 1 , TRUE);
            g_device
-> LightEnable( 2 , FALSE);
            
break ;
    
        
case   51 :     //  key "3", enable lights 3, disable other lights.
            g_device -> LightEnable( 0 , FALSE);
            g_device
-> LightEnable( 1 , FALSE);
            g_device
-> LightEnable( 2 , TRUE);
            
break ;

        
case   52 :     //  key "4", enable all lights.
            g_device -> LightEnable( 0 , TRUE);
            g_device
-> LightEnable( 1 , TRUE);
            g_device
-> LightEnable( 2 , TRUE);
            
break ;

        
case   53 :     //  key "5", flat shade mode.
            g_device -> SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
            
break ;

        
case   54 :     //  key "6", gouraud shade mode.
            g_device -> SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
            
break ;
        }
            
        
break ;

    
case  WM_DESTROY:        
        PostQuitMessage(
0 );
        
return   0 ;
    }

    
return  DefWindowProc(hwnd, msg, wParam, lParam);
}

int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
    WNDCLASSEX wc;

    wc.cbSize            
=   sizeof (WNDCLASSEX);
    wc.style            
=  CS_CLASSDC;
    wc.lpfnWndProc        
=  WinProc;
    wc.cbClsExtra        
=   0 ;
    wc.cbWndExtra        
=   0 ;
    wc.hInstance        
=  inst;
    wc.hIcon            
=  NULL;
    wc.hCursor            
=  NULL;
    wc.hbrBackground    
=  NULL;
    wc.lpszMenuName        
=  NULL;
    wc.lpszClassName    
=  CLASS_NAME;
    wc.hIconSm            
=  NULL;

    
if ( !  RegisterClassEx( & wc))
        
return   - 1 ;

    HWND hwnd 
=  CreateWindow(CLASS_NAME,  " Direct3D App " , WS_OVERLAPPEDWINDOW,  200 100 640 480 ,
                             NULL, NULL, wc.hInstance, NULL);    

    
if (hwnd  ==  NULL)
        
return   - 1 ;

    
if (init_d3d(hwnd))
    {
        ShowWindow(hwnd, SW_SHOWDEFAULT);
        UpdateWindow(hwnd);

        MSG msg;
        ZeroMemory(
& msg,  sizeof (msg));

        
while (msg.message  !=  WM_QUIT)
        {
            
if (PeekMessage( & msg, NULL,  0 0 , PM_REMOVE))
            {
                TranslateMessage(
& msg);
                DispatchMessage(
& msg);
            }
                
            render();
        }
    }

    cleanup();
    UnregisterClass(CLASS_NAME, wc.hInstance);    

    
return   0 ;
}

场景中的环境光有两个来源:一是通过渲染状态设置的全局环境光,二是通过每个光源中的环境光属性设置的环境光。建议通过渲染状态设置一个整体上的环境光,对于场景中的各个光源不设置其环境光属性,因为在同一个场景中,对于每个物体其接受到的环境光应当相同,所以通过渲染状态设置一个整体上的环境光比较方便,也符合实际情况。

在Direct3D中,光源和材质是互不分离、相互作用的两部分,光源是相对于整个场景的,而材质是相对于每个物体的。两者相互作用,共同决定最终的渲染结果,这样虽然灵活但不易控制,所以光源和物体表面材质的设置应尽量符合现实情况。例如,可将光源设为白光,将各个物体材质颜色设为真实颜色,当然为了得到特殊的效果,可以在某些方面进行夸张。


你可能感兴趣的:(光照与材质(5))