The Frame Buffer

  光栅器将图形primitives转化成像素流,这些像素将与Frame buffer里的目的像素结合在一起。Frame buffer这个术语起源于早期的光栅图形,它就是一块能容纳一张图片的存储空间。随着计算机图形的发展,这个术语不仅包含图像数据,而且也包含一些图形渲染所需要的辅助信息。在Direct3D中,Frame Buffer 不仅包括当前所选择的render target的表面,而且也包含depth/stencil面。如果使用了多采样,需要更多的内存。

 在光栅化以后,每个源像素都包含一个RGB颜色,一个Alpha channel里的透明度值,Z 值里面的depth值。Z值是由光栅器产生的固定精度值。在像素被结合到render target之前,可以进行雾化处理。雾化以后或者stenciling操作以后,基于每个像素的透明度值以及场景里面的深度,它们有可能被拒绝。Stenciling操作可以让Frame Buffer的任意区域的像素被masked away. 与alpha和depth不同的是,与源像素相关的stencil值是从一个render state获得的。像素经过alpha, depth和stencil测试以后,它将被结合到render target里面去。源像素深度值只用于可视计算,深度test以后,就没有与深度值相关的进一步处理被执行了。最后,当render target包含一个RGB颜色的reduced dynamic range,源像素执行抖动处理来减少任何banding artifacts.  抖动处理执行完毕后,源像素就可以写到render target,以及相关的depth/stencil表面。写操作是通过一组write mask控制的。

 Multisampling 为Render Target每个像素提供了提供了多个颜色,深度,stencil值。多个颜色值结合在一起,最终产生出一副图片用于video scan out. 额外的depth和stencil值用来取得合适视觉和steniling效果。Multisampling可以用于antialiasing, depth of field, motion blur 和其他效果。 在渲染的过程中,你可以控制多采样render target的哪个采样将用于detination. 有的效果,是在一个pass里面渲染到与像素有关的所有的samples,然而有的像素在每个pass只渲染到这些采样里面的一部分。 

Fog Blending

在Frame buffer处理之前,雾的颜色混合到源像素的RGB颜色里面。注意:雾只是影响源像素的颜色,并没有影响其Transparency.

Alpha Test

在雾化以后,像素进行基于transparency值的rejection测试。如果alpha Test enable,源像素的alpha值和由render state提供的固定alpha值将进行比较。如果测试失败,这个像素就会被删除掉。

 你能完全reject透明的像素,这些像素在最后的渲染状态中将不会产生任何效果。在大量的像素是完全透明的情况下,这种方法将会减少Frame Buffer里面的工作并且还能提高渲染的效率。

  Alpha Test比较可以通过如下等式: As <op> Ar。

  在这里As是源像素的alpha值, Ar是参考alpha值。<op>是比较函数。 小心不要混淆Alpha Test和Alpha blending,Alpha Test基于源像素的alpha值做reject操作,Alpha blending使用源像素的alpha值将它与Frame buffer结合起来。RS Alpha Blend Enable 控制是否使用alpha test. RS Alpha Func 指定他们的比较函数, RS Alpha Ref指定参考alpha值,它是一个在[0,255]的DWORD值,0对应全透明,255对应全模糊。

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

} D3DCMPFUNC;

  D3DCMPFUNC 对应常用的数学比较操作,但是D3DCMP_NEVER和D3DCMP_ALWAYS除外。D3DCMP_NEVER将总是失败,D3DCMP_ALWAYS将总是成功。D3DCAPS9::AlphaCmpCaps 描述了设备支持的比较函数,它的每个位对应一个比较函数。

The Z Buffer and Visiblity

 Direct3D的可视性通常是由Z buffer决定的。也有其他可视性算法。但是Z Buffer在硬件上容易实现,并且是最通用的可视性算法。当设备创建的时候设置了AutoDepthStencil和AutoDepthStencilFormat,你能创建一个depth/stencil buffer。 如果你使用CreateRenderTarget创建额外的Render Target或者其他swap chains,那么你也可以为这些Render target创建它们的depth/stencil buffer。使用CreateDepthStencilSurface和SetRenderTarget可以到达这个目的。GetDepthStencilSurface返回当前render target的depth/stencil surface.

  Z buffer算法为每个像素保存一个深度值。 当场景被渲染的时候,Z buffer初始化为一个最远的Z 值。 随着源像素经过光栅化产生后,每个像素就有一个Z value。 源像素的Z值与Z buffer的相同位置像素的Z value进行比较。如果源像素的Z值比Z buffer里面的值更加靠近观察者,这个源像素将会被存储在Z buffer里面。 通过这样一种对每个像素的深度值的排序方法实现了可视性检测。

  RS Z Enbale控制是否Enable Z buffer test. 

typedef enum _D3DZBUFFERTYPE

{

   D3DZB_FALSE = 0,

   D3DZB_TRUE = 1, //选择 z buffer

   D3DZB_USEW = 2 // 选择w buffering
}D3DZBUFFERTYPE;

Z buffer test的执行方程是:

   Zs <op>  Zd

Zs 是源像素的Z值, Zd是存储在Render Target里面的深度buffer里面的Z值。op是比较函数。

  • W Buffering

  当使用透视投影的时候,Z buffer对于深度的低位可能是个问题。透视投影使大部分Z buffer的值用于场景中靠近相机的部分。这对于距离相机远的primitive产生了视觉上的artifacts。 你也许可以通过将视截体的近平面和远平面拉近来降低这种影响,但是也不能消除这种问题。另外一种方法就是使用W buffer,W buffer存储的值是齐次深度w的倒数。在这种情况下,w buffer的值甚至会超出视截体的范围。对于一个16位的深度buffer,W buffer 能提高场景里面的可视性的分辨率。

插一段人家写的z buffer 和w buffer的比较:

z-buffering 和 w-buffering

z-buffering 和 w-buffering都表示深度值。几乎所有的3-D加速卡都支持z-buffering,这样就使得z-buffers成为现在最常用的深度缓冲类型。但是,z-buffers也有它本身的缺陷。由于它所使用的数学方法,使得一个z-buffer中产生的z值在它允许的范围内[0.0,1.0]并不是均匀分布的。特别是靠近剪切面与远离剪切面处的比例,更是影响了z值的均匀分布。如果远平面的距离与近平面的距离的比为100,那么导致深度缓冲区的90%被花费在前10%的场景深度。一般的娱乐程序或视觉仿真程序要求远近平面的距离比在1000到10000之间。比值为1000时,范围的98%花费在深度的前2%上,并且随着比值的增大,分布将变得更糟。这样可能会使较远距离的物体上的隐藏表面产生失真,特别是当使用16-bit深度缓冲时。

  w深度缓冲比z-buffer能更均匀地在远近剪切面之间进行分配。使用它的最大好处就是远近剪切面的距离比不再是关键因素。这样就允许程序使用更大的距离范围,同时仍能保持深度缓冲与观察位置间的精确联系。w-buffer也不是完美的,有时也会使近处物体的隐藏表面产生失真。w-buffer的另一个缺点是不能得到硬件的广泛支持。

 

  • Visibility of Transparent Primitives

  Z Buffer的可视性算法实际上就找到离相机最近的一种排序算法,你可能会忽略它的顺序。当primitive完全模糊,最近的pimitive将会出现在最后的渲染图像里面。然而,当primitive半透明,就会显示它后面的像素。为了能够正确的渲染,我们必须维护一个back-to-front的list。 但是这种渲染方式,不能只是通过简单的Z buffer的方式能实现的。

   首先对于完全模糊的物体使用标准的Z buffer可视性算法。接下来,对于场景里面的透明物体,基于他们的bouding box back-to-front排序。然后,对Z buffer的写入被disable,透明物体按照back-to-front的顺序一一被绘制出来。虽然Z buffer写入被禁止,但是Z test还是需要enable,透明的物体依然可以被模糊的物体所遮挡,但是它们还是可以渗透(interpenetrate)到其他透明物体。按照back-to-front的顺序绘制透明的物体,只要物体不相互渗透,它们还是可以遮挡透明物体。对于相互渗透物体的完美的渲染,你应该排序他们的每个三角形,保证每个三角形back-to-front的顺序。然而,取得这个额外的视觉效果往往需要很高的计算成本。

  • Biasing Primitive

  有时候你可能需要绘制两个在数学上是同一个位置的primitive。 比如,你可能想要绘制一个在立方体某一边上的primitive。 解决这种问题你可能通过建模的方法,连接重合的三角形。 另外一个更加简单的办法是使用Z buffer增加一个固定的Z值使它显示在在立方体的前面(front)。

  RSZBias代表增加的Z值,他一般在【0,16】范围以内。

  如果D3DCAPS9::RASTERCAPS的DDPRasterCapsZBias被设置,设置将支持这种处理。

  • Filling and Reading the Z Buffer

  可能有很多次你会往Z buffer里面写值和读取Z buffer的数据。然而,如果你不使用能够锁住的Z buffer格式,这可能不会直接操作。

