测试不同格式下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位定点数,还有最常用的24位定点数(DXGI_FORMAT_D24_UNORM_S8_UINT) 。
测试的方法是在pixel shader里采样depth buffer,然后构建出view space position,把这个值和vertex shader里插值过来的position做对比,把两者的差别输出到RT的red分量,这样越红的部分误差就越大。测试的near-clip plane为1,far-clip plane为300,场景模型用的是DXSDK里的Columns。
测试程序画面的左半边显示精度误差,右半边显示把精度误值乘以100的结果。
运行结果:
- Linear Z,16位浮点格式

从结果可以看出16位浮点的误差还是蛮大的,越靠近far-clip plane,误差越大
- Linear Z,32位浮点格式

很明显,32位的精度很高,只有在非常接近far-clip plane时才有些许误差,理论上来讲32位定点数精度会更好。当然高精度的代价是高带宽
- Linear Z,16位定点格式

16位定点格式的精度比浮点要好,误差分布也很均匀。如果某些情况必须使用16位的buffer时,16位定点数是不错的选择。
- Perspective Z,16位浮点格式

这是所有测试结果中误差最严重的一种,这和MJP的结果是一样的,原因在于浮点数的分布和透视投影的特性。所以无论何时,都不要使用16位浮点数的非线性depth buffer。
- Perspective Z,32位浮点格式

和之前的32位线性buffer一样,精度很高
- Perspective Z,16位定点格式

这个测试结果表明:对于非线性的depth buffer,16位定点数格式远好于16位浮点数,并且在靠近near-clip plane的地方,比16位的线性buffer精度更好,缺点就是在靠近far-clip plane时精度就下降很多,这是透视投影的特性导致的
- Perspective Z,24位定点格式

这是最常用的格式,从结果来看和32位的差不多。主要是这个测试结果的far-clip值并不大,误差值不容易察觉,实际的误差值在0.005%左右,如果far-clip非常大的话,误差就会变大。
- 分析总结
为什么16位浮点数非线性buffer的误差这么之大?原因有两个:1.透视投影的特性 2.浮点数的精度分布
根据透视投影矩阵,可以推导出view space z对应z buffer的函数图像如下

可以看出在靠近near的地方,曲线非常陡峭,斜率很大,在靠近far时,曲线很平稳,斜率很小。所以透视投影对于近处的物体有很好的精度,但随着越来越靠近far时,精度就会不断下降。
far和near的比值决定了曲线的陡峭程度,如果far/near越大,那么曲线就越陡,z buffer的精度越差。比如16位浮点格式,当far/near为600时,误差约为1%,当far/near为8000时,误差高达10%。
对于浮点类型,其值在[0,1] 区间并不是均匀分布的,实际上是在靠近0时,精度最好,远离0时,精度下降。如下图:

而浮点类型的这种分布,和透视投影的特性刚好是相矛盾的——在靠近near(0)时,斜率很大,view space z只要变换一点点,z buffer就能有很大变换,所以并不需要很高的精度,而在远离near时,斜率很小,就需要更多的精度。16位浮点本身精度就不如32位,再加上浮点的分布和透视投影特性,更加加剧了误差,所以16位float的非线性buffer的精度才会如此之差。
这也说明了为什么定点数的精度要好于浮点数——因为定点数是均匀分布的,不会有浮点数那样的问题。
当使用非线性的浮点buffer时,实际上浮点数的很多精度都被浪费了。所以有一种做法就是把near plane和far plane对换,这样近处的物体映射到1附近,远处的物体映射到0附近,这就刚好符合了浮点数的精度分布,这在精度不够时是一种很有效的优化手段。但在用的时候需要把depth test的条件从less改为greater,z buffer中的值变成了越大越靠近。
- Position Buffer的精度
MJP的博客里还测试了把position直接存储到texture的精度,他测试的格式是DXGI_FORMAT_R16G16B16A16_FLOAT 效果如下(左下角和右下角分别为误差和误差乘以100):

可以看出误差并不小,结果和用16位浮点depth buffer构建position是差不多的,所以把position存到texture是糟糕的选择,不仅精度不够,而且占用带宽。
- 线性和非线性的buffer
前面所说的线性和非线性buffer,指的是在view space中,perspective z的buffer不是线性的,view space z的buffer是线性的。但是在屏幕空间,情况相反,perspective z的buffer是线性的,而view space z的buffer不是线性的。Why ? 因为在屏幕空间,1/z才是线性的,而perspective z本身就是1/z的形式,所以是线性的,view space z不是1/z的形式,所以不是线性的。
屏幕空间中是线性的有什么好处?很多屏幕空间的渲染就能收益,线性就意味着位于同一图元表面的pixel的delta z是相同的(ddx(z), ddy(z)),那么边缘检测之类的就变得很容易。而且屏幕空间的线性意味着插值简单,无需做透视校正,那么对硬件是很友好的。
关于线性和非线性,Humus的“A couple of notes about Z”中有详细的论述。
- 总结
1. 尽量减小far/near的值。
2. 16位浮点数的非线性depth buffer精度最差,避免使用。
3. 浮点格式精度不够时,考虑交换near plane和far plane来提高精度
4. 在屏幕空间中,perspective z buffer是线性的,view space z buffer不是。
参考资料:
https://mynameismjp.wordpress.com/2010/03/22/attack-of-the-depth-buffer/
https://developer.nvidia.com/content/depth-precision-visualized
https://www.sjbaker.org/steve/omniv/love_your_z_buffer.html
http://www.humus.name/index.php?page=Comments&ID=255
http://dev.theomader.com/linear-depth/
测试不同格式下depth buffer的精度的更多相关文章
- D3D depth buffer的预览
在使用D3D开发游戏的过程中,很多情况下都会用到depth buffer来完成特定的效果,比如DOF,Shadows,SSAO等等.在这些情况下我们就可能需要预览depth buffer来确定它是正确 ...
- [Zz] DX depth buffer
声明:本文完全翻译自DX SDK Documentation depth buffer,通常被称为z-buffer或者w-buffer,是设备的一个属性,用来存储深度信息,被D3D使用.当D3D渲染一 ...
- Caffe学习系列(12):不同格式下计算图片的均值和caffe.proto
均值是所有训练样本的均值,减去之后再进行训练会提高其速度和精度. 1.caffe下的均值 数据格式是二进制的binaryproto,作者提供了计算均值的文件compute_image_mean, 计算 ...
- gpt格式下通过U盘装win7系统
首先下好一个64位的win7系统,可以是ghost版的,然后放到你的U盘,在U盘的根目录下添加bootmgr.efi,bootx64.efi.shell.efi这几个文件,其它都不要管,重启,你就在g ...
- 从depth buffer中构建view-space position
观察透视投影矩阵: 对于x和y,矩阵变换只是一个缩放系数,那么逆变换就是缩放系数的倒数,所以 设Xndc Yndc为NDC空间中的XY坐标,Xview Yview Zview为view space中的 ...
- Cesium 中由 Logarithmic Depth Buffer 引起的模型显示不完整的问题
当 Cesium 单个模型过长时,会遇到某些视角模型显示不完整的问题,如下图所示: 经过在官方论坛上询问,该问题由 viewer.scene.logarithmicDepthBuffer 开启造成,关 ...
- click 在网页测试手机模式下无效,不能执行。调成非手机模式即可
click 在网页测试手机模式下无效,不能执行. 调成非手机模式即可
- Depth Buffer
Up until now there is only one type of output buffer you've made use of, the color buffer. This chap ...
- 用实力燃爆暑期丨i春秋渗透测试工程师线下就业班开课了!
i春秋&赛虎暑期渗透测试工程师线下就业班开课了! 本期开班地点:北京,面授脱产:四个月. 如果这次没来得及报名的同学也可以选择9月份广州的班次,具体开班时间请咨询谢老师:18513200565 ...
随机推荐
- PHPcms 把盛大登陆换成人人网登陆
首先要确保你的 phpcms是比较新的版本, v9.3以后的吧 这里说明一个函数 rawurlencode() 本函数将字符串编码成 URL 的字符串专用格式,特殊的字符会转换成百分比符号后面加上二个 ...
- Struts2框架学习(三) 数据处理
Struts2框架学习(三) 数据处理 Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:Value ...
- origin中把多个拟合曲线放在一张图
双击其中一个.或者New一个graph.这里直接双击其中一个图. 右键,找到layer contents. 可以看到,一个scatter配一个polynomial fit line.把剩下的B,C,D ...
- I帧/P帧/B帧---术语解释
视频压缩中,每帧代表一幅静止的图像.而在实际压缩时,会采取各种算法减少数据的容量,其中IPB就是最常见的. 简单地说,I帧是关键帧,属于帧内压缩.就是和AVI的压缩是一样的. P是向前搜索的意思.B ...
- android:在ViewPager中使用Button
最近在项目用用到ViewPager ,其中页面包含有Button,因为之前也有使用个ViewPager ,所以这个也照搬之前的方式,测试后发现点击button无法执行,这个button是在第一页面的默 ...
- TypeScript教程2
在TS中,我们允许开发人员使用面向对象技术. 1.类让我们看看一个简单的基于类的例子: class Greeter { greeting: string; constructor(message: s ...
- 通过判断cookie过期方式向Memcached中添加,取出数据(Java)
应用场景:在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载.缓存是解决这个问题的好办法.但是ASP.NET中的虽然已经可以实现对页面局部进行缓存,但还是不够 ...
- Professional C# 6 and .NET Core 1.0 - 38 Entity Framework Core
本文内容为转载,重新排版以供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - 38 Entity Framework ...
- ArcGIS制图表达Representation-制图表达介绍
ArcGIS制图表达技术-制图表达介绍 by 李远祥 在基于GIS数据的制图中,大部分都是使用的数据+符号应用的这种模式.这种模式已经被应用很多年,而且也是非常成熟.对应在ArcGIS体系里面,就是数 ...
- 解析.NET对象的跨应用程序域访问(下篇)
转眼就到了元宵节,匆匆忙忙的脚步是我们在为生活奋斗的写照,新的一年,我们应该努力让自己有不一样的生活和追求.生命不息,奋斗不止.在上篇博文中主要介绍了.NET的AppDomain的相关信息,在本篇博文 ...