# 天行健 君子当自强而不息

## 8.3实例程序：平面阴影

### 8.3.1平行光阴影

An intersection point s is easily found with a ray/plane intersection test:

### 8.3.3阴影矩阵

１．假如w＝０，那么L表示平行光的照射方向。

２．假如w＝1 ，那么L表示点光源的位置。

D3DX库中已经给我们提供了一个建立阴影矩阵的函数。其中当w＝０时表示平行光，当w＝１时表示点光源：

Builds a matrix that flattens geometry into a plane.

`D3DXMATRIX * D3DXMatrixShadow(  D3DXMATRIX * pOut,  CONST D3DXVECTOR4 * pLight,  CONST D3DXPLANE * pPlane);`

#### Parameters

pOut
[in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
pLight
[in] Pointer to a D3DXVECTOR4 structure describing the light's position.
pPlane
[in] Pointer to the source D3DXPLANE structure.

#### Return Values

Pointer to a D3DXMATRIX structure that flattens geometry into a plane.

#### Remarks

The D3DXMatrixShadow function flattens geometry into a plane, as if casting a shadow from a light.

The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixShadow function can be used as a parameter for another function.

This function uses the following formula to compute the returned matrix.

`P = normalize(Plane);L = Light;d = dot(P, L)    P.a * L.x + d  P.a * L.y      P.a * L.z      P.a * L.w  P.b * L.x      P.b * L.y + d  P.b * L.z      P.b * L.w  P.c * L.x      P.c * L.y      P.c * L.z + d  P.c * L.w  P.d * L.x      P.d * L.y      P.d * L.z      P.d * L.w + d`

If the light's w-component is 0, the ray from the origin to the light represents a directional light. If it is 1, the light is a point light.

### 8.3.5代码和解释

 void RenderShadow() {        Device->SetRenderState(D3DRS_STENCILENABLE, true);        Device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);        Device->SetRenderState(D3DRS_STENCILREF, 0x0);        Device->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);        Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);        Device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);        Device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); Device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);

 // compute the transformation to flatten the teapot into a shadow.        D3DXVECTOR4 lightDirection(0.707f, -0.707f, 0.707f, 0.0f);        D3DXPLANE groundPlane(0.0f, -1.0f, 0.0f, 0.0f);        D3DXMATRIX S;        D3DXMatrixShadow(&S, &lightDirection, &groundPlane);        D3DXMATRIX T;        D3DXMatrixTranslation(&T, TeapotPosition.x, TeapotPosition.y, TeapotPosition.z);        D3DXMATRIX W = T * S; Device->SetTransform(D3DTS_WORLD, &W);

 Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);        Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);        Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);        D3DMATERIAL9 mtrl = d3d::InitMtrl(d3d::BLACK, d3d::BLACK,        d3d::BLACK, d3d::BLACK, 0.0f);        mtrl.Diffuse.a = 0.5f; // 50% transparency.        // Disable depth buffer so that z-fighting doesn't occur when we        // render the shadow on top of the floor.        Device->SetRenderState(D3DRS_ZENABLE, false);        Device->SetMaterial(&mtrl);        Device->SetTexture(0, 0);        Teapot->DrawSubset(0);        Device->SetRenderState(D3DRS_ZENABLE, true);        Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);        Device->SetRenderState(D3DRS_STENCILENABLE, false); }//end RenderShadow()

/**************************************************************************************
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.0f3.0f-7.5f);
D3DMATERIAL9    g_teapot_material
= YELLOW_MATERIAL;

void render_scene();

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

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(00, (void**)&v, 0);

// floor
v[0= cTextureVertex(-7.5f0.0f-10.0f0.0f1.0f0.0f0.0f1.0f);
v[
1= cTextureVertex(-7.5f0.0f,   0.0f0.0f1.0f0.0f0.0f0.0f);
v[
2= cTextureVertex( 7.5f0.0f,   0.0f0.0f1.0f0.0f1.0f0.0f);

v[
3= cTextureVertex(-7.5f0.0f-10.0f0.0f1.0f0.0f0.0f1.0f);
v[
4= cTextureVertex( 7.5f0.0f,   0.0f0.0f1.0f0.0f1.0f0.0f);
v[
5= cTextureVertex( 7.5f0.0f-10.0f0.0f1.0f0.0f1.0f1.0f);

// wall
v[6]  = cTextureVertex(-7.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
7]  = cTextureVertex(-7.5f5.0f0.0f0.0f0.0f-1.0f0.0f0.0f);
v[
8]  = cTextureVertex(-2.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);

v[
9]  = cTextureVertex(-7.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
10= cTextureVertex(-2.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);
v[
11= cTextureVertex(-2.5f0.0f0.0f0.0f0.0f-1.0f1.0f1.0f);

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

v[
12= cTextureVertex(2.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
13= cTextureVertex(2.5f5.0f0.0f0.0f0.0f-1.0f0.0f0.0f);
v[
14= cTextureVertex(7.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);

v[
15= cTextureVertex(2.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
16= cTextureVertex(7.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);
v[
17= cTextureVertex(7.5f0.0f0.0f0.0f0.0f-1.0f1.0f1.0f);

// mirror
v[18= cTextureVertex(-2.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
19= cTextureVertex(-2.5f5.0f0.0f0.0f0.0f-1.0f0.0f0.0f);
v[
20= cTextureVertex( 2.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);

v[
21= cTextureVertex(-2.5f0.0f0.0f0.0f0.0f-1.0f0.0f1.0f);
v[
22= cTextureVertex( 2.5f5.0f0.0f0.0f0.0f-1.0f1.0f0.0f);
v[
23= cTextureVertex( 2.5f0.0f0.0f0.0f0.0f-1.0f1.0f1.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_POINT);

// lights

D3DXVECTOR3 light_dir(
0.707f-0.707f0.707f);
D3DXCOLOR color(
1.0f1.0f1.0f1.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.0f1000.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;

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

if(GetAsyncKeyState(VK_DOWN) & 0x80000f)
+= 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)
D3DXVECTOR3 target(
0.0f0.0f0.0f);
D3DXVECTOR3 up(
0.0f1.0f0.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, 0xff0000001.0f0);

g_d3d_device
->BeginScene();
render_scene();
g_d3d_device
->EndScene();

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

return true;
}

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

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

g_d3d_device
->SetStreamSource(0, g_vertex_buffer, 0sizeof(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, 02);

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

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

// 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);
}

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

{
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
g_d3d_device
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

D3DXVECTOR4 light_dir(0.707f-0.707f0.707f0.0f);
D3DXPLANE    ground_plane(
0.0f-1.0f0.0f0.0f);    // xz plane

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

D3DXMATRIX world_matrix
g_d3d_device
->SetTransform(D3DTS_WORLD, &world_matrix);

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;
}

posted on 2008-03-25 10:37 lovedday 阅读(1758) 评论(0)  编辑 收藏 引用

 只有注册用户登录后才能发表评论。

• 随笔 - 1360
• 文章 - 75
• 评论 - 520
• 引用 - 0

•