Stencil Test

  stencil test需要与z buffer联合起来使用。stencil buffer基于depth test的结果和stencil test的结果可以对源像素进行任意的rejection. stencil test把当前的stecil 值与其参考值进行比较。 两个stencil值使用当前的stencil掩码进行And计算,这样就可以指定那些位进行比较计算。

  Stencil buffer是Z Buffer的一部分。 当Z Buffer格式是D3DFMT_Z24S8, D3DFMT_Z15S1, D3DFMT_Z24X4S4,S代表的就是stencil buffer。 RS Stencil Test 控制是否使用stencil test。 RS Stencil Mask控制stencil 参考值和stencil buffer值的那些位用于比较计算。 RS Stencil Func 定义了比较函数。如果比较函数的结果是FALSE,则源像素被discarded,没有后续的处理。

 Stecil test可能产生的结果:stecil test 失败;stencil test成功而depth test失败;stencil test成功depth test也成功。这三个结果对应的渲染状态分别是RS Stencil Fail, RS Stencil Z Fail和RS Stencil Pass,他们都是从D3DSTENCILOP取值。

typedef enum _D3DSTENCILOP

{

   D3DSTENCILOP_KEEP= 1,

  D3DSTENCILOP_ZERO = 2,

   D3DSTENCILOP_REPLACE= 3,

   D3DSTENCILOP_INVERT = 6,

   D3DSTENCILOP_INCR = 7,

   D3DSTENCILOP_INCRSAT = 4,

   D3DSTENCILOP_DECRSAT = 5

} D3DSTENCILOP;

The Frame Buffer_第1张图片

 D3DCAPS9::StencilCaps 的每个位都对应设备支持一个stencil操作。

stencil buffer可以用来渲染很多特别效果。

  •  Masking Irregular Regions

  Stencil test常用的例子就是掩盖render target里面的不规则的区域。首先,我们创建一个stencil buffer的mask image,然后我们绘制被stencil test masked的几何数据。

  为了创建mask, 首先将stencil buffer清0,接下来,设置渲染状态,一般在stencil buffer渲染产生的源像素位置存储1。 这就在几何体被绘制的地方,创建了掩码。在stencil test执行之前,alpha test reject像素,复杂的几何体使用简单的纹理化而且有透明区域的四边形进行绘制。

   RS Stencil Enable = FALSE

   RS  Stencil Func = D3DCMP_ALWAYS

   RS  Stencil Ref = 1

   RS  Stencil Fail = D3DSTENCILOP_REPLACE

   RS  Stencil Z Fail = D3DSTENCILOP_REPLACE

   RS Stencil Pass =  D3DSTENCILOP_REPLACE

   接下来设置rending state以便让几何体被掩码clipped掉。使用stencil test将那些目的stencil值为1的地方被reject掉,并且保持stencil buffer值不变。当你改变mask的时候,如果你清除stencil buffer, 你可能在每一帧重用那个mask。

   RS Stencil Enable = TRUE

   RS Stencil Func = D3DCMP_NOTEQUAL

   RS  Stencil Ref = 0

   RS Stencil Fail = D3DSTENCILOP_KEEP

   RS Stencil Z FAIL=D3DSTENCILOP_KEEP

   RS Stencil PASS = D3DSTENCILOP_KEEP

  

  •  Screen Door Transparency and Stippling

 设置stencil buffer的值为0和1,并且使用stencil buffer为掩码,我们能绘制出一个透过一个门看到场景里面的外观。在stencil buffer 为0的地方,screen 被绘制,在stencil buffer值为1的地方,透过屏幕的场景被绘制。 如果我们使用透明度的alpha 混合,就能取得更好的渲染质量。这种方法能提供一种屏幕空间的stipple的模式。一个值用于打开stipple模式,另外一个用于关闭stipple模式。

  •  Filling and Reading the Stencil Buffer

 因为stencil buffer是z buffer的一部分,所以,可以跟z buffer一样的方法来访问他们的buffer。

