遇到问题的场景

很多时候一个物体会具有点、线、面三种模式。如果需要同时绘制多种模式,比如以面和线模式绘制两遍模型,可能会看到线不连续,当镜头推远推近时会出现闪烁现象。
闪烁原因:
直线和多边形的光栅化方式并不完全相同,在线上和多边形边缘上产生的像素的深度值通常并不相同。
但是深度是有精度限制的,距离视点越远,精度越低,由于舍入误差会造成判断错误,进而导致渲染上问题。
解决办法:
在深度检测之前,可以对zbuffer值进行一个偏移,即多边形偏移,为片元的z值增加一个适当的偏移值,把重合的z值适当地分开一些,使着重显示的直线与多边形的边缘清晰地分离开来。

多边形偏移

偏移值

offset = m ∗ factor + r∗units

在OpenGL和WebGL(以及基于它们的Three.js)中,当启用多边形偏移时,片元的深度值会根据以下公式调整:

  • m: 表示最大深度斜率(Maximum Depth Slope)的值,是一个根据当前渲染的多边形相对于视线的角度自动计算出来的值。它基本上表示该多边形表面有多倾斜;如果表面与视线平行,则m值小,如果表面近乎垂直于视线,则m值大。

  • factor: 这是一个你可以控制的变量,对应于Three.js中的material.polygonOffsetFactor。这个数值会乘以上述的m值,也就是说,它表示深度偏移量将随着多边形的视觉倾斜程度而增加。

  • r: 这是指解析度,表示深度缓冲区每个单位的更改所能表示的最小深度差异。不同的系统和深度缓冲区的配置可能具有不同的解析度。

  • units: 同样是一个你可以控制的数值,对应于Three.js中的material.polygonOffsetUnits。这个数值会乘以r,提供了一个恒定的深度偏移,这个偏移与多边形的倾斜无关。

以上结合起来,这个公式用于根据多边形的深度斜率和一个固定单位调整每个片段的深度值,以避免Z-fighting问题。通过调节factor和units参数,开发者可以微调多边形在深度缓冲区中的位置,从而减少或消除渲染过程中相互重叠的几何体之间的深度冲突。

threejs中的多边形偏移

在多边形偏移(Polygon Offset)中,“最大深度斜率”(Maximum Depth Slope)涉及到polygonOffsetFactor参数。这个参数是用来计算新的深度值时,根据多边形表面相对于视线(观察方向)的角度(也就是“斜率”或“倾斜”)来增加的一个因子。

具体地说,当使用多边形偏移时:

  • polygonOffsetFactor —— 与多边形的深度斜率成比例的偏移量。深度斜率是指多边形面相对于视线的角度;斜率越大,表明面越倾斜。
  • polygonOffsetUnits —— 向每个片段的深度值添加一个恒定值,这个值乘以一个实现特定的常数分辨率。

这两个参数共同工作,用于调整渲染多边形的深度值,以避免Z-fighting现象。
polygonOffsetFactor主要负责考虑面的倾斜程度,而polygonOffsetUnits则为所有面提供固定值的深度位移,无论其倾斜程度如何。

当你有两个几何体重叠或非常接近时,深度缓冲区的精度可能不足以区分它们。通过使用多边形偏移,可以将其中一个几何体的深度值人为地增加一点,从而确保它在渲染过程中不会与另一个几何体发生深度冲突。

这里是一个Three.js中设置多边形偏移的示例:

material.polygonOffset = true;
// 对倾斜的面进行更多的深度偏移
material.polygonOffsetFactor = 1.0; 
 // 在深度值上增加了一个恒定的偏移
material.polygonOffsetUnits = 1.0;

调整polygonOffsetFactor和polygonOffsetUnits可以帮助控制偏移量,找到适合特定场景需要的值可能需要一些实验。记住,这个技术主要用于解决Z-fighting问题,并且应该谨慎使用,因为不正确的设置可能会导致新的渲染问题。

offset的值影响了什么

在三维图形的上下文中,"offset"值是用来调整给定片段(像素)的深度值以避免Z-fighting现象。这里的"offset"不直接对应于渲染优先级,而是影响片段在深度缓冲(Z缓冲)中的位置。

当启用多边形偏移时,通过使用公式 offset = m * factor + r * units 调整的深度值会使得某些几何体在深度上稍微“推迟”或“拉近”。这样,当两个表面非常接近时,它们在渲染时不会互相干扰,导致Z-fighting。

  • 如果 offset 的值是正数,表示该片段的渲染深度被人为地增加了,使得它在深度缓冲区中更靠后——看起来好像离观察者更远。因此,它被认为在其他不进行偏移的几何体后面,从而降低了它与这些几何体发生Z-fighting的概率。

  • 相反,如果 offset 是负数,那么片段的深度会减小,使其在深度缓冲区中更往前——看起来好像离观察者更近。这在实践中不常见,因为多边形偏移通常用来避免Z-fighting,即保证一个面不会被错误地覆盖另一个面。

所以说,offset 值更大并不意味着渲染优先级更低,而是指该片段将在深度测试中更可能被视为在其他对象之后,进而可能被遮挡。在同一深度位置的两个片段进行比较时,有更高 offset 值的片段会输掉深度测试,因为它被认为是在另一个片段之后。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