您的位置:首页 > 其它

Direct3D学习手记八:模板技术【镜面效果】

2013-12-28 14:15 204 查看

本文介绍模板技术并实现镜面效果

模板缓存:

模板缓存和深度缓存是同时创建的,在指定深度缓存格式的时候,模板缓存的格式也被同时指定了,语句如下:

d3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;//24位深度缓存,8位模板缓存
模板缓存的分辨率与深度缓存和后台缓存的分辨率大小相同,

屏幕上的某个像素点都对应着模板缓存、深度缓存和后台缓存中的某个像素值。

模板缓存与深度缓存类似,都需要通过特定的比较来判断是否更新后台缓存的像素,即也有模板测试过程。

启用模板缓存:

要使用模板缓存必须开启其状态,默认为关闭状态,

g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE,true);//开启模板缓存
另外在执行清屏动作时,还要使用D3DCLEAR_STENCIL清除模板缓存:

g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,D3DCOLOR_XRGB(80,80,80),1.0,0);


模板测试:

模板测试的效果与深度测试类似,都是通过特定的比较方式判断某个像素是否应该被写入后台缓存。

测试表达式:

result=(ref & mask) OP (value & writemask)

result为比较结果,ref为模板参考值,mask为模板参考值的掩码,value为当前像素的值,writemask为当前像素的掩码

设置模板参考值:

g_pd3dDevice->SetRenderState(D3DRS_STENCILREF,0x1);//设置模板参考值


设置模板参考值的掩码:

g_pd3dDevice->SetRenderState(D3DRS_STENCILMASK,0xffffffff);//设置模板测试掩码


设置当前像素的掩码:

g_pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff);//设置模板写掩码


OP为比较方式为D3DCMPFUNC枚举成员:

typedef enum D3DCMPFUNC
{
D3DCMP_NEVER = 1,
D3DCMP_LESS = 2,
D3DCMP_EQUAL = 3,
D3DCMP_LESSEQUAL = 4,
D3DCMP_GREATER = 5,
D3DCMP_NOTEQUAL = 6,
D3DCMP_GREATEREQUAL = 7,
D3DCMP_ALWAYS = 8,
D3DCMP_FORCE_DWORD = 0x7fffffff,
} D3DCMPFUNC, *LPD3DCMPFUNC;
设置比较方式:

g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);//设置比较方法


更新模板缓存:

在测试完成判断某个像素是否写入后台缓存后,要更新模板缓存,必须为其制定更新方式:

1.在模板测试失败时更新

g_pd3dDevice->SetRenderState(D3DRS_STENCILFAIL,StencilOperation);
2.在深度测试失败时更新

g_pd3dDevice->SetRenderState(D3DRS_STENCILZFAIL,StencilOperation);
3.在模板测试和深度测试都成功时更新

g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS,StencilOperation);
其中,StencilOperation为D3DSTENCILOP枚举的成员:

typedef enum D3DSTENCILOP
{
D3DSTENCILOP_KEEP = 1,
D3DSTENCILOP_ZERO = 2,
D3DSTENCILOP_REPLACE = 3,
D3DSTENCILOP_INCRSAT = 4,
D3DSTENCILOP_DECRSAT = 5,
D3DSTENCILOP_INVERT = 6,
D3DSTENCILOP_INCR = 7,
D3DSTENCILOP_DECR = 8,
D3DSTENCILOP_FORCE_DWORD = 0x7fffffff,
} D3DSTENCILOP, *LPD3DSTENCILOP;


镜面效果:

实现步骤:

1.执行清屏操作Clear,指定D3DCLEAR_STENCIL标志清除模板缓存

//Step 1:清屏,颜色设为灰色,深度缓存置为1.0,模板缓存置为0
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,D3DCOLOR_XRGB(80,80,80),1.0,0);


2.禁用模板缓存,绘制一般场景,包括镜面