Alpha Blending

Alpha blending将源像素和目的像素使用一个函数结合起来,计算出新的像素值。当需要显示多层效果时,经常会用到它。RS Alpha Blend Enable 控制Alpha blending的应用。

  C = <r, g, b, a>

  f = <fr, fg,fb,fa>

  Cf = <rfr,gfg,bfb,afa>

  Cs'= <func><Csfs,Cdfd>

在这里Cs是源像素的RGBA颜色值,fs 是源blending系数,Cd是目的像素的RGBA颜色值。<func>是blending函数,Cs'是alpha blending操作的最后结果。在这个方程里面颜色和blending系数都是4维向量。如果render target的目的像素没有alpha channel,它的默认值是255。

RS Src Blend 和 RS Dest Blend 用于选择blend系数对fs和fd。 他们的值都是从D3DBEND枚举值里面取。 RS Blend Op指定blend函数,默认值是D3DBLENDOP_ADD。

typedef enum _D3DBLEND

{

   D3DBLEND_ZERO = 1,

   D3DBlEND_ONE = 2,

   D3DBLEND_SRCCOLOR =3,

   D3DBLEND_INVSRCCOLOR = 4,

   D3DBLEND_SRCALPHA = 5,

   D3DBLEND_INVSRCALPHA =6,

   D3DBLEND_DESTALPHA = 7,

   D3DBLEND_INVDESTALPHA = 8,

   D3DBLEND_DESTCOLOR = 9,

   D3DBLEND_INVDESTCOLOR = 10,

   D3DBLEND_SRCALPHASAT = 11,

   D3DBLEND_BOTHINVSRCALPHA = 13
}D3DBLEND

The Frame Buffer_第2张图片

typedef enum _D3DBLENDOP

{

    D3DBLENDOP_ADD = 1,

    D3DBLENDOP_SUBTRACT = 2,

    D3DBLENDOP_REVSUBTRACT = 3,

    D3DBLENDOP_MIN = 4,

    D3DBELNDOP_MAX = 5
} D3DBLENDOP

Alpha blending 也可以执行组合计算,如下图所示。最常用的操作是over,用来组合back-to-front的每一层。列在下面表里面的操作数是已经被alpha处理过的,就是alpha通道的已经被乘到颜色通道。

 

 当在exclusivem模式上使用D3DSWAPEFFECT_FLIP或者D3DSWAP_EFFECT_DISCARD,并且设备的D3DCAPS9::Caps3的D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD被设置,设备支持目的地的Alpha。否则,应用程序应该使用D3DSWAPEFFECT_COPY或者D3DSwapEffectCopyVSync。  当D3DCAPS9::PrimitiveMiscCaps的D3DPMISCCAPS_BLENDOP被设置,设备支持扩展的blend操作。D3DCAPS9的成员SrcBlendCaps和DestBlendCaps分别定义可支持的源和目的blend系数。每个位代表一个系数。

