D3D中的模板缓存(4)

D3D中的模板缓存(4)

该示例演示了如何利用D3D中的模板缓存技术同时显示物体的镜像和阴影。

主程序:

/* *************************************************************************************
  Demonstrates mirrors and shadows with stencils.  
  Use the arrow keys and the 'A' and 'S' key to navigate the scene and translate the teapot. 
 *************************************************************************************
*/

#include 
" d3dUtility.h "

#pragma warning(disable : 
4100 )

class  cTextureVertex
{
public :
    
float  _x, _y, _z;
    
float  _nx, _ny, _nz;
    
float  _u, _v;

    cTextureVertex() { }

    cTextureVertex(
float  x,  float  y,  float  z, 
                   
float  nx,  float  ny,  float  nz,
                   
float  u,  float  v)
    {
        _x  
=  x;  _y   =  y;  _z   =  z;
        _nx 
=  nx; _ny  =  ny; _nz  =  nz;
        _u  
=  u;  _v   =  v;
    }    
};

const  DWORD TEXTURE_VERTEX_FVF  =  D3DFVF_XYZ  |  D3DFVF_NORMAL  |  D3DFVF_TEX1;

const   int  WIDTH   =   640 ;
const   int  HEIGHT  =   480 ;

IDirect3DDevice9
*         g_d3d_device;
IDirect3DVertexBuffer9
*     g_vertex_buffer;

IDirect3DTexture9
*         g_floor_texture;
IDirect3DTexture9
*         g_wall_texture;
IDirect3DTexture9
*         g_mirror_texture;

D3DMATERIAL9    g_floor_material  
=  WHITE_MATERIAL;
D3DMATERIAL9    g_wall_material   
=  WHITE_MATERIAL;
D3DMATERIAL9    g_mirror_material 
=  WHITE_MATERIAL;

ID3DXMesh
*         g_teapot_mesh;
D3DXVECTOR3        g_teapot_pos(
0.0f 3.0f - 7.5f );
D3DMATERIAL9    g_teapot_material 
=  YELLOW_MATERIAL;

void  render_scene();
void  render_mirror();
void  render_shadow();

/////////////////////////////////////////////////////////////////////////////////////////////////// /