//绘制镜面
D3DXMatrixTranslation(&matWorld1,0.0F,0.0F,6.0F);
D3DXMatrixRotationY(&Ry,D3DX_PI/4.0F);
D3DXMatrixMultiply(&matWorld1,&Ry,&matWorld1);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld1);
g_pd3dDevice->SetMaterial(&g_Materials[0]);
g_pWallMesh->DrawSubset(0);

//绘制茶壶
D3DXMatrixTranslation(&matWorld2,-1.0F,1.0F,1.0F);
D3DXMatrixRotationY(&Ry,timeGetTime()/500.0F);
D3DXMatrixMultiply(&matWorld2,&matWorld2,&Ry);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld2);
g_pd3dDevice->SetMaterial(&g_Materials[1]);
g_pTeapotMesh->DrawSubset(0);

//绘制球体
D3DXMatrixTranslation(&matWorld3,-1.0F,-1.0F,1.0F);
D3DXMatrixRotationY(&Ry,timeGetTime()/500.0F);
D3DXMatrixMultiply(&matWorld3,&matWorld3,&Ry);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld3);
g_pd3dDevice->SetMaterial(&g_Materials[2]);
g_pSphereMesh->DrawSubset(0);


3.启用模板缓存,并对模板参考值,模板掩码,更新方式进行设置

//Step 3:设置模板
g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE,true);//开启模板缓存
g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);//设置比较方法
g_pd3dDevice->SetRenderState(D3DRS_STENCILREF,0x1);//设置模板参考值
g_pd3dDevice->SetRenderState(D3DRS_STENCILMASK,0xffffffff);//设置模板测试掩码
g_pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff);//设置模板写掩码
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_REPLACE);//设置模板测试成功后更新模板的方式为替换


4.关闭向深度缓存的写操作,开启融合技术,源融合因子设为0,目标融合因子设为1,最终得到目标颜色值

//Step 4:关闭向深度缓存的写操作,开启融合技术,源融合因子设为0,目标融合因子设为1
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE,false);//关闭向深度缓存的写操作
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true);//开启融合
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);//源融合因子设为0
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);//目标融合因子设为1


5.绘制镜面到模板缓存中

//绘制镜面
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld1);
g_pd3dDevice->SetMaterial(&g_Materials[0]);
g_pWallMesh->DrawSubset(0);


6.开启向深度缓存的写操作,重新设置模板的比较方式与更新方式

//Step 6.1
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE,true);//开启向深度缓存的写操作
g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL);//设置比较方法
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);//设置模板测试成功后更新模板的方式


7.清空深度缓存,让镜像与镜面相融合

g_pd3dDevice->Clear(0,NULL,D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(80,80,80),1.0F,0);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTALPHA);//源融合因子设为目标Alpha
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);//目标融合因子设为0


8.重新设置消隐方式,因为镜像为物体的背面,其图元为逆时针,默认会被消隐,即看不到

g_pd3dDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);//镜像翻转绘制背面,设置消隐方式为顺时针


9.设置镜面及镜面变换矩阵

D3DXMATRIX matReflect,matMirror;
D3DXPLANE plane(1.0F,0.0F,1.0F,-6.0F);//平面 (x)+0*y+(z-6)=0即x+z-6=0;
D3DXMatrixReflect(&matReflect,&plane);


10.绘制物体的镜像

//茶壶镜像
D3DXMatrixMultiply(&matMirror,&matWorld2,&matReflect);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matMirror);
g_pd3dDevice->SetMaterial(&g_Materials[1]);
g_pTeapotMesh->DrawSubset(0);
//球体镜像
D3DXMatrixMultiply(&matMirror,&matWorld3,&matReflect);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matMirror);
g_pd3dDevice->SetMaterial(&g_Materials[2]);
g_pSphereMesh->DrawSubset(0);


Render函数源码:

/****************************************************************
*函数名	:	Render
*功能		:	场景绘制
*输入		:	无
*输出		:	无
*返回值	:	无
****************************************************************/
void			Render()
{
//Step 1:清屏,颜色设为灰色,深度缓存置为1.0,模板缓存置为0
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,D3DCOLOR_XRGB(80,80,80),1.0,0);

