[Zz] DX depth buffer

声明:本文完全翻译自DX SDK Documentation

depth buffer,通常被称为z-buffer或者w-buffer,是设备的一个属性,用来存储深度信息,被D3D使用。当D3D渲染一个场景到target surface的时候,它会使用depth-buffer surface上的数据,来决定被rasterized三角面片的pixel间的遮挡关系。

当depth buffer被开启,rendering surface上的每一个点都会被检测。depth buffer上的值可以是点的z坐标值,也可以是在投影空间中齐次坐标的w值。用z坐标的叫z-buffer,用w坐标值的角z-buffer。它们各有优缺点。

在深度测试开始的时候,depth buffer上的深度值被设置为场景中的最大值。rendering surface上的颜色值被设置为背景色或者背景纹理颜色。场景中的每一个三角面片都会被检测它是否跟当前的(x,y)坐标相交,如果相交,z或者w值会被检测是否比depth buffer中对应的值小,如果小,它就会被写入到depth buffer中,三角面片的颜色值会被写入到当前点的rendering surface上。

我们可以通过改变渲染状态D3DRS_ZFUNC的值,来改变D3D的比较方法,以影响depth buffer的值和render-target surface。

市面上的几乎所有减速器都支持z-buffering,使z-buffer是如今最常见的depth buffer类型。然而,无所不在的z-buffer有它的缺点。产生的z值往往不是平均分布在z-buffer 范围内(典型的是,0.0~1.0,包括0跟1)。特别的是,far跟near clipping plane非常影响z值的分布。在支持最普遍的16位depth buffer中,很容易引起远处应该被隐藏的物体显示在rendering surface上。

w-buffering就不存在这个问题,它的值会均匀分布。尤其,far跟near clipping planes的比率不再会影响w值的分布,使程序可以支持非常大的比值。当然,z-buffering不是完美的,它会引起近处本该隐藏的物体显现。另一个缺点是,w-buffering需要硬件支持,并没有z-buffering支持的那么普遍。

在渲染的时候,z-buffering是有overhead的。

Querying for Depth Buffer Support(D3D9)

如同任何特性,程序使用的驱动可能并不支持所有类型的depth buffering。总是要检查驱动的能力,尽管大部分驱动支持z-based buffering,但是并不一定支持w-based buffering。如果你尝试打开一个不支持的特性,驱动并不会崩溃。驱动可能fall back到一个它支持的depth buffering。

在创建设备之前,你可以使用D3D对象检查一下所支持的depth buffering。如果D3D对象告诉说,它支持depth buffering,那么它创建的任何设备都会支持的。

// The following example assumes that pCaps is a valid pointer to an
// initialized D3DCAPS9 structure
if(FAILED(m_pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal,
                                                                        pCaps->DeviceType,
                                                                        AdapterFormat,
                                                                        D3DUSAGE_DEPTHSTENCIL,
                                                                        D3DRTYPE_SURFACE,
                                                                        D3DFMT_D16)))
        return E_FAIL;

同样,我们可以检测depth-stencil的支持情况。

// Reject devices that cannot create a render target of RTFormat while
// the back buffer is of RTFormat and the depth-stencil buffer is
// at least 8 bits of stencil
if(FAILED(m_pD3D->CheckDepthStencilMatch(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, RTFormat, D3DFMT_D24S8)))
     return E_FAIL;

Create a Depth Buffer

depth buffer是设备的一个属性。要创建一个被D3D管理的depth buffer,对D3DPRESENT_PARAMETERS结构体进行恰当设置。

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

通过设置EnableAutoDepthStencil = TRUE,我们命令D3D管理程序的depth buffer。AutoDepthStencilFormat = D3DFMT_D16 必须是一个有效并支持的depth buffer 格式。D3DFMT_D16是一个16位的depth buffer。

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3dDevice ) ) ) return E_FAIL;

如上代码会创建一个,创建depth buffer的设备。

depth buffer会自动被设为设备的render target。当设备重设后,depth buffer会被自动释放并重新创建,以新的大小。

要创建一个新的depth buffer surface,使用IDirect3DDevice9::CreateDepthStencilSurface。
要将新的depth buffer设置到设备上,用IDirect3DDevice9::SetDepthStencilSurface。
要使用depth buffer在我们程序中,我们需要打开 depth buffer。

Enabling Depth Buffering

在创建好depth buffer后,如果要打开depth buffer,我们可以调用IDirect3DDevice9::SetRenderState方法。设置render state的D3DRS_ZENABLE。
D3DZB_FALSE
Disable depth buffering.
D3DZB_TRUE
Enable z-buffering.
D3DZB_USEW
Enable w-buffering.
 
Retrieving a Depth Buffer

获取一个指向depth buffer surface的指针。
LPDIRECT3DSURFACE9 pZBuffer;

m_d3dDevice->GetDepthStencilSurface( &pZBuffer );

Clearing Depth Buffer

许多C++程序在渲染新的frame前都会清理depth buffer。我们可以显式地清理depth buffer通过调用IDirect3DDevice9::Clear,指明D3DCLEAR_ZBUFFER标签,同时,我们可以指定一个任意深度值。

Changing Depth Buffer Write Access

默认情况下,D3D是允许写depth buffer。不过,我们可以disable这个写的权限,来获得某些特效。

通过调用IDirect3DDevice9::SetRenderState,用参数D3DRS_ZWRITEENABLE,值为0。

