Direct3D模版缓存
来源:互联网 发布:java邮箱验证基本思路 编辑:程序博客网 时间:2024/05/18 03:16
一、概要
模版缓存是一个用于获得某种特效的离屏(off-screen)缓存。模版缓存的分辨率与后台缓存和深度缓存的分辨率完全相同,所以模版缓存中的像素与后台缓存和深度缓存中的像素是一一对应的。模版缓存允许我们动态地、有针对性地决定是否绘制某个像素,创建诸如图形合成、贴花、消融、淡入淡出、轮廓显示、侧影、滑入以及阴影等特殊效果。
模版测试的工作步骤如下:
1、 将模版参考值同模版掩码进行按位与运算。
2、将当前像素的模版缓存中的数值同模版掩码进行按位与运算。
3、利用模版比较函数,比较上述两步产生的结果。
二、模版缓存的格式
模版缓存可与深度缓存一同创建。为深度缓存指定格式时,我们可以同时指定模版缓存的格式。实际上,模版缓存和深度缓存共享同一个离屏的表面缓存,而每个像素的内存段被划分为若干部分,分别与某种特定缓存相对应。
例如:
●D3DFMT_D24S8 该格式的含义是,创建一个32位的深度/模版缓存,其中每个像素的24位指定给深度缓存,8位指定给模版缓存。
●D3DFMT_D24X4S4 该格式的含义是,创建一个32位的深度/模版缓存,其中每个像素的24位指定给深度缓存,4位指定给模版缓存,其余4位不使用。
●D3DFMT_D15S1 该格式的含义是,创建一个16位的深度/模版缓存,其中每个像素的15位指定给深度缓存,1位指定给模版缓存。
一些格式没有为模版缓存分配任何空间,例如,D3DFMT_D32仅创建一个32位的深度缓存。
三、模版测试
判定是否将某个像素写入后台缓存的决策过程称为模版测试,其表达式如下:
(ref & mask)ComparisonOperation (value & mask)
假定模版已处于启用状态,则每个像素都需要进行模版测试。模版测试需要如下两个操作数。
●左操作数(LHS = ref & mask),该值由应用程序定义的模版参考值(ref)和模版掩码(mask)通过按位与运算得到。
●右操作数(RHS = value & mask),该值由当前进行测试的像素的模版缓存中的数值(value)和模版掩码(mask)通过按位与运算得到。
接下来依据ComparisonOperation所指定的比较规则对 LHS 和 RHS 进行比较。比较结果为布尔类型。如果测试结果为 true ,便将该像素写入后台缓存。如果测试结果为 false ,则阻止该像素被写入后台缓存。当然,当一个像素不被写入后台缓存时,也不会被写入深度缓存。
四、模版测试的控制
1、模版参考值
模版参考值(stencil reference value)ref的默认值为 0 ,我们可以使用D3DRS_STENCILREF绘制状态改变该值。例如:
Device->SetRenderState(D3DRS_STENCILREF,0x1);
2、模版掩码
模版掩码(mask)用于屏蔽(隐藏)ref 和 value 变量中的某些位。其默认值为 0xffffffff ,表示不屏蔽任何位。我们可以使用绘制状态D3DRS_STENCILMASK来修改该值。例如:
Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff);
3、模版值
模版值是当前待测试像素在模版缓存中的对应值。我们不能显式地单独设置模版值,但是可以对模版缓存进行清空操作。此外,我们还可以用模版的绘制状态控制将要写入模版缓存的内容。
4、比较运算
我们可以通过绘制状态D3DRS_STENCILFUNC来设置比较运算函数。该比较运算函数可取自如下枚举类型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, /* force 32-bit size 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, /* force 32-bit size enum */
} D3DCMPFUNC;
●D3DCMP_NEVER 模版测试总是失败,即比较函数总是返回 false 。
●D3DCMP_LESS 若 LHS < RHS ,则模版测试成功。
●D3DCMP_EQUAL 若 LHS = RHS ,则模版测试成功。
●D3DCMP_LESSEQUAL 若 LHS <= RHS ,则模版测试成功。
●D3DCMP_GREATER 若 LHS > RHS ,则模版测试成功。
●D3DCMP_NOTEQUAL 若 LHS ≠ RHS ,则模版测试成功。
●D3DCMP_GREATEREQUAL 若 LHS >= RHS ,则模版测试成功。
●D3DCMP_ALWAYS 模版测试总是成功,即比较函数总是返回 true 。
五、模版缓存的更新
除了决定一个具体像素是否应该被写入后台缓存,我们还可以基于一下 3 中可能的情形定义模版缓存中的值如何进行更新。
●第 i 行、第 j 列的像素模版测试失败。这种情况下,我们可借助绘制状态D3DRS_STENCILFAIL将模版缓存中处于同样位置的项的更新方式定义如下:
Device->SetRenderState(D3DRS_STENCILFAIL,StencilOperation);
●第 i 行、第 j 列的像素深度测试失败。这种情况下,我们可借助绘制状态D3DRS_STENCILZFAIL将模版缓存中处于同样位置的项的更新方式定义如下:
Device->SetRenderState(D3DRS_STENCILZFAIL,StencilOperation);
●第 i 行、第 j 列的像素深度测试和模版测试均成功。这种情况下,我们可借助绘制状态D3DRS_STENCILPASS将模版缓存中处于同样位置的项的更新方式定义如下:
Device->SetRenderState(D3DRS_STENCILPASS,StencilOperation);
其中StencilOperation可取以下预定义的常量:
●D3DSTENCILOP_KEEP 不更新模版缓存中的值,即保留当前值。
●D3DSTENCILOP_ZERO 将模版缓存中的值设为 0 。
●D3DSTENCILOP_REPLACE 用模版参考值替代模版缓存中的对应值。
●D3DSTENCILOP_INCRSAT 增加模版缓存中的对应数值,如果超过最大值,取最大值。
●D3DSTENCILOP_ZERO 将模版缓存中的值设为 0 。
●D3DSTENCILOP_REPLACE 用模版参考值替代模版缓存中的对应值。
●D3DSTENCILOP_INCRSAT 增加模版缓存中的对应数值,如果超过最大值,取最大值。
●D3DSTENCILOP_DECRSAT 减小模版缓存中的对应数值,如果小于最小值,取最小值。
●D3DSTENCILOP_INVERT 模版缓存中的值按位取反。
●D3DSTENCILOP_INCR 增加模版缓存中的对应数值,如果超过最大值,取 0 。
●D3DSTENCILOP_DECR 减小模版缓存中的对应数值,如果小于 0,取最大值 。
●D3DSTENCILOP_INVERT 模版缓存中的值按位取反。
●D3DSTENCILOP_INCR 增加模版缓存中的对应数值,如果超过最大值,取 0 。
●D3DSTENCILOP_DECR 减小模版缓存中的对应数值,如果小于 0,取最大值 。
六、模版写掩码
通过设置写掩码,我们可以屏蔽将写入模版缓存的任何值的某些位。可以用绘制状态D3DRS_STENCILWRITEMASK来设定写掩码的值,其默认值为 0xffffff。
Device->SetRenderState(D3DRS_STENCILWRITEMASK,0x0000ffff);
七、示例代码
下面的代码绘制一个矩形,矩形的左下角为红色,右上角为绿色,然后在矩形的正中心绘制一个茶壶。通过应用模版缓存,仅绘制茶壶位于矩形右上角的部分。
#include <d3d9.h>#pragma warning( disable : 4996 ) // disable deprecated warning #include <strsafe.h>#pragma warning( default : 4996 )#include <d3dx9math.h>LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; ID3DXMesh* Teapot = 0;struct CUSTOMVERTEX{ FLOAT x, y, z; DWORD color; };#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)HRESULT InitD3D( HWND hWnd ){ if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;d3dpp.BackBufferCount = 1;d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;d3dpp.MultiSampleQuality = 0;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.Windowed = true;d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;d3dpp.Flags = 0; if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } return S_OK;}VOID SetupMatrices(){D3DXVECTOR3 vEyePt(0.0f, 0.0f, -20);D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);D3DXMATRIXA16 matView;D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);//D3DXMatrixPerspectiveFovLH()函数中的最远、最近距离为相对于视点的距离(即vEyePt中的距离)D3DXMATRIXA16 matProj;D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 2, 1.0f, 1.0f, 200.0f);g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);}HRESULT InitVB(){D3DXCreateTeapot(g_pd3dDevice, &Teapot, 0); CUSTOMVERTEX vertices[6] = { -10, -10, 0, D3DCOLOR_XRGB(255, 0, 0), -10, 10, 0, D3DCOLOR_XRGB(255, 0, 0), 10, -10, 0, D3DCOLOR_XRGB(255, 0, 0), -10, 10, 0, D3DCOLOR_XRGB(0, 255, 0), 10, 10, 0, D3DCOLOR_XRGB(0, 255, 0), 10, -10, 0, D3DCOLOR_XRGB(0, 255, 0) }; if( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( vertices ), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL ) ) ) { return E_FAIL; }VOID* pVertices; if( FAILED( g_pVB->Lock( 0, sizeof( vertices ), ( void** )&pVertices, 0 ) ) ) return E_FAIL; memcpy( pVertices, vertices, sizeof( vertices ) ); g_pVB->Unlock();SetupMatrices(); return S_OK;}VOID Cleanup(){ if( g_pVB != NULL ) g_pVB->Release();if(Teapot != NULL)Teapot->Release(); if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); if( g_pD3D != NULL ) g_pD3D->Release();}void RenderRectangle(){ g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);}void RenderTeapot(){/************************************/将模版缓存用于标记右上三角形区域/***********************************/ 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_STENCILZFAIL, D3DSTENCILOP_KEEP); g_pd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);//禁止写入深度缓存和后台缓存//通过将源目标因子和目标融合因子分别设置为D3DBLEND_ZERO和D3DBLEND_ONE来阻止对后台缓存的更新 g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);//将右上三角形画入模版缓存,这样模版缓存中对应于右上三角形的区域被标记为1g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX)); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 3, 1);// re-enable depth writesg_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, true );//将茶壶只画入右上三角形g_pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); g_pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);g_pd3dDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);//画茶壶D3DXMATRIX W;D3DXMatrixTranslation(&W, 0, 0, -15);g_pd3dDevice->SetTransform(D3DTS_WORLD, &W);Teapot->DrawSubset(0);D3DXMATRIX I;D3DXMatrixIdentity(&I);g_pd3dDevice->SetTransform(D3DTS_WORLD, &I);// Restore render states.g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, false);}VOID Render(){g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0); if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { RenderRectangle();RenderTeapot(); g_pd3dDevice->EndScene(); } // Present the backbuffer contents to the display g_pd3dDevice->Present( NULL, NULL, NULL, NULL );}LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){ switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam );}INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT ){ // Register the window class WNDCLASSEX wc = { sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle( NULL ), NULL, NULL, NULL, NULL, "D3D Tutorial", NULL }; RegisterClassEx( &wc ); // Create the application's window HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial: Stencil", WS_OVERLAPPEDWINDOW, 100, 100, 600, 600, NULL, NULL, wc.hInstance, NULL ); if( SUCCEEDED( InitD3D( hWnd ) ) ) { // Create the vertex buffer and index buffer if( SUCCEEDED( InitVB() ) ) { // Show the window ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); // Enter the message loop MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else Render(); } } } UnregisterClass( "D3D Tutorial", wc.hInstance ); return 0;}
运行效果如下:
阅读全文
0 0
- Direct3D模版缓存
- Direct3D-顶点缓存
- Direct3D-索引缓存
- Direct3D Stencil模板缓存技术
- direct顶点缓存与索引缓存Direct3D
- 模版缓存2
- 模版缓存3
- 三级缓存模版
- Direct3D---深度测试和Z缓存
- Direct3D使用顶点缓存和索引缓存进行绘制
- Direct3D
- Direct3D成长日记(04):深度缓存测试
- Direct3D 10教程7:纹理映射和常量缓存
- [Direct3D] Surfaces (Direct3D 9)
- Direct3D Surfaces (Direct3D 9)
- Tp5关于include模版标签的使用和模版缓存问题
- php中smarty模版引擎中的缓存应用!
- 模版
- frame和iframe的区别
- lmp--->php
- 详解以太坊的工作原理
- list的简单应用
- Elasticsearch部分节点不能发现集群(脑裂)问题处理
- Direct3D模版缓存
- 图片懒加载与预加载
- springboot入门经典
- Alibaba UVa 1632
- ubuntu16.04--需要运行"apt-get -f install"来纠正下列错误
- 关于Android中Dialog位置的设置
- Ubuntu:Unable to locate package(无法定位安装包)
- 如何操作图像的像素--Mat和vector
- 数据库中间件收集