D3D模板测试
模版缓存是一个远离屏幕的缓存,我们能够用它来完成一些特效。模版缓存与后缓存和深度缓存有相同的定义,因此在模版缓存中的[i][j]像素与后缓存和深度缓存中的[i][j]像素是相协调的。就象名字所说,模版缓存就象一个模版它允许我们印刷渲染后缓存的某个部分。
1.使用模板缓存
1.1启用模版缓存
Device->SetRenderState(D3DRS_STENCILENABLE,true);
我们可以使用IDirect3DDevice9::Clear方法来清除模版缓存并让其拥有默认值,也用在1.2清除后缓存和深度缓存中
Device->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,0xffffffff,1.0f,0);
表示把模版缓存和目标(后缓存)以及深度缓存一起清除。
2.创建模板缓存
在我们创建深度缓存的同时一个模版缓存能够被创建。当指定深度缓存格式的时候,我们同时指定模版缓存的格式。这样,模版缓存和深度缓存分享同一个离屏表面缓存,但是每个像素被指定到各自缓存内存片段中。
下面列出了3种深度/模版缓存的格式:
D3DFMT_D24S8—一个32位深度/模版缓存,其中24位为深度缓存,8位为模版缓存。
D3DFMT_D24X4S4—一个32位深度/模版缓存,其中24位为深度缓存,位为模版缓存,还有4位留着不用。
D3DFMT_D15S1—一个16位深度/模版缓存,其中15位为深度缓存,1位为模版缓存。
3.模板测试(stencil test)
能够使用模版缓存来阻止渲染后缓存中的某些部分,阻止特殊像素被写是通过模版测试(stencil test)来决定的,这是通过下面的表达式来完成的:
(ref & mask) ComparisonOperation (value & mask)
模版测试是对每个像素进行的,假设模版是被允许。将有两个操作:
左手边操作数(LHS=ref&mask) 右手边操作数(RHS=value&mask)
模版测试比较LHS和RHS,通过比较运算来指定。全部的运算都得到一个布尔值(true/false)。假如结果是true,那么我们把像素写入后缓存。反之,就阻止像素被写入后缓存。如果像素不能被写入后缓存,那么它也不能被写入深度缓存。
控制模版测试
指定参考值(stencil reference)和掩码(mask value),以便进行比较运算。虽然不能明确地设定模版值(stencil value),但是能够控制写入模版缓存的值。
模版参考值(Reference Value)
模版参考值ref的默认值为0,通过设置D3DRS_STENCILREF渲染状态来改变:
Device->SetRenderState(D3DRS_STENCILREF,0x1);
值常用16位表示
模版掩码(stencil mask)
模版掩码值mask是被用来掩饰(隐藏)在ref和value变量中的位。它的默认值是0xffffffff,也就是没有掩饰任何位,通过设置D3DRS_STENCILMASK渲染状态来改变,例掩饰高16位:
Device->SetRenderState(D3DRS_STENCILMASK,0x0000ffff);
模版值(Stencil Value)
在模版缓存中我们进行模版测试的当前像素。对像素进行模版测试,那么该值将被写入该模版缓存。不能明确地设置个别模版值,但是可以清除模版缓存。能够使用模版渲染状态来控制将什么写入模版缓存。
比较运算
通过设置D3DRS_STENCILFUNC渲染状态来设置比较运算。这个比较运算能够被
D3DCMPFUNC的任何成员类型列举:
typedef enum D3DCMPFUNC {
D3DCMP_NEVER = 1,//Always fail the test.
D3DCMP_LESS = 2,//假如LHS < RHS,那么模版测试成功
D3DCMP_EQUAL = 3,//假如LHS = RHS,那么模版测试成功
D3DCMP_LESSEQUAL = 4,//假如LHS <= RHS,那么模版测试成功
D3DCMP_GREATER = 5,//假如LHS > RHS,那么模版测试成功
D3DCMP_NOTEQUAL = 6,//假如LHS <> RHS,那么模版测试成功
D3DCMP_GREATEREQUAL = 7,//假如LHS >= RHS,那么模版测试成功
D3DCMP_ALWAYS = 8,//always pass the test
D3DCMP_FORCE_DWORD = 0x7fffffff
} D3DCMPFUNC, *LPD3DCMPFUNC;
更新模板缓存
除了决定是否写或阻止一个特殊像素被写入后缓存以外,我们能够定义模版缓存基于三种可能的案例怎样被更新:
对于[i][j]处像素模版测试失败:
Device->SetRenderState(D3DRS_STENCILFAIL, StencilOperation);
对于[i][j]处像素深度测试失败:
Device->SetRenderState(D3DRS_STENCILZFAIL, StencilOperation);
对于[i][j]处像素模版测试和深度测试都成功:
Device->SetRenderState(D3DRS_STENCILPASS, StencilOperation);
StencilOperation是以下常数
typedef enum D3DSTENCILOP {
D3DSTENCILOP_KEEP = 1,//不改变模版缓存
D3DSTENCILOP_ZERO = 2,//设置模版缓存入口为。
D3DSTENCILOP_REPLACE = 3,//指定用模版参考值来替换模版缓存入口
D3DSTENCILOP_INCRSAT = 4,//指定增加模版缓存入口。假如增加的值超过了允许的最大值,我们就设置它为最大值。
D3DSTENCILOP_DECRSAT = 5,//指定减少模版缓存入口。假如减少后的值小于了,我们就设置它。
D3DSTENCILOP_INVERT = 6,//指定按位取反模版缓存入口。
D3DSTENCILOP_INCR = 7,//指定增加模版缓存入口。假如增加的值超过了允许的最大值,我们就设置它为0。
D3DSTENCILOP_DECR = 8,//指定减少模版缓存入口。假如减少后的值小于0,我们就设置它为允许的最大值。
D3DSTENCILOP_FORCE_DWORD = 0x7fffffff
} D3DSTENCILOP, *LPD3DSTENCILOP;
模版写掩码
除了已经提及的模版渲染状态之外,我们能够设置一个写掩码(write mask)它将掩饰我们写进模版缓存的任何值的位。我们能够通过D3DRS_STENCILWRITEMASK渲染状态来设置写掩码。它的默认值是0xffffffff。下面的例子是掩饰高16位:
Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0x0000ffff);
反射矩阵:
D3DXMATRIX * D3DXMatrixReflect(
__inout D3DXMATRIX *pOut,//输出反射矩阵
__in const D3DXPLANE *pPlane//反射平面
);
3种特殊的反射变换:
关于三个坐标平面的反射—yz平面,xz平面,和xy平面—分别通过下面三个矩阵来表现:

