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 ;
}
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 ;
}
运行截图:
下载源程序