OpenGL - Drawing Lines over Polygons and Using Polygon Offset 在多边形上画线并使用多边形偏移量

原文:Drawing Lines over Polygons and Using Polygon Offset

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"(渗透)效果。实际上,多边形偏移量可能会导致一些图元在正常情况下无法完全通过深度测试,反之亦然。当模型相交时,多边形偏移会导致交点的绘制不准确。

调用glPolygonOffset()中的两个参数是什么?它们是什么意思?

多边形偏移允许应用程序使用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)

OpenGL 1.0多边形偏移扩展和OpenGL 1.1(及更高版本)多边形偏移接口之间有什么区别?

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位置,深度值都保证是相同的,而不管绘制它的图元是什么。


找到了 DX 的 Depth Bias 伪代码

jave.lin : 这部分不是翻译的内容,只不过是搬运的内容,这部分有显示 depth bias 的伪代码:D3D11_3_FunctionalSpec

在这里插入图片描述

Rasterizer State(15.1) defining Depth Biasing:
    INT     DepthBias
    float   SlopeScaledDepthBias
    float   DepthBiasClamp

Formulas:

MaxDepthSlope = max(abs(dZ/dX),abs(dz/dy)) // approximation of max depth
                                           // slope for polygon

if( SlopeScaledDepthBias != 0 )
    SlopeScaledDepthBias = SlopeScaledDepthBias * MaxDepthSlope;
    // Above: only doing SlopeScaledDepthBias math when nonzero to avoid
    // a 0*INF = NaN scenario with edge-on wireframe triangles.
    // Previously in the D3D10 spec, hardware was erroneously spec'd to
    // unconditionally multiply SlopeScaledDepthBias with MaxDepthSlope.
    // The new behavior defined here applies to any new hardware regardless
    // of what D3D API or feature level it is running against.

When UNORM Depth Buffer is at Output Merger (or no Depth Buffer):
    Bias = (float)DepthBias * r + SlopeScaledDepthBias

    Where r is the minimum representable value > 0 in the depth buffer
    format, converted to float32.

When Floating Point Depth Buffer at Output Merger:
    Bias = (float)DepthBias * 2^(exponent(max abs(z) in primitive) - r) +
            SlopeScaledDepthBias

    Where r is the # of mantissa bits in the floating point representation
    (excluding the hidden bit), e.g. 23 for float32.

Adding Bias to z:

if(DepthBiasClamp > 0)
    Bias = min(DepthBiasClamp, Bias)
else if(DepthBiasClamp < 0)
    Bias = max(DepthBiasClamp, Bias)
// else if DepthBiasClamp == 0, no clamping occurs

if ( (DepthBias != 0) || (SlopeScaledDepthBias != 0.) )
    z = z + Bias
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在`bm-polygon`组件上显示文字,你可以通过以下步骤实现: 1.通过Vue的`v-for`指令循环渲染多个`bm-polygon`组件,每个组件对应一个多边形,同时设置一个唯一的`id`属性,如下所示: ```html <template> <div> <bm-polygon v-for="(polygon, index) in polygons" :key="polygon.id" :id="polygon.id" :path="polygon.path"></bm-polygon> </div> </template> ``` 2.在每个`bm-polygon`组件后面添加一个`bm-label`组件,同时绑定`forId`属性和`content`属性。`forId`属性的值应该与对应的`bm-polygon`组件的`id`属性相同,`content`属性的值则为你要显示的文字内容,如下所示: ```html <template> <div> <bm-polygon v-for="(polygon, index) in polygons" :key="polygon.id" :id="polygon.id" :path="polygon.path"></bm-polygon> <bm-label v-for="(polygon, index) in polygons" :key="polygon.id" :forId="polygon.id" :content="polygon.label"></bm-label> </div> </template> ``` 3.在Vue组件的`data`选项中定义多个多边形对象,每个对象包含一个唯一的`id`属性、一个`path`属性表示多边形的路径、一个`label`属性表示要显示的文字内容,如下所示: ```js export default { data() { return { polygons: [ { id: 'poly1', path: [ {lng: 116.191031, lat: 39.988585}, {lng: 116.41248, lat: 39.908718}, {lng: 116.382905, lat: 39.947246} ], label: '多边形1' }, { id: 'poly2', path: [ {lng: 116.191031, lat: 39.988585}, {lng: 116.233516, lat: 39.909187}, {lng: 116.191031, lat: 39.876516}, {lng: 116.148546, lat: 39.909187}, {lng: 116.191031, lat: 39.988585} ], label: '多边形2' } ] } } } ``` 4.在`bm-polygon`组件和`bm-label`组件中分别设置样式,以及`bm-label`组件中设置`style`属性来控制文字的样式和位置,如下所示: ```css <style scoped> .bm-polygon { fill-opacity: 0.5; stroke: #333; stroke-width: 2; } .bm-label { font-size: 14px; color: #fff; background-color: #f00; padding: 5px; border-radius: 5px; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } </style> ``` ```html <bm-label v-for="(polygon, index) in polygons" :key="polygon.id" :forId="polygon.id" :content="polygon.label" style="text-align:center;"></bm-label> ``` 这样,每个多边形就可以显示对应的文字了。你可以根据具体需求来调整文字的样式和位置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值