if(SUCCEEDED(g_pd3dDevice->BeginScene()))//开始绘制
{
/*在此绘制其他*/

//Step :2:先绘制一般物体,先禁用模板缓存
g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE,false);//禁用模板缓存

//设置世界变换矩阵
D3DXMATRIX matWorld1,matWorld2,matWorld3,Ry;

//绘制镜面
D3DXMatrixTranslation(&matWorld1,0.0F,0.0F,6.0F);
D3DXMatrixRotationY(&Ry,D3DX_PI/4.0F);
D3DXMatrixMultiply(&matWorld1,&Ry,&matWorld1);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld1);
g_pd3dDevice->SetMaterial(&g_Materials[0]);
g_pWallMesh->DrawSubset(0);

//绘制茶壶
D3DXMatrixTranslation(&matWorld2,-1.0F,1.0F,1.0F);
D3DXMatrixRotationY(&Ry,timeGetTime()/500.0F);
D3DXMatrixMultiply(&matWorld2,&matWorld2,&Ry);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld2);
g_pd3dDevice->SetMaterial(&g_Materials[1]);
g_pTeapotMesh->DrawSubset(0);

//绘制球体
D3DXMatrixTranslation(&matWorld3,-1.0F,-1.0F,1.0F);
D3DXMatrixRotationY(&Ry,timeGetTime()/500.0F);
D3DXMatrixMultiply(&matWorld3,&matWorld3,&Ry);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld3);
g_pd3dDevice->SetMaterial(&g_Materials[2]);
g_pSphereMesh->DrawSubset(0);

//Step 3:设置模板
g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE,true);//开启模板缓存
g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_ALWAYS);//设置比较方法
g_pd3dDevice->SetRenderState(D3DRS_STENCILREF,0x1);//设置模板参考值
g_pd3dDevice->SetRenderState(D3DRS_STENCILMASK,0xffffffff);//设置模板测试掩码
g_pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff);//设置模板写掩码
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_REPLACE);//设置模板测试成功后更新模板的方式为替换

//Step 4:关闭向深度缓存的写操作,开启融合技术,源融合因子设为0,目标融合因子设为1
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE,false);//关闭向深度缓存的写操作
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true);//开启融合
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);//源融合因子设为0
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);//目标融合因子设为1

//Step 5:绘制镜面到模板缓存中
//绘制镜面
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matWorld1);
g_pd3dDevice->SetMaterial(&g_Materials[0]);
g_pWallMesh->DrawSubset(0);

//Step 6:绘制物体镜像
//Step 6.1
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE,true);//开启向深度缓存的写操作
g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL);//设置比较方法
g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);//设置模板测试成功后更新模板的方式
//Step 6.2:清空深度缓存
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(80,80,80),1.0F,0);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTALPHA);//源融合因子设为目标Alpha
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);//目标融合因子设为0

//Step 6.3:设置镜面变换矩阵
D3DXMATRIX matReflect,matMirror;
D3DXPLANE plane(1.0F,0.0F,1.0F,-6.0F);//平面 (x)+0*y+(z-6)=0即x+z-6=0;
D3DXMatrixReflect(&matReflect,&plane);

g_pd3dDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);//镜像翻转绘制背面,设置消隐方式为顺时针
//茶壶镜像
D3DXMatrixMultiply(&matMirror,&matWorld2,&matReflect);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matMirror);
g_pd3dDevice->SetMaterial(&g_Materials[1]);
g_pTeapotMesh->DrawSubset(0);
//球体镜像
D3DXMatrixMultiply(&matMirror,&matWorld3,&matReflect);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&matMirror);
g_pd3dDevice->SetMaterial(&g_Materials[2]);
g_pSphereMesh->DrawSubset(0);

g_pd3dDevice->EndScene();//结束绘制
}
g_pd3dDevice->Present(NULL,NULL,NULL,NULL);//翻转,显示
}


程序运行结果:






源代码及工程文件下载地址:

百度网盘
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: