Logarithmic zbuffer artifacts fix

In cameni's Journal of Lethargic Programmers, I've been very interested by his idea about using a logarithmic zbuffer.
在卡梅尼的《懒洋洋的程序员的日志》里,我对他关于使用对数z缓冲的思想非常感兴趣。

Unfortunately, his idea comes with a couple of very annoying artifacts, due to the linear interpolation of the logarithm (non-linear) based formula. It particularly shows on thin or huge triangles where one or more vertices fall off the edges of the screen. As cameni explains himself in his journal, basically for negative Z values, the triangles tend to pop in/out randomly.
不幸的是,由于其基于对对数(非线性的)进行线性插值的公式,他的方法会带来令人恼火的伪影(artifacts)问题。当细小的或巨大的三角形的一个或多个顶点落到屏幕之外时,这尤为突出。如卡梅尼在其日志中所解释的,基本上对于负值的Z值(摄像机后面),三角形会呈现随机的跳入/跳出显示。

It was suggested to keep a high tesselation of the scene to avoid the problem, or to use geometry shaders to automatically tesselate the geometry.
建议保持场景的高的网格细分程度(tessellation)以避免出现问题,或者使用几何着色器自动对几何体进行网格细分。

I'm proposing a solution that is much more simple and that works on pixel shaders 2.0+: simply generate the correct Z value at the pixel shader level.
我提出了一种简单得多并且在像素着色器(pixel shaders)2.0+上面能运行的解决方法:只需要在像素渲染阶段生成正确的Z值即可。

In the vertex shader, just use an interpolator to pass the vertex position in clip space (GLSL) (here I'm using tex coord interpolator#6):
在顶点着色器中,只需要使用一个插值器传递剪裁空间(GLSL)中的顶点位置到像素处理阶段(我使用的是第6个纹理坐标插值器):

void main()
{
  vec4 vertexPosClip = gl_ModelViewProjectionMatrix * gl_Vertex;
  gl_Position = vertexPosClip;
  gl_TexCoord[6] = vertexPosClip;
}

Then you override the depth value in the pixel shader:
然后你在像素着色中校正深度值:

void main()
{
  gl_FragColor = ...
  const float C = 1.0;
  const float far = 1000000000.0;
  const float offset = 1.0;
  gl_FragDepth = (log(C * gl_TexCoord[6].z + offset) / log(C * far + offset));
}

Note that as cameni indicated before, the 1/log(C*far+1.0) can be optimized as a constant. You're only really paying the price for a mad and a log.
注意到就像卡梅尼已指出的,1/log(C*far+1.0)可以优化为常量传递进来使用。你实际上只需要付出求一次mad和求一次log的代价。

Quality-wise, I've found that solution to work perfectly: no artifacts at all. In fact, I went so far as testing a city with centimeter to meter details seen from thousands of kilometers away using a very very small field-of-view to simulate zooming. I'm amazed by the quality I got. It's almost magical. ZBuffer precision problems will become a thing of the past, even when using large scales such as needed for a planetary engine.
质量出乎意料的好,我发现这个方法运行得很完美:再也没有伪影(artifacts)了。实际上,到目前为止,我进行了更深入的测试,我使用一个非常非常小的视域去模拟放大来观察几千公里以外的城市的细节,细节精度从几厘米到几米。我被这个显示质量震惊了!太神奇了!Z缓冲精确度问题将成为过去,甚至当使用非常巨大缩放比时,如在行星引擎中,也不会存在Z缓冲精确度的问题了。

There's a performance hit due to the fact that fast-Z is disabled, but to be honnest in my tests I haven't seen a difference in the framerate. Plus, tesselating the scene more or using geometry shaders would very likely cost even more performance than that.
由于fast-Z清除被禁用(因为在PS中计算深度),这就产生了一个性能问题,但是说句老实话,在我的测试中我并没有发现帧率有什么不同。而且,更多网格细分(tesselating)的场景或者使用几何着色器会付出比这更高的代价。

I've also found that to control the znear clipping and reduce/remove it, you simply have to adjust the "offset" constant in the code above. Cameni used a value of 1.0, but with a value of 2.0 in my setup scene, it moved the znear clipping to a few centimeters.
我同时还发现为控制znear clipping对它的拉近/删除,你只需要在以上代码中调整“offset”常量。卡梅尼使用了1.0这个值,但是我建立场景时使用的2.0这个值,结果它把znear clipping移动了几厘米。

Results:
Settings of the test:
- znear = 1.0 inch
- zfar = 39370.0 * 100000.0 inches = 100K kilometers
- camera is at 205 kilometers from the scene and uses a field-of-view of 0.01°
- zbuffer = 24 bits

Normal zbuffer:

Logarithmic zbuffer:

Future works
    Could that trick be used to increase precision of shadow maps?

原文链接:http://www.infinity-universe.com ... 5&topic=11849.0

阅读更多
个人分类: 图形图像技术
想对作者说点什么? 我来说一句

ZBuffer扫描线

2011年05月16日 3.57MB 下载

zbuffer算法消隐

2009年06月10日 560KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