-
12.
屏蔽缓冲区
屏蔽是一项我们尚未讨论过的高阶绘制功能,这是一项在发展商业应用程序时很有用的技
术。如果想让您的
3D
程序与众不同,最好能结合屏蔽以及前面
学到的贴图技术。本章会详
述如何运用屏蔽,并且展示能用它产生的不同类型效果。
p>
市面上很多
3D
游戏和模拟都用电影级的特效添加戏剧性的冲击。您可以用屏蔽缓冲区来建
立像合成、印
花(
decal
)、溶入、淡出淡入(
fade
)、边框、剪影(
silhouette
)、刷抹
(
swipe
)以
及阴影等效果。屏蔽缓冲区能决定会绘制影像中的哪些像素。屏蔽缓冲区能让
您针对各像
素开启或关闭对绘制目的绘图页来达成这些功能。这表示您的软件可以「遮住」
部份的影
像让它不要显示。
当屏蔽功能启动时,
Microsoft Direct3D<
/p>
会对要写入绘制目的绘图页的每个像素进行屏蔽测
试。屏蔽测试会
用一个屏蔽参考值、一个屏蔽板(
stencil mask
)
、一个比较函式、以及一
个取自屏蔽缓冲区的像素值(对应于目的绘图页中的现行像素)
。下面是这个测试中所作的
步骤:
1.
用
屏蔽板对屏蔽参考值作位
p>
AND
运算。
2.
用
屏蔽板针对现行像素的屏蔽缓
冲区值作位
AND
运算。
3.
用
比较函式比较步骤
1
和步骤
2
的结果。
p>
控制比较函式、屏蔽板、屏蔽参考值、以及屏蔽测试通过或失败时
的动作,就可以控制屏蔽
缓冲区的运作。当测试成功时,现行像素会被写入目标。预设比
较动作(
D3DCMPFUNC
列举类型所定义的
D3DCMP_ALWAYS
)不会管屏蔽缓冲区的内容而直接写入像素。您
可
以设定
D3DRENDERSTATE_STENCILFU
NC
绘制状态并转入任一个
D3DCMPFUNC
成员
值来改用任何所要的函式。
建立一个屏蔽缓冲区
在建立屏蔽缓冲区之前必须决定目标系统所支持的屏蔽功能。
方法是呼叫
IDirect3DDevice7::GetCaps
方法。
dwStencilCaps
旗标表示装置所支持的
屏蔽缓冲区运
算。回报的旗标对全部三种屏蔽缓冲区运算都有效:
D3DRENDERSTATE_STENCILFAIL
、
D3DRENDERSTATE_STENCILPASS
以及
D3DRENDERSTATE_STENCILZFAIL
。
Direct3D
定义了下列的
dwStencilCaps<
/p>
旗标:
?
D3DSTENCILCAPS_DECR
表示有支持
p>
D3DSTENCILOP_DECR
运算
?
D3DSTENCILCAPS_DECRSAT
表示有支持
D3DSTENCILOP_DECRSAT
运算
?
D3DSTENCILCAPS_INCR
表示有支持
D3DSTENCILOP_INCR
运算
?
D3DSTENCILCAPS_INCRSAT
表示有支持
D3DSTENCILOP_INCRSAT
运算
?
D3DSTENCILCAPS_INVERT
表示有支持
D3DSTENCILOP_INVERT
运算
?
D3DSTENCILCAPS_KEEP
表示有支持
D3D
STENCILOP_KEEP
运算
?
D3DSTENCILCAPS_REPLACE
表示有支持
D3DSTENCILOP_REPLACE
运算
?
D3DSTENCILCAPS_ZERO
表示有支持
D3DSTENCILOP_ZERO
运算
<
/p>
Direct3D
会用深度缓冲区数据来纪录屏蔽缓冲区信息。要
找出目标系统的硬件支持哪些深
度缓冲区及屏蔽缓冲区格式,可以呼叫
< br>IDirect3D7::EnumZBufferFormats
方法,宣告如
下:
HRESULT
IDirect3D7::EnumZBufferFormats (
);
参数
riidDevice
lpEnumCallback
LpContext
说明
指向一个代表所要列举深度缓冲
区格式的全域唯一辨别码(
GUID
)的参照
< br>
指向
D3DenumPixelFormatsCal
lback
函式的地址,
Direct3D
< br>会对每个支持的深
度缓冲区格式呼叫这个函式。
由应用程序所定义并传入回传函式的数据
REFCLSID riidDevice,
LPD3DENUMPIXELFORMATSCALLBACK
lpEnumCallback,
LPVOID lpContext
如果这个方法成功就会传回
D3D_OK
。如果失败
就会传回以下四个值之一:
?
DDERR_INVALIDOBJECT
?
DDERR_INVALIDPARAMS
?
DDERR_NOZBUFFERHW
?
DDERR_OUTOFMEMORY
下列程序会找出系统提供哪些屏蔽缓冲区以及支持哪些运算,
然后建立一个屏蔽缓冲区。您
可以看到,这段程序代码注明屏蔽缓冲区支持是否大于
p>
1
位。如果只支持
1
位屏蔽缓冲
区,某些屏蔽技术就得用不同的方法处理。
HRESULT
CMyD3DApplication::CreateStencilBuffer()
{
{
}
else
{
//
最好使用上下限为
0/max
的
sat
运算,不过如果屏蔽位足够的话可
以用其它运算。
g_StencIncOp=(dwStencilCaps
&D3DSTENCILCAPS_INCRSAT)?
}
m_
pddsRenderTarget->DeleteAttachedSurface(0,NULL); <
/p>
//
由绘制目标取得
z
< br>缓冲区大小。
//
建立
z
缓冲区的绘图页描述。
DDSURFACEDESC2 ddsd;
D3DUtil_InitSurfaceDesc(ddsd);
D3DSTENCILOP_INCRSAT:D3DSTENCILOP_INCR;
D3DSTENCILOP_DECRSAT:D3DSTENCILOP_DECR;
g_StencDecOp=(dwStencilCaps
&D3DSTENCILCAPS_DECRSAT)?
//
必须用
1
位屏蔽缓冲区。
g_bCanOnlyDoOneBitStencil=TRUE;
g_bCanOnlyDoOneBitStencil=FALSE;
DWORD dwStencilCaps
=m_pDeviceInfo-
if((!(dwStencilCaps
&D3DSTENCILCAPS_INCR)&&
!(dwStencilCaps &D3DSTENCILCAPS_INCRSAT))||
(!(dwStencilCaps
&D3DSTENCILCAPS_DECR)&&
!(dwStencilCaps &D3DSTENCILCAPS_DECRSAT)))
>cilCaps;
m_pddsRenderTarget
->GetSurfaceDesc(&ddsd);
s
=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|
DDSD_PIXELFORMAT;
=DDSCAPS_ZBUFFER;
2 =0;
3 =0;
4 =0;
s =DDPF_ZBUFFER|DDPF_STENCILBUFFER;
if(m_pDeviceInfo->bHardware)
else
//
由格式列举动作取得适合的像素
格式。
m_pD3D->EnumZBufferForma
ts((*m_pDeviceInfo->pDeviceGUID),
EnumZBufferFormatsCallback,
(VOID*)&xelFormat);
assert(cilBitDepth!=0);
g_bC
anOnlyDoOneBitStencil=g_bCanOnlyDoOneBitStencil||
在窗口大小改变的时候保持 <
br>lpRects 绘制目标绘图页的大小来清除整个绘图页。这些矩形都是用对应于绘制目标绘图
次方
0.0
g_dwMaxStencilValue=(1<
p>
//
建立并连接
z
缓冲区。
if(FAILED(m_pDD->Create
Surface(&ddsd,&m_pddsDepthBuffer,
NULL)))
return E_FAIL;
if(
FAILED(m_pddsRenderTarget->AddAttachedSurface(
return E_FAIL;
SetMenuStates();
//
g_bUseOneBitStencil
为被设定。
if(!g_bUseOneBitStencil)
p>
g_bUseOneBitStencil=g_bCanOnlyDoOneBitSte
ncil;
((1<
|=DDSCAPS_SYSTEMMEMORY;
|=DDSCAPS_VIDEOMEMORY;
构。
}
//
必须呼叫
SetRenderTarget()
来重建新连接
z
缓冲区所用的内部结
return m_pd3dDevice->S
etRenderTarget(m_pddsRenderTarget,0L);
//------------------------------------------------
----------------
---
//
名称:
EnumZBufferFormatsCallback
//
说明:回报合法
z
缓冲区像素格式的列举函式
//-------------
--------------------------------------------------
-
---
static
HRESULT WINAPI
EnumZBufferFormatsCallback(DDPIXELFORMAT*pddpf,
VOID*pddpfDesired)
{
}
if(NULL==pddpf||NULL==pddpfDesired)
return D3DENUMRET_CANCEL;
//
如果目前的像素格式符合需要
(DDPF_ZBUFFER
p>
,可能也有
//DDPF_STENCI
LBUFFER)
,复制格式并返回。这个函式并不挑剔,
//
它会接受第一个传回的合法格式。
if(pddpf->dwFlags
==((DDPIXELFORMAT*)pddpfDesired)->dwFlags)
{
}
return D3DENUMRET_OK;
memcpy
(pddpfDesired,pddpf,sizeof(DDPIXELFORMAT));
return D3DENUMRET_CANCEL;
清除屏蔽缓冲区
您可以用
IDirect3DDevice7
接口的
Clear
方法同时清除绘制目标的色彩缓冲区、深度缓冲
区以及屏蔽缓冲区。下面
是
IDirect3DDevice7::Clear
方法的宣
告:
HRESULT
IDirect3DDevice7::Clear(
DWORD dwCount,
LPD3DRECT
lpRects,
);
DWORD dwFlags,
D3DVALUE dvZ,
DWORD
dwStencil
参数
说明
dwCount
在
中的矩形数量。
一个
D3DRECT
结构的数组,数组中定义了要清除的矩形
区域。您可以把矩形设成
lpRects
页上
图点的画面坐标。坐标值会受检视
埠矩形的边界限制。
指示要清除哪个
绘图页的旗标。这个参数可以是下列旗标的组合,
不过至少要有
一个旗标:
D3DCLEAR_TARGET
把绘制目标绘图页清成<
/p>
dwColor
参数中的颜色。
D3DCLEAR_STENCIL
把屏蔽缓冲区清成
p>
dwStencil
参数中的值。
D3DCLEAR_ZBUFFER
把深度缓冲区清成
p>
dvZ
参数的值。
dwColor
用来清除绘制目标绘
图页的
32
位
RGBA
色彩值。
dvZ
由这个方法存到深度缓冲区的新
z
值。参数值由
0.0
到
1.0
。
0.0
表示离观察者最近
的距离。
1.0
表示最远的距离。
储存在各个屏蔽缓冲区内容的整数值。这个参数的范围为
0
到
2
的
n
-1
,其中
n
是屏蔽缓冲区的位深度。
dwFlags
dwStencil
IDirect
3DDevice7::Clear
方法还是能接受以前的
D3
DCLEAR_TARGET
旗标,意思是用
dwColor<
/p>
参数提供的
RGBA
色彩清除绘制目标。
这个方法也还能接受
D3DCLEAR_ZBUFFER
旗标,
意思是把深度缓冲区清除成在
dvZ
(其中
表示最近的距
离而
1.0<
/p>
表示最远的距离)所设定的深度。
DirectX 6
引入了
D3DCLEAR_STENCIL
旗标,
作用是用
dwStencil
参数所指
定的值重设屏蔽位。这个值的范围是
0
到
2
的
n
次方
-1
,其中
n
是屏蔽缓冲区的位深度。
设定屏蔽状态
您用
ID
irect3DDevice7::SetRenderState
方法来控制屏蔽缓冲
区的各种设定。下面是与屏蔽
相关的
D3DRENDERSTA
TETYPE
列举类型成员:
typedef enum _D3DRENDERSTATETYPE{
.
.
.
D3DRENDERSTATE_STENCILREF
D3DRENDERSTATE_STENCILMASK
=57,//
屏蔽测试的参考值
p>
=58,//
屏蔽测试所用的屏
=59,/
/
屏蔽缓冲区写入的
.
.
.
D3DRENDERSTATE_STENCILFAIL
D3DRENDERSTATE_STENCILPASS
D3DRENDERSTATE_STENCILFUNC
=53,//
屏蔽运算
=54,//
屏蔽运算
=55,//
屏蔽运算
=56,//
屏蔽比较函式
D3DRENDERSTATE_STENCILZFAIL
D3DRENDERSTATE_STENCILENABLE
=52,//
启动或关闭屏蔽
蔽
mask
值
D3DRENDERSTATE_STENCILWRITEMASK
屏蔽
mask
值
} D3DRENDERSTATETYPE;
下面是与屏蔽相关的绘制状态定义:
?
D3DRENDERSTATE_STENCILENABLE
用这个成员来启动或关
闭屏蔽。要启动屏
蔽时把这个成员设成
TRUE
,要关闭时则设成
FALSE
。默认值为
FALSE
。
?
D3DRENDERSTATE_STENCILFAIL
用这个成员来指定当屏蔽测
试失败时所做的屏
蔽测试。屏蔽运算可以是
D3DSTENCI
LOP
列举类型的任一个成员。默认值是
D3DSTENCIL
OP_KEEP
。
?
D3DRENDERSTATE_STENCILZFAIL
用这个成员来指定当屏蔽
测试通过而深度测
试(
z
测试)失败时
所作的屏蔽运算。这个运算可以是
D3DSTENCILOP
列
举类型
的任一个成员。默认值为
D3DSTENCILOP_K
EEP
。
?
D3DRENDERSTATE_STENCILPASS
用这个成员来指定当屏蔽测
试和深度测试(
z
测试)都通过时所作的屏蔽运算。这个运算可
以是
D3DSTENCILOP
列举类型的任
< br>一个成员。默认值为
D3DSTENCILOP_KEEP
。
?
D3DRENDERSTATE_STENCILFUNC
用这个成员来指定屏蔽测试
所用的比较函
式。这个比较函式可以是
D3DCMPFUNC<
/p>
列举类型的任一个成员。默认值是
D3DCMP_ALWAYS<
/p>
。这个函式会把参考值和屏蔽板所设的屏蔽缓冲区值相比较。
(<
/p>
D3DRENDERSTATE_STENCILMASK
绘制状
态会设成屏蔽板)如果比较结果为
真,屏蔽测试就通过。
?
D3DRENDERSTATE_STENCILREF
用
这个成员来指定屏蔽测试所用的整数参考
值。默认值为
0
。
?
D3DRENDERSTATE_STENCILMASK
用这个成员来指定套用在参
考值及各个屏蔽
缓冲区内容以决定屏蔽测试重要位的屏蔽值。预设屏蔽板为
0×
FFFFFFFF
。
?
D3DRENDERSTATE_STENCILWRITEMASK
用这个成员来指定作用在写入屏蔽缓
冲区值的屏蔽值。默认值为
0×
FFFFFFFF
。
D3DSTENCILOP
列举类型叙述
D3DRENDERSTATE_STENCILFAI
L
、
D3DRENDERSTATE_STENCILZFAI
L
以及
D3DRENDERSTATE_STENCILPAS
S
绘制状
态所用的屏蔽运算。下面是
D
3DSTENCILOP
的定义:
typedef enum _D3DSTENCILOP {
D3DSTENCILOP_KEEP
D3DSTENCILOP_ZERO
=3,
=4,
=5,
=6,
=7,
=8,
=1,
=2,
D3DSTENCILOP_REPLACE
D3DSTENCILOP_INCRSAT
D3DSTENCILOP_DECRSAT
D3DSTENCILOP_INVERT
D3DSTENCILOP_INCR
D3DSTENCILOP_DECR
D3DSTENCILOP_FORCE_DWORD
=0x7fffffff
}D3DSTENCILOP;
这些成员的目的如下:
?
D3DSTENCILOP_KEEP
表示您不想更新屏蔽缓冲区中的数据。这是预设的运算。
-
-
-
-
-
-
-
-
-
上一篇:Unity内置Shader着色器效果整理
下一篇:常用纸浆中英文单词对照