阴影矩阵
影子本质上是把物体按照灯光照射方向平行地投射到平面n*p+d=0
之上。同样的,图8.7中所示的点光源,影子本质上是把物体按照透视画法从光源投射到平面n*p+d=0之上。
我们能够使用一个矩阵来表示从一个顶点p变换到平面n*p=d=0上的s的变化。而且,我们能够用同一个矩阵来表现正交投影和透视投影。
我们用一个4D向量(nx, ny, nz, d)来表示将要用于投射阴影平面的平面等式中的各个系数。让4D向量L=(Lx, Ly, Lz, Lw)来表示平行光的照射方向或点光源的位置。我们用w来区别:
1.假如w=0,那么L表示平行光的照射方向。
2.假如w=1 ,那么L表示点光源的位置
让k=(nx, ny, nz, d) * (Lx, Ly, Lz, Lw) = nxLx+nyLy+nzLz+dLw
那么我们就可得到表示点p到点s的变换矩阵,即阴影矩阵:
在D3DX库中已经给我们提供了一个建立阴影矩阵的函数。其中当w=0时表示平行光,当
w=1时表示点光源:
D3DXMATRIX * D3DXMatrixShadow(
__inout D3DXMATRIX *pOut,
__in const D3DXVECTOR4 *pLight,
__in const D3DXPLANE *pPlane
);
防止双倍渲染
几何学上,当我们将一个物体投影到一个平面上时,很可能会有两个或者更多的投影三角形被重叠到一起。若我们就这样渲染,那么有重叠三角形的地方就会被多次混合以至这些地方将会变得更黑。 我们设置模版测试为允许像素第一次被渲染。即,当把影子像素渲染到后缓存时,我们同时在模版缓存中做好标记。然后,如果试图把像素向一个已经渲染过的地方写,那么模版测试将会失败。
我们能够通过下面的混合等式来混合被反射的茶壶和镜子:
例子:
- #include "d3dUtility.h"
- //
- // Globals
- //
- IDirect3DDevice9* Device = 0;
- const int Width=640,Height=480;
- IDirect3DTexture9 * WallTex;
- IDirect3DTexture9 * MirrorTex;
- IDirect3DTexture9 * FloorTex;
- IDirect3DVertexBuffer9 * VB;
- D3DMATERIAL9 FloorMtrl= d3d::WHITE_MTRL;
- D3DMATERIAL9 WallMtrl = d3d::WHITE_MTRL;
- D3DMATERIAL9 MirrorMtrl= d3d::WHITE_MTRL;
- ID3DXMesh * Teapot = 0;
- D3DXVECTOR3 TeapotPosition(0.0f,3.0f,-6.0f);
- D3DMATERIAL9 TeapotMtrl = d3d::BLUE_MTRL;
- void RenderSceen();
- void RenderMirror();
- void RenderShdow();
- // Classes and Structures
- 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; // texture coordinates
- static const DWORD FVF;
- };
- void RenderShdow()
- {
- //启用模板缓存
- Device->SetRenderState(D3DRS_STENCILENABLE, true);
- //设置比较运算,假设LHS==RHS 模板测试成功(ref & mask) ComparisonOperation (value & mask)
- Device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
- //设置模板参考值设置为,因此假如在模版缓存中相应的值为x0,才会渲染到后缓存中
- //因为因为模版缓存是被清除为x0的,所以第一次将影子像素写入的时候总是正确的
- Device->SetRenderState(D3DRS_STENCILREF, 0x0);
- //设置模板测试比较时的掩码,设置为xffffffff,因为是&运算,设为全,就是不掩饰任何位
- Device->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
- //设置对模板缓存写入时掩码,设置为xffffffff,就是不掩饰任何位
- Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);
- //假设深度测试失败,就保持原状
- Device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
- //假设模板测试失败,就保持原状
- Device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
- //如果像素模版测试和深度测试都成功,就增加模版缓存入口
- //第一次将像素写入测试必然都成功,所以模板缓存入口就会增加到,再次写入时
- //因为模板缓存的值是,所以测试就会失败,失败保持原状,因此防止双倍混合
- Device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
- //设置灯光
- //这里是灯光的方向
- D3DXVECTOR4 lightDirection(0.0f,-1.0f,0.0f,0.0f);
- //设置地板平面
- D3DXPLANE groundPlane(0.0f,-1.0f,0.0f,0.0f);
- //建立阴影矩阵
- D3DXMATRIX S;
- D3DXMatrixShadow(&S,&lightDirection,&groundPlane);
- //平移矩阵用T来存储茶壶的位置
- 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;
- //关闭深度渲染,为了防止闪动,因为阴影和地面都在同一层上通过先渲染地板然后用深度测
- //试屏蔽阴影,这样我们就能够保证阴影将绘制在地面之上
- 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);
- }
- //
- const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL|D3DFVF_TEX1;
- //
- // Framework Functions
- //
- bool Setup()
- {
- //设置材质
- //设置墙的镜面反射光为白色*0.2
- WallMtrl.Specular = d3d::WHITE *0.2f;
- //创建一个茶壶对象
- D3DXCreateTeapot(Device,&Teapot,0);
- //创建顶点缓冲区
- Device->CreateVertexBuffer(24*sizeof(Vertex),D3DUSAGE_WRITEONLY,Vertex::FVF,D3DPOOL_MANAGED,&VB,0);
- Vertex * v;
- //锁缓冲区
- VB->Lock(0,0,(void **)&v,0);
- // floor地板
- //地板宽长,长中点是原点,正面朝y轴的正方向
- 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);
- // wall
- //墙的一边-7.5和-2.5之间,x5的正方形,正面朝z轴的负方向
- 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);
- //墙的另一边,.5和.5之间,x5的正方形,正面朝z轴的负方向
- 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);
- // 两边墙的中间-2.5和.5之间放镜子
- 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, "ice.bmp", &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);
- //开启灯光
- Device->LightEnable(0,true);
- //重新规格化法线,并且设为镜面高光可用
- Device->SetRenderState(D3DRS_NORMALIZENORMALS,true);
- Device->SetRenderState(D3DRS_SPECULARENABLE,true);
- //设置相机
- D3DXMATRIX V;
- D3DXVECTOR3 pos(0.0f,3.0f,-3.0f);
- D3DXVECTOR3 target(0.0f,0.0f,0.0f);
- D3DXVECTOR3 up(0.0f,3.0f,0.0f);
- D3DXMatrixLookAtLH(&V,&pos,&target,&up);
- Device->SetTransform(D3DTS_VIEW,&V);
- //设置透视平面
- D3DXMATRIX proj;
- D3DXMatrixPerspectiveFovLH(&proj,D3DX_PI *0.5f,(float)Width/(float)Height,1.0f,1000.0f);
- Device->SetTransform(D3DTS_PROJECTION,&proj);
- return true;
- }
- void Cleanup()
- {
- d3d::Release<IDirect3DVertexBuffer9*>(VB);
- d3d::Release<IDirect3DTexture9*>(FloorTex);
- d3d::Release<IDirect3DTexture9*>(WallTex);
- d3d::Release<IDirect3DTexture9*>(MirrorTex);
- d3d::Release<ID3DXMesh*>(Teapot);
- }
- void RenderSceen()
- {
- //设置材质
- Device->SetMaterial(&TeapotMtrl);
- //设置纹理
- Device->SetTexture(0, 0);
- //把茶壶的自身坐标系转换为世界坐标系
- D3DXMATRIX W;
- D3DXMatrixTranslation(&W,
- TeapotPosition.x,
- TeapotPosition.y,
- TeapotPosition.z);
- Device->SetTransform(D3DTS_WORLD, &W);
- //绘制茶壶
- Teapot->DrawSubset(0);
- //单位矩阵和世界坐标系重合
- D3DXMATRIX I;
- D3DXMatrixIdentity(&I);
- Device->SetTransform(D3DTS_WORLD, &I);
- //设置资源流和设置顶点格式
- Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
- Device->SetFVF(Vertex::FVF);
- //开始画地板了
- //设置地板材质
- Device->SetMaterial(&FloorMtrl);
- //设置地板纹理
- Device->SetTexture(0, FloorTex);
- //画个三角形图元,就是个长方体Vertex[0]-Vertex[5]
- Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
- //画墙
- Device->SetMaterial(&WallMtrl);
- Device->SetTexture(0, WallTex);
- //从Vertex[6]开始画个三角形图元,因为有墙有两部分Vertex[6]-Vertex[17]
- Device->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 4);
- //画镜子,Vertex[18]-Vertex[23]
- Device->SetMaterial(&MirrorMtrl);
- Device->SetTexture(0, MirrorTex);
- Device->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);
- }
- void RenderMirror()
- {
- //启用模板缓存
- Device->SetRenderState(D3DRS_STENCILENABLE,true);
- //设置模板测试为总是成功
- Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);
- //设置模板参考值为
- Device->SetRenderState(D3DRS_STENCILREF,0x1);
- //设置模板掩码为全,不掩盖任何位
- 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_REPLACE);
- //关闭深度缓存
- Device->SetRenderState(D3DRS_ZWRITEENABLE,false);
- //混合和设置源混合要素为D3DBLEND_ZERO目
- //的混合要素为D3DBLEND_ONE。将这些混合要素代入混合等式,我们得到后缓存是不会改变的
- Device->SetRenderState(D3DRS_ALPHATESTENABLE,true);
- Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);
- Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
- //绘制镜子
- Device->SetStreamSource(0,VB,0,sizeof(Vertex));
- Device->SetFVF(Vertex::FVF);
- Device->SetMaterial(&MirrorMtrl);
- Device->SetTexture(0,MirrorTex);
- D3DXMATRIX I;
- D3DXMatrixIdentity(&I);
- Device->SetTransform(D3DTS_WORLD,&I);
- Device->DrawPrimitive(D3DPT_TRIANGLELIST,18,2);
- //开启深度渲染
- Device->SetRenderState(D3DRS_ZWRITEENABLE,true);
- //设置模式测试为相等时成功,成功时保持原状
- Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL);
- Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);
- //反射矩阵
- D3DXMATRIX W,T,R;
- D3DXPLANE plane(0.0f,0.0f,1.0f,0.0f);
- D3DXMatrixReflect(&R,&plane);
- //把茶壶的世界坐标位置赋给T
- D3DXMatrixTranslation(&T,
- TeapotPosition.x,
- TeapotPosition.y,
- TeapotPosition.z);
- //这时的W就是镜子里茶壶的位置
- W = T * R;
- //,假如现在就渲染它,它是不会被显示的。因为被反射的茶壶的深度比镜子的深度大,因此镜子的图元将把被反射茶壶的图元弄模糊。
- // 为了避免这种情况,清除深度缓存:
- //清除深度缓存并且要混合被反射的茶壶和镜子
- Device->Clear(0,0,D3DCLEAR_ZBUFFER,0,1.0f,0);
- Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
- Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);
- //绘制镜子里的茶壶
- Device->SetTransform(D3DTS_WORLD,&W);
- Device->SetMaterial(&TeapotMtrl);
- Device->SetTexture(0,0);
- Device->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);
- Teapot->DrawSubset(0);
- //当一个物体被反射以后,它的正面和背面将会被交
- //换。因此必须改变背面拣选模式
- Device->SetRenderState(D3DRS_ALPHATESTENABLE,false);
- Device->SetRenderState(D3DRS_STENCILENABLE,false);
- Device->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
- }
- 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)
- {
- radius -= 2.0f * timeDelta;
- }
- if(GetAsyncKeyState(VK_DOWN)&0x8000f)
- {
- radius += 2.0f * timeDelta;
- }
- static float angle = (3.0f * D3DX_PI) / 2.0f;
- if( ::GetAsyncKeyState('A') & 0x8000f )
- angle -= 0.5f * timeDelta;
- if( ::GetAsyncKeyState('S') & 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_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x00000000,1.0f,0L);
- Device->BeginScene();
- RenderSceen();
- RenderShdow();
- RenderMirror();
- Device->EndScene();
- Device->Present(0,0,0,0);
- }
- return true;
- }
- //
- // WndProc
- //
- LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch( msg )
- {
- case WM_DESTROY:
- ::PostQuitMessage(0);
- break;
- case WM_KEYDOWN:
- if( wParam == VK_ESCAPE )
- ::DestroyWindow(hwnd);
- break;
- }
- return ::DefWindowProc(hwnd, msg, wParam, lParam);
- }
- //
- // WinMain
- //
- int WINAPI WinMain(HINSTANCE hinstance,
- HINSTANCE prevInstance,
- PSTR cmdLine,
- int showCmd)
- {
- if(!d3d::InitD3D(hinstance,
- Width, Height, true, D3DDEVTYPE_HAL, &Device))
- {
- ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
- return 0;
- }
- if(!Setup())
- {
- ::MessageBox(0, "Setup() - FAILED", 0, 0);
- return 0;
- }
- d3d::EnterMsgLoop( Display );
- Cleanup();
- Device->Release();
- return 0;
- }
链接地址:http://blog.youkuaiyun.com/xfate/article/details/5828845