原文:Drawing Lines over Polygons and Using Polygon Offset
在多边形上画线并使用多边形偏移量
在OpenGL中很难渲染共面图元(primitive)有两个原因:
GL_LEQUAL或GL_EQUAL的深度比较方式的设置,不能解决这个问题。这种视觉效果被称为stitching、bledding或Z fighting。
Polygon offset(多边形偏移)是OpenGL 1.0的扩展,现在被合并到OpenGL 1.1中。它允许应用程序定义一个深度偏移量,这个偏移量可以应用于已填充的图元,在OpenGL 1.1下,它可以单独启用或禁用,这取决于图元的绘制模式:fill(填充)、line(直线)或point(点模)式。因此,可以先渲染第一共面图元,在通过设置Polygon offset后,调整深度偏移后,再渲染第二个图元。
虽然多边形偏移量可以在点和线模式下改变填充图元的深度值,但在任何情况下,多边形偏移量都不会影响GL_POINTS、GL_LINES、GL_LINE_STRIP或GL_LINE_LOOP图元的深度值。如果您试图将point,line的图元覆盖在fill的图元之上,请使用多边形偏移量将fill图元的深度往远处推即可。(但它不能用于将点和线的图元往前的深度拉。)
由于多边形偏移量会改变栅格化过程中计算的正确Z值,因此存储在深度缓冲区中的结果Z值将包含此偏移量,并可能对结果图像产生影响。在许多情况下,可能会产生"bleed-through"(渗透)效果。实际上,多边形偏移量可能会导致一些图元在正常情况下无法完全通过深度测试,反之亦然。当模型相交时,多边形偏移会导致交点的绘制不准确。
多边形偏移允许应用程序使用factors因子和units单位两个参数指定深度偏移。factors因子缩放多边形相对于X或Y的最大Z斜率,units单位缩放最小可解析深度缓冲值。对结果进行求和,得到深度偏移量。这个偏移量应用于屏幕空间,通常是正Z指向屏幕。
// s:slop ⇒ 上面说的factors的slop by x,y
// d:discrete ⇒ 上面说的units深度的最小不可再分的值
finalOffset = s * factors + d * units;
//
//
/*
jave.lin 2019.07.04: 但是这两个分别:s, d是如何算的,暂时不知道
may be:
slop: s = abs(getDepthBuff(curPos.xy).x - (curFrag.clipPos.z / curFrag.clipPos.w * 0.5 + 0.5))
discrete: d = depth数值类型范围的倒数吧:
d 例如:d 数据类型假设为:float 32位
那么最小不可再分的可量化值应该是:
d = 1 / (float.MAX_V - float.MIN_V).precision(7)
对应normalized device coordinate的-1.0~1.0的话,可能就是:
d在NDC下因数值域缩小到0.0~1.0,那表示小数部分都所有最小精度就是不可再分的深度值了吧?
*/
因子参数是必需的,以确保相对相机的侧视图的fill填充图元的正确结果。在这种情况下,由两个共面图元生成的同一像素的Z值之间的差异可以达到X或Y中Z斜率的最大值。Z的斜率值将会依赖这个多边形的越接近侧视角而增大,越是前视角面对图元该值就越小。factor材质就是以这个差异值来做为深度偏移值。
(上面这段翻译好虚,求大神纠正,因为上段的原文很难理解,原文在文章开头。我就画了个图来理解,如果有错求大神纠正,谢谢)
通常的用法可能是将factor和units设置为1.0,以将图元偏移到正Z(往屏幕里推),并为填充模式启用多边形偏移。然后进行两次绘制,一次使用模型几何体,另一次使用线几何绘制。为了尽量减少对线几何绘制的干扰(模型会与线绘制有z-fighting),模型几何体绘制基本上被推到远离视线的位置,被绘制到线后面的至少一个深度缓冲单元的深度上。
(原文没有说:OpenGL 深度值越小越靠近屏幕/相机,或是越往nearPlane靠近的说法,反之远离屏幕/相机,越往farPlane靠近)
(原文没有说:启用多边形偏移的方式:glEnable的三种方式:GL_POLYGON_OFFSET_POINT, GL_POLYGON_OFFSET_LINE 和GL_POLYGON_OFFSET_FILL对应三种装配方式:GL_POINT, GL_LINE 和GL_FILL,再调用:glPolygonOffset(factors, units);参考)
(后面再叫Vulkan的Depth bias翻译:https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#primsrast-depthbias)
1.0 polygon offset扩展不允许您将偏移量应用于以line行或point点模式填充的图元。只有填充模式下的填充图元才能被偏移。
在1.0扩展中,一个偏差参数被添加到规范化(0.0 - 1.0)深度值中,而不是1.1的单位参数。通常应用程序可以通过指定0.001的偏差获得良好的偏移效果。
请参阅GLUT example示例,它呈现了两个柱体,一个使用1.0多边形偏移扩展,另一个使用1.1多边形偏移接口。
Polygon offset多边形偏移,正如它的名字一样,仅工作于多边形图元。仅对填充图元有作用:GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON。Polygon offset将会在你使用GL_FILL,GL_LINE,GL_POINT的glPolygonMode渲染它们时起作用。
Polygon offset不会影响non-polygonal非多边形的图元。GL_POINTS,GL_LINES,GL_LINE_STRIP,和GL_LINE_LOOP图元都不会应用glPolygonOffset的偏移。
您可以通过修改glDepthRange()来模拟多边形偏移的效果。例如,您可以编写以下代码:
glDepthRange (0.1, 1.0); /* Draw underlying geometry 共面绘制在下面的数值 */
glDepthRange (0.0, 0.9); /* Draw overlying geometry 共面绘制在上面的数值 */
这段代码在Z中提供一个固定的偏移量,但不考虑多边形的斜率。它大致相当于使用因子参数为0.0的glPolygonOffset。
你也可以使用模板缓冲区以多种创造性的方式绘制共面图元。OpenGL Programming Guide(OpenGL编程指南)概述了一种众所周知的方法。绘制多边形及其轮廓的算法如下:
在一些SGI OpenGL平台上,应用程序可以使用SGIX_reference_plane扩展。通过这个扩展,用户可以在对象坐标中指定一个平面方程,该方程对应于一组共面图元。您可以启用或禁用该平面。当启用该平面时,所有片段Z值将从指定的平面方程推导算出。因此,对于任何给定的片段XY位置,深度值都保证是相同的,而不管绘制它的图元是什么。