Dithering

 在概念上,所有的像素处理都是发生在RGBA颜色的四个通道,并且每个通道一般至少8位。但是Render Target可能有少于8位的通道,如D3DFMT_R3G2B2。在一个颜色被写到render target之前,direct3d将会减少颜色通道的深度,来匹配render target的通道。当render target有一个被缩减的颜色通道时,这将导致banding artifacts。 Dithering算法则可以减少这种artifacts。

  Dithering 通过计算原始颜色和写入到render target的颜色的误差来进行操作。随着像素写入到render target,dithering算法尽量均衡的分布误差。

   RS Dither Enable enable dithering。 如果D3DCaps9::RasterCaps的D3DPRASTERCAPS_DITHER被设置, 设备将支持dithering。

MultiSampling

  使用multisampling, 将为render target的每个像素的创建多个颜色和depth/stencil buffer。 多个采样加权计算,就可以提供全屏抗锯齿和其他效果,如depth-of-field, soft shadow 和motion blur。 使用multisampling的时候,设备必须使用 discard swap effect。 Direct3D的每个render target支持2到16个采样,你可以通过IDirect3D9的接口CheckDeviceMultiSampleType来查看支持的multisampling。

   全屏抗锯齿是常用的multisampling的例子。当把RS Sample Antialias设置为true的时候,设备就enable 全屏Multisampling。 多个采样通过加权结合在一起产生平滑的多边形的边和轮廓。注意只有一个颜色值应用到所有的采样,它包括了所有的子采样。这样,pixel shader和固定功能的多纹理处理为每个像素都只执行一次,并不是像素的每个采样。但是depth和stencil需要基于每个采样来处理。

   当RS Multi Sample Antialias为False的时候,每个采样可以通过掩码 RS Multi Sample Mask控制。特别效果可以通过多个rendering pass和为每个pass使用不同的采样来实现。

    如果在render target上n个samples,渲染的时候enable第i个sample。则产生的图片有i/n强度。如果所有的sample被enable,则图片的强度跟未采样一样。

   如果D3DCAPS9::RasterCaps的DDDPRASTERCapsStretchBltMultiSample位被设置,就执行像stretchblt 操作一样的采样。全屏抗锯齿只能基于每一个frame,并不是每个primitive的。

  •    Depth of Field

  现实中的相机对场景里面的物体是有一段深度范围的。这段范围称作Depth of Field。 但是direct3d的相机模型却好像有无限的深度。 你可以通过multi sampling来模拟有限的深度。具体做法是在几个Pass里面绘制场景,在每个pass轻微的jitter 视截体。

   假定我们有16个sample,使用16个pass来渲染,每个pass都通过RS Multi Sample Mask enable一个不同的采样。 每个pass都是用稍微不一样的视截体。每个视截体都会贯穿同一个相同深度的矩形区域。这个共同的矩形局域就是焦点面,远离这个焦点面的物体将会被涂抹掉。

  •    Motion Blur

  当场景里面的物体以快于presentation的速度运动的时候,他们运动就会出现短暂的锯齿。 常用的例子是出现在19世纪电影里面的马车的轮子。在计算机图形里面,随时间采样场景的行为是发生在渲染过程中,动态渲染的每一帧只是捕捉每一个瞬间,并没有考虑物体的运动。

  使用multisampling,每帧渲染快速运动的物体多次,把每次渲染保存到采样的子集里面。

Writing to the Render Target

  在所有的frame buffer处理完毕后,它的depth, stencil , color值都会写到render target。 数据的写入是通过write mask 集合来控制的。

  RS Z write enable 控制是否把depth和stencil写入到render target的 depth/stencil buffer。 depth test 与这个write mask无关。 RS stencil Write mask 控制stencil buffer的那些位可以写。

  可以使用RS Color Write Enable选择render target的每个颜色通道。如果D3DCAPS9::PrimitiveMiscCaps的D3DPMISCCAPS_COLORWRITEENABLE被设置,设备支持颜色值的写入。

  RS Multi Sample Mask控制多采样的那几个sample被写。

 

参考文章: 浅谈抗锯齿技术

 

 

 

 

 

 

你可能感兴趣的:(算法,buffer,Blend,图形,Primitive,Direct3D)