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

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

模板缓存:

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

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);//翻转,显示
}

程序运行结果:

Direct3D学习手记八:模板技术【镜面效果】_第1张图片Direct3D学习手记八:模板技术【镜面效果】_第2张图片


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

百度网盘


你可能感兴趣的:(Direct3D【C++】)