Changing Depth Buffer Comparison Functions

默认情况下,在rendering surface上进行深度测试时,如果相应的深度值(z/w)小于depth buffer上的,D3D系统就会更新render-target上相应的点。我们可以更改深度值的比较方法。

通过调用IDirect3DDevice9::SetRenderState,用参数D3DRS_ZFUNC,值为D3DCMPFUNC枚举类型中一个。

[Zz] DX depth buffer

时间: 2024-08-04 07:40:48

[Zz] DX depth buffer的相关文章

测试不同格式下depth buffer的精度

这篇文章主要是参考MJP的"Attack of The Depth Buffer",测试不同格式下depth buffer的精度. 测试的depth buffer包含两类: 一是非线性的depth buffer,存储着perspective z(也就是最常用的,透视投影后归一化的z/w的buffer),二是线性的depth buffer,存储着view space z(这里的线性指的是在view space 中是否线性).测试的格式包括16位浮点数,32位浮点数,16位定点数,还有最常

从depth buffer中构建view-space position

观察透视投影矩阵: 对于x和y,矩阵变换只是一个缩放系数,那么逆变换就是缩放系数的倒数,所以 设Xndc Yndc为NDC空间中的XY坐标,Xview Yview Zview为view space中的坐标,则 所以 所以已知XY的NDC坐标和view space z,就能求出view space position,写成代码就是: float M = tan(fov*0.5f)*aspect; float N = tan(fov*0.5f); float3 GetViewSpacePos(floa

D3D depth buffer的预览

在使用D3D开发游戏的过程中,很多情况下都会用到depth buffer来完成特定的效果,比如DOF,Shadows,SSAO等等.在这些情况下我们就可能需要预览depth buffer来确定它是正确的,以免导致后续运算渲染出错.此时有一个问题就出现了,因为原始的depth buffer中保存的depth不是线性的.我们知道,世界坐标系下的顶点在经过视图变换后会被转换到视图空间,此时摄像机在原点,并且我们为摄像机定义了一个近平面和一个远平面: 在经过视图变换后,接着执行的就是投影变换,D3D的透

DX & OpenGL 's depth

Some math I did ... (not 100% verified, but looks like it works) n = near f = far z = depth buffer Z-value EZ = eye Z value LZ = depth buffer Z-value remapped to a linear [0..1] range (near plane to far plane) LZ2 = depth buffer Z-value remapped to a

DX笔记之一---Direct3D基础

一.预备知识 1.表面 表面就是Direct3D用于储存2D图像数据的一个像素矩阵.width和height以像素为单位,pitch以字节单位,用接口IDirect3DSurface来描述表面 LockRect:该方法用于获取指向表面存储区的指针,通过通过指针运算,可对每个像素进行读写操作: UnlockRect:配对使用,调用lock必须unlock,解除对表面存储区的锁定: GetDesc: 获取表面的描述信息,通过填充D3DSURFACE_DESC; //Assume _surface i

引擎设计跟踪(九.14.3.1) deferred shading: Depthstencil as GBuffer depth

问题汇总 1.Light support for Editor编辑器加入了灯光工具, 可以添加和修改灯光. 问题1. light object的用户互交.point light可以把对应的volume (wireframe sphere/cone)画出来用于用户选中, 但是光源太多的时候, 球就有点凌乱了. 所以使用了HUD, 只要选中HUD就会选中灯光, 只有灯光被选中的时候才显示volume. 另外, 编辑器里面的很多"不可见"的逻辑对象都有这种需求, 虽然现在还没有. 另外, 可

OpenGL ES 3.0之Fragment buffer objects(FBO)详解(一)

片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓冲: OpenGL ES •• Color buffer颜色缓冲 •• Depth buffer深度缓冲 •• Stencil buffer模板缓冲 创建缓冲区 OpenGL ES 是一个交互式的渲染系统,假设每帧的开始,你希望初始化所有缓冲区中数据的默认值.调用glClear 函数来清除缓冲区内容,参数mask 指定清除的缓冲区. 你可能不要求清除每一个缓冲区,不在同时清除它们.但如

【OpenGL】OpenGL帧缓存对象(FBO:Frame Buffer Object) 【转】

http://blog.csdn.net/xiajun07061225/article/details/7283929/ OpenGL Frame BufferObject(FBO) Overview: 在OpenGL渲染管线中,几何数据和纹理经过多次转化和多次测试,最后以二维像素的形式显示在屏幕上.OpenGL管线的最终渲染目的地被称作帧缓存 (framebuffer).帧缓冲是一些二维数组和OpenG所使用的存储区的集合:颜色缓存.深度缓存.模板缓存和累计缓存.一般情况下,帧缓存完全 由wi

OpenGL学习脚印: 帧缓冲对象(Frame Buffer Object)

写在前面 一直以来,我们在使用OpenGL渲染时,最终的目的地是默认的帧缓冲区,实际上OpenGL也允许我们创建自定义的帧缓冲区.使用自定义的帧缓冲区,可以实现镜面,离屏渲染,以及很酷的后处理效果.本节将学习帧缓存的使用,文中示例代码均可以在我的github下载. 本节内容整理自 1.OpenGL Frame Buffer Object (FBO) 2.www.learnopengl.com Framebuffers FBO概念 在OpenGL中,渲染管线中的顶点.纹理等经过一系列处理后,最终显