bool  setup()
{    
    
//  make walls have low specular reflectance - 20%
    g_wall_material.Specular  =  WHITE  *   0.2f ;

    D3DXCreateTeapot(g_d3d_device, 
& g_teapot_mesh, NULL);

    
//  Create and specify geometry.  For this sample we draw a floor and a wall with a mirror on it.  
    
//  We put the floor, wall, and mirror geometry in one vertex buffer.
    
//
    
//    |----|----|----|
    
//    |Wall|Mirr|Wall|
    
//    |    | or |    |
    
//    /--------------/
    
//   /   Floor      /
    
//  /--------------/

    g_d3d_device
-> CreateVertexBuffer( 24   *   sizeof (cTextureVertex),  0 , TEXTURE_VERTEX_FVF, D3DPOOL_MANAGED,
                                     
& g_vertex_buffer, NULL);

    cTextureVertex
*  v;

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

    
//  floor
    v[ 0 =  cTextureVertex( - 7.5f 0.0f - 10.0f 0.0f 1.0f 0.0f 0.0f 1.0f );
    v[
1 =  cTextureVertex( - 7.5f 0.0f ,    0.0f 0.0f 1.0f 0.0f 0.0f 0.0f );
    v[
2 =  cTextureVertex(  7.5f 0.0f ,    0.0f 0.0f 1.0f 0.0f 1.0f 0.0f );
    
    v[
3 =  cTextureVertex( - 7.5f 0.0f - 10.0f 0.0f 1.0f 0.0f 0.0f 1.0f );
    v[
4 =  cTextureVertex(  7.5f 0.0f ,    0.0f 0.0f 1.0f 0.0f 1.0f 0.0f );
    v[
5 =  cTextureVertex(  7.5f 0.0f - 10.0f 0.0f 1.0f 0.0f 1.0f 1.0f );

    
//  wall
    v[ 6 ]   =  cTextureVertex( - 7.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
7 ]   =  cTextureVertex( - 7.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 0.0f );
    v[
8 ]   =  cTextureVertex( - 2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    
    v[
9 ]   =  cTextureVertex( - 7.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
10 =  cTextureVertex( - 2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    v[
11 =  cTextureVertex( - 2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 1.0f );

    
//  Note: We leave gap in middle of walls for mirror

    v[
12 =  cTextureVertex( 2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
13 =  cTextureVertex( 2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 0.0f );
    v[
14 =  cTextureVertex( 7.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    
    v[
15 =  cTextureVertex( 2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
16 =  cTextureVertex( 7.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    v[
17 =  cTextureVertex( 7.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 1.0f );

    
//  mirror
    v[ 18 =  cTextureVertex( - 2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
19 =  cTextureVertex( - 2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 0.0f );
    v[
20 =  cTextureVertex(  2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    
    v[
21 =  cTextureVertex( - 2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 0.0f 1.0f );
    v[
22 =  cTextureVertex(  2.5f 5.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 0.0f );
    v[
23 =  cTextureVertex(  2.5f 0.0f 0.0f 0.0f 0.0f - 1.0f 1.0f 1.0f );

    g_vertex_buffer
-> Unlock();

    
//  create the texture and set filters

    D3DXCreateTextureFromFile(g_d3d_device, 
" checker.jpg " ,     & g_floor_texture);
    D3DXCreateTextureFromFile(g_d3d_device, 
" brick0.jpg " ,     & g_wall_texture);
    D3DXCreateTextureFromFile(g_d3d_device, 
" ice.bmp " ,         & g_mirror_texture);

    g_d3d_device
-> SetSamplerState( 0 , D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    g_d3d_device
-> SetSamplerState( 0 , D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    g_d3d_device
-> SetSamplerState( 0 , D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

    
//  lights

    D3DXVECTOR3 light_dir(
0.707f - 0.707f 0.707f );
    D3DXCOLOR color(
1.0f 1.0f 1.0f 1.0f );
    D3DLIGHT9 light 
=  init_directional_light( & light_dir,  & color);

    g_d3d_device
-> SetLight( 0 & light);
    g_d3d_device
-> LightEnable( 0 , TRUE);

    g_d3d_device
-> SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_SPECULARENABLE, TRUE);

    
//  set the projection matrix
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
& proj, D3DX_PI / 4.0f , ( float )WIDTH / HEIGHT,  1.0f 1000.0f );
    g_d3d_device
-> SetTransform(D3DTS_PROJECTION,  & proj);
    
    
return   true ;
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

void  cleanup()
{    
    safe_release
< IDirect3DVertexBuffer9 *> (g_vertex_buffer);
    safe_release
< IDirect3DTexture9 *> (g_floor_texture);
    safe_release
< IDirect3DTexture9 *> (g_wall_texture);
    safe_release
< IDirect3DTexture9 *> (g_mirror_texture);
    safe_release
< ID3DXMesh *> (g_teapot_mesh);    
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

bool  display( float  time_delta)
{
    
//  update the scene

    
if (GetAsyncKeyState(VK_LEFT)  &   0x80000f )
        g_teapot_pos.x 
-=   3.0f   *  time_delta;

    
if (GetAsyncKeyState(VK_RIGHT)  &   0x80000f )
        g_teapot_pos.x 
+=   3.0f   *  time_delta;

    
static   float  radius  =   20.0f ;

    
if (GetAsyncKeyState(VK_UP)  &   0x80000f )
        radius 
-=   2.0f   *  time_delta;

    
if (GetAsyncKeyState(VK_DOWN)  &   0x80000f )
        radius 
+=   2.0f   *  time_delta;

    
static   float  angle  =  ( 3.0f   *  D3DX_PI)  /   2.0f ;

    
if (GetAsyncKeyState( ' A ' &   0x80000f )
        angle 
-=   0.5f   *  time_delta;

    
if (GetAsyncKeyState( ' S ' &   0x80000f )
        angle 
+=   0.5f   *  time_delta;

    D3DXVECTOR3 position(cosf(angle) 
*  radius,  3.0f , sinf(angle)  *  radius);
    D3DXVECTOR3 target(
0.0f 0.0f 0.0f );
    D3DXVECTOR3 up(
0.0f 1.0f 0.0f );

    D3DXMATRIX view_matrix;
    D3DXMatrixLookAtLH(
& view_matrix,  & position,  & target,  & up);
    g_d3d_device
-> SetTransform(D3DTS_VIEW,  & view_matrix);

    
//  render now

    g_d3d_device
-> Clear( 0 , NULL, D3DCLEAR_TARGET  |  D3DCLEAR_ZBUFFER  |  D3DCLEAR_STENCIL,  0xff000000 1.0f 0 );

    g_d3d_device
-> BeginScene();

    render_scene();
    render_mirror();
    render_shadow();

    g_d3d_device
-> EndScene();

    g_d3d_device
-> Present(NULL, NULL, NULL, NULL);

    
return   true ;
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

void  render_scene()
{
    
//  draw teapot

    g_d3d_device
-> SetMaterial( & g_teapot_material);
    g_d3d_device
-> SetTexture( 0 , NULL);

    D3DXMATRIX world_matrix;
    D3DXMatrixTranslation(
& world_matrix, g_teapot_pos.x, g_teapot_pos.y, g_teapot_pos.z);
    g_d3d_device
-> SetTransform(D3DTS_WORLD,  & world_matrix);

    g_teapot_mesh
-> DrawSubset( 0 );

    D3DXMATRIX identity_matrix;
    D3DXMatrixIdentity(
& identity_matrix);
    g_d3d_device
-> SetTransform(D3DTS_WORLD,  & identity_matrix);

    g_d3d_device
-> SetStreamSource( 0 , g_vertex_buffer,  0 sizeof (cTextureVertex));
    g_d3d_device
-> SetFVF(TEXTURE_VERTEX_FVF);

    
//  draw the floor
    g_d3d_device -> SetMaterial( & g_floor_material);
    g_d3d_device
-> SetTexture( 0 , g_floor_texture);
    g_d3d_device
-> DrawPrimitive(D3DPT_TRIANGLELIST,  0 2 );

    
//  draw the walls
    g_d3d_device -> SetMaterial( & g_wall_material);
    g_d3d_device
-> SetTexture( 0 , g_wall_texture);
    g_d3d_device
-> DrawPrimitive(D3DPT_TRIANGLELIST,  6 4 );

    
//  draw the mirror
    g_d3d_device -> SetMaterial( & g_mirror_material);
    g_d3d_device
-> SetTexture( 0 , g_mirror_texture);
    g_d3d_device
-> DrawPrimitive(D3DPT_TRIANGLELIST,  18 2 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

void  render_mirror()
{
    
//  Draw Mirror quad to stencil buffer ONLY.  In this way only the stencil bits that 
    
//  correspond to the mirror will be on.  Therefore, the reflected teapot can only be 
    
//  rendered where the stencil bits are turned on, and thus on the mirror only.

    g_d3d_device
-> SetRenderState(D3DRS_STENCILENABLE,        TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILFUNC,            D3DCMP_ALWAYS);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILREF,             0x1 );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILMASK,             0xffffffff );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILWRITEMASK,     0xffffffff );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILZFAIL,        D3DSTENCILOP_KEEP);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILFAIL,            D3DSTENCILOP_KEEP);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILPASS,            D3DSTENCILOP_REPLACE);

    
//  draw the mirror to the stencil buffer

    g_d3d_device
-> SetStreamSource( 0 , g_vertex_buffer,  0 sizeof (cTextureVertex));
    g_d3d_device
-> SetFVF(TEXTURE_VERTEX_FVF);
    g_d3d_device
-> SetMaterial( & g_mirror_material);
    g_d3d_device
-> SetTexture( 0 , g_mirror_texture);

    D3DXMATRIX identity_matrix;
    D3DXMatrixIdentity(
& identity_matrix);
    g_d3d_device
-> SetTransform(D3DTS_WORLD,  & identity_matrix);

    g_d3d_device
-> DrawPrimitive(D3DPT_TRIANGLELIST,  18 2 );
    
    
//  only draw reflected teapot to the pixels where the mirror was drawn to
    g_d3d_device -> SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);

    
//  clear depth buffer and blend the reflected teapot with the mirror
    g_d3d_device -> Clear( 0 , NULL, D3DCLEAR_ZBUFFER,  0 1.0f 0 );
    g_d3d_device
-> SetRenderState(D3DRS_ALPHABLENDENABLE,    TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_SRCBLEND,            D3DBLEND_DESTCOLOR);
    g_d3d_device
-> SetRenderState(D3DRS_DESTBLEND,            D3DBLEND_ZERO);

    
//  position reflection

    D3DXMATRIX world_matrix, translation_matrix, reflect_matrix;

    D3DXPLANE plane(
0.0f 0.0f 1.0f 0.0f );     //  xy plane
    D3DXMatrixReflect( & reflect_matrix,  & plane);

    D3DXMatrixTranslation(
& translation_matrix, g_teapot_pos.x, g_teapot_pos.y, g_teapot_pos.z);

    world_matrix 
=  translation_matrix  *  reflect_matrix;

    
//  Finally, draw the reflected teapot.
    g_d3d_device -> SetTransform(D3DTS_WORLD,  & world_matrix);
    g_d3d_device
-> SetMaterial( & g_teapot_material);
    g_d3d_device
-> SetTexture( 0 , NULL);

    
//  reverse cull mode
    g_d3d_device -> SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);

    g_teapot_mesh
-> DrawSubset( 0 );

    
//  restore render states
    g_d3d_device -> SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILENABLE,     FALSE);
    g_d3d_device
-> SetRenderState(D3DRS_CULLMODE,         D3DCULL_CCW);
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

void  render_shadow()
{    
    g_d3d_device
-> SetRenderState(D3DRS_STENCILENABLE,        TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILFUNC,            D3DCMP_EQUAL);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILREF,             0x0 );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILMASK,             0xffffffff );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILWRITEMASK,     0xffffffff );
    g_d3d_device
-> SetRenderState(D3DRS_STENCILZFAIL,        D3DSTENCILOP_KEEP);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILFAIL,            D3DSTENCILOP_KEEP);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILPASS,            D3DSTENCILOP_INCR);     //  increment to 1

    
//  position shadow
    D3DXVECTOR4 light_dir( 0.707f - 0.707f 0.707f 0.0f );
    D3DXPLANE    ground_plane(
0.0f - 1.0f 0.0f 0.0f );     //  xz plane

    D3DXMATRIX shadow_matrix;
    D3DXMatrixShadow(
& shadow_matrix,  & light_dir,  & ground_plane);

    D3DXMATRIX tran_matrix;
    D3DXMatrixTranslation(
& tran_matrix, g_teapot_pos.x, g_teapot_pos.y, g_teapot_pos.z);

    D3DXMATRIX world_matrix 
=  tran_matrix  *  shadow_matrix;
    g_d3d_device
-> SetTransform(D3DTS_WORLD,  & world_matrix);

    
//  alpha blend the shadow
    g_d3d_device -> SetRenderState(D3DRS_ALPHABLENDENABLE,    TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_SRCBLEND,            D3DBLEND_SRCALPHA);
    g_d3d_device
-> SetRenderState(D3DRS_DESTBLEND,            D3DBLEND_INVSRCALPHA);

    D3DMATERIAL9 material 
=  init_material(BLACK, BLACK, BLACK, BLACK,  0.0f );
    material.Diffuse.a 
=   0.5f ;     //  50% transparancy

    
//  disable depth buffer so that z-fighting doesn't occur when we render the shadow
    
//  on top of the floor.
    g_d3d_device -> SetRenderState(D3DRS_ZENABLE, FALSE);
    
    g_d3d_device
-> SetMaterial( & material);
    g_d3d_device
-> SetTexture( 0 , NULL);

    g_teapot_mesh
-> DrawSubset( 0 );

    
//  restore render states
    g_d3d_device -> SetRenderState(D3DRS_ZENABLE, TRUE);
    g_d3d_device
-> SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    g_d3d_device
-> SetRenderState(D3DRS_STENCILENABLE,     FALSE);    
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
    
switch (msg)
    {
    
case  WM_DESTROY:
        PostQuitMessage(
0 );
        
break ;

    
case  WM_KEYDOWN:
        
if (word_param  ==  VK_ESCAPE)
            DestroyWindow(hwnd);
        
break ;
    }

    
return  DefWindowProc(hwnd, msg, word_param, long_param);
}

////////////////////////////////////////////////////////////////////////////////////////////////////// /

int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line,  int  cmd_show)
{
    
if ( !  init_d3d(inst, WIDTH, HEIGHT,  true , D3DDEVTYPE_HAL,  & g_d3d_device))
    {
        MessageBox(NULL, 
" init_d3d() - failed. " 0 , MB_OK);
        
return   0 ;
    }

    
if ( !  setup())
    {
        MessageBox(NULL, 
" Steup() - failed. " 0 , MB_OK);
        
return   0 ;
    }

    enter_msg_loop(display);

    cleanup();
    g_d3d_device
-> Release();

    
return   0 ;
}

运行截图:

D3D中的模板缓存(4)_第1张图片

下载源程序


你可能感兴趣的:(D3D中的模板缓存(4))