//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: stencilmirror.cpp
//
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0
//
// Desc: Demonstrates mirrors with stencils. Use the arrow keys
// and the 'A' and 'S' key to navigate the scene and translate the teapot.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "d3dUtility.h"
//
// Globals
//
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
IDirect3DVertexBuffer9* VB = 0;
//纹理
IDirect3DTexture9* FloorTex = 0; // 地面纹理
IDirect3DTexture9* WallTex = 0; // 墙面纹理
IDirect3DTexture9* MirrorTex = 0; // 镜子纹理
//材质
D3DMATERIAL9 FloorMtrl = d3d::WHITE_MTRL; // 地面材质
D3DMATERIAL9 WallMtrl = d3d::WHITE_MTRL; // 墙面材质
D3DMATERIAL9 MirrorMtrl = d3d::WHITE_MTRL; // 镜面材质
D3DMATERIAL9 TeapotMtrl = d3d::RED_MTRL; // 茶壶材质
ID3DXMesh* Teapot = 0; // 茶壶模型
D3DXVECTOR3 TeapotPosition(0.0f, 3.0f, -7.5f); // 茶壶位置
D3DXMATRIX mTotal; // 最终矩阵
//场景渲染函数
void RenderScene(float timeDelta);
//镜子渲染函数
void RenderMirror();
struct Vertex
{
Vertex(){}
Vertex(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;
}
float _x, _y, _z;
float _nx, _ny, _nz;
float _u, _v;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
// 初始化函数
bool Setup()
{
//镜面反光率为20%,(这个值越大,材质就越亮)
WallMtrl.Specular = d3d::WHITE * 0.2f;
//创建茶壶
D3DXCreateTeapot(Device, &Teapot, 0);
//
// 创建并且指定顶点. 在这个例子中,我们创建一个地面、墙和墙上的镜子。
// 我们把地面、墙、镜子的顶点放在一个缓存中
//
// |----|----|----|
// |Wall|Mirr|Wall|
// | | or | |
// /--------------/
// / Floor /
// /--------------/
//
Device->CreateVertexBuffer(
24 * sizeof(Vertex),
0, // usage
Vertex::FVF,
D3DPOOL_MANAGED,
&VB,
0);
Vertex* v = 0;
VB->Lock(0, 0, (void**)&v, 0);
// floor
v[0] = Vertex(-7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[1] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
v[2] = Vertex( 7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[3] = Vertex(-7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[4] = Vertex( 7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[5] = Vertex( 7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
// left wall
v[6] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[7] = Vertex(-7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[8] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[9] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[10] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[11] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
// right wall
v[12] = Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[13] = Vertex(2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[14] = Vertex(7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[15] = Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[16] = Vertex(7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[17] = Vertex(7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
// mirror
v[18] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[19] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[20] = Vertex( 2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[21] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[22] = Vertex( 2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[23] = Vertex( 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
VB->Unlock();
// 装载纹理(地面、墙面、镜子)
D3DXCreateTextureFromFile(Device, "checker.jpg", &FloorTex);
D3DXCreateTextureFromFile(Device, "brick0.jpg", &WallTex);
D3DXCreateTextureFromFile(Device, "checker.jpg", &MirrorTex);
//过滤器
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); //放大时的过滤效果
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); //缩小时的过滤效果
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// 设置光
D3DXVECTOR3 lightDir(0.707f, -0.707f, 0.707f); // 光的方向
D3DXCOLOR color(1.0f, 1.0f, 1.0f, 1.0f); // 光的颜色
D3DLIGHT9 light = d3d::InitDirectionalLight(&lightDir, &color); // 初始化光
Device->SetLight(0, &light); // 设置索引为0的一个光源
Device->LightEnable(0, true); // 启动索引为0的光源
//在顶点变换时,顶点的法线会变成非标准化的,这个操作将标准化所有顶点法线
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
//默认光的状态不考虑镜面高光,要使用镜面光,将D3DRS_SPECULARENABLE设为true(可以感觉到光在不同位置的反射)
Device->SetRenderState(D3DRS_SPECULARENABLE, true);
// 进行视图变换(设置摄像机)
D3DXVECTOR3 pos(-10.0f, 3.0f, -15.0f);
D3DXVECTOR3 target(0.0, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &pos, &target, &up);
Device->SetTransform(D3DTS_VIEW, &V);
// 设置投影矩阵(将3D空间转换成2D空间)
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI / 4.0f, // 90 degree
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
bool Display(float timeDelta)
{
if( Device )
{
//移动茶壶的处理
static float radius = 20.0f;
if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )
TeapotPosition.x -= 3.0f * timeDelta;
if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )
TeapotPosition.x += 3.0f * timeDelta;
if( ::GetAsyncKeyState(VK_UP) & 0x8000f )
TeapotPosition.z += 3.0f * timeDelta;
if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )
TeapotPosition.z -= 3.0f * timeDelta;
//移动摄像机的处理
static float angle = (3.0f * D3DX_PI) / 2.0f;
if( ::GetAsyncKeyState('W') & 0x8000f )
radius -= 4.0f * timeDelta;
if( ::GetAsyncKeyState('S') & 0x8000f )
radius += 4.0f * timeDelta;
if( ::GetAsyncKeyState('A') & 0x8000f )
angle -= 0.5f * timeDelta;
if( ::GetAsyncKeyState('D') & 0x8000f )
angle += 0.5f * timeDelta;
//设置摄像机,进行视图变换
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 V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
Device->SetTransform(D3DTS_VIEW, &V);
// 画场景
Device->Clear(0, 0,
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
D3DCOLOR_XRGB(100, 100, 100), 1.0f, 0);
Device->BeginScene();
RenderScene( timeDelta ); // 渲染场景
RenderMirror(); // 渲染镜子中的场景(只有茶壶在镜子中)
Device->EndScene();
// 后备表面的交换
Device->Present(0, 0, 0, 0);
}
return true;
}
void RenderScene(float timeDelta)
{
// 进行世界变换 -------------------------------------------------------------
D3DXMATRIX mRotY, mTran;
static float y = 0.0f;
y += timeDelta;
if( y >= 6.28f )
y = 0.0f;
D3DXMatrixRotationY(&mRotY, y); // 先旋转
D3DXMatrixTranslation(&mTran, // 后平移
TeapotPosition.x,
TeapotPosition.y,
TeapotPosition.z);
mTotal = mRotY * mTran; // 最终矩阵 = 旋转矩阵 * 平移矩阵
// 渲染茶壶
Device->SetMaterial( &TeapotMtrl ); // 设置材质
Device->SetTexture(0, 0); // 设置纹理
Device->SetTransform(D3DTS_WORLD, &mTotal); // 设置变换
Teapot->DrawSubset(0); // 绘制茶壶
// --------------------------------------------------------------------------
//标准化世界矩阵
D3DXM