Shader Depth Offset [Polygon Offset]

本文深入探讨了Shader中的深度偏移(Polygon Offset),解释了如何在Unity和OpenGL中实现这一技术,以解决深度冲突问题,确保正确渲染近似平面的多边形。

Offset Factor, Units
factor

Specifies a scale factor that is used to create a variable depth offset for each polygon. The initial value is 0.

units

Is multiplied by an implementation-specific value to create a constant depth offset. The initial value is 0.

When GL_POLYGON_OFFSET_FILLGL_POLYGON_OFFSET_LINE, or GL_POLYGON_OFFSET_POINT is enabled, each fragment's depth value will be offset after it is interpolated from the depth values of the appropriate vertices. The value of the offset is factor×DZ+r×unitsfactor×DZ+r×units, where DZDZ is a measurement of the change in depth relative to the screen area of the polygon, and rr is the smallest value that is guaranteed to produce a resolvable offset for a given implementation. The offset is added before the depth test is performed and before the value is written into the depth buffer.


如果英文不太好理解,请参考:

每一个Fragment的深度值都会增加如下所示的偏移量:

offset = (m * factor) + (r * units)

m是多边形的深度的斜率(在光栅化阶段计算得出)中的最大值。这句话难以理解,你只需知道,一个多边形越是与近裁剪面(near clipping plan)平行,m就越接近0。

r是能产生在窗口坐标系的深度值中可分辨的差异的最小值,r是由具体实现OpenGL的平台指定的一个常量。

一个大于0的offset 会把模型推到离你(摄像机)更远一点的位置,相应地,一个小于0的offset 会把模型拉近。


注:因为深度缓存的值是非线性的,所以使用Offset的话,当相机比较近的时候,相对深度偏移(深度偏移相对于物体本身的深度值)会比较小,相机比较远时,相对深度偏移会比较大(如覆盖在本来不应该覆盖的物体上面).所以如果我们是需要设置Offset的值比较大的时候,建议直接设置相机空间或者Clip空间的Z值(线性),保证Z值的偏移总是符合预期。

深度缓存计算参考:

  1. a= zFar/( zFar- zNear)
  2. b= zFar* zNear/( zNear- zFar)
  3. z= distancefrom the eye to theobject
  4. z_buffer_value= a+ b/ z

参考:

https://docs.unity3d.com/Manual/SL-CullAndDepth.html

https://www.opengl.org/archives/resources/faq/technical/polygonoffset.htm

https://www.opengl.org/sdk/docs/man/html/glPolygonOffset.xhtml

http://www.cnblogs.com/bitzhuwei/p/polygon-offset-for-stitching-andz-fighting.html

Cesium.js:92 [Cesium WebGL] Fragment shader source: #version 300 es #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; precision highp int; #else precision mediump float; precision mediump int; #define highp mediump #endif #define LOG_DEPTH #define OES_texture_float_linear #define OES_texture_float #line 0 uniform mat4 czm_viewportTransformation; const float czm_epsilon7 = 0.0000001; uniform float czm_oneOverLog2FarDepthFromNearPlusOne; uniform float czm_farDepthFromNearPlusOne; float czm_alphaWeight(float a) { float z = (gl_FragCoord.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2]; return pow(a + 0.01, 4.0) + max(1e-2, min(3.0 * 1e3, 0.003 / (1e-5 + pow(abs(z) / 200.0, 4.0)))); } #ifdef LOG_DEPTH in float v_depthFromNearPlusOne; #ifdef POLYGON_OFFSET uniform vec2 u_polygonOffset; #endif #endif void czm_writeLogDepth(float depth) { #if (defined(LOG_DEPTH) && (__VERSION__ == 300 || defined(GL_EXT_frag_depth))) if (depth <= 0.9999999 || depth > czm_farDepthFromNearPlusOne) { discard; } #ifdef POLYGON_OFFSET float factor = u_polygonOffset[0]; float units = u_polygonOffset[1]; #if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) if (factor != 0.0) { float x = dFdx(depth); float y = dFdy(depth); float m = sqrt(x * x + y * y); depth += m * factor; } #endif #endif gl_FragDepth = log2(depth) * czm_oneOverLog2FarDepthFromNearPlusOne; #ifdef POLYGON_OFFSET gl_FragDepth += czm_epsilon7 * units; #endif #endif } void czm_writeLogDepth() { #ifdef LOG_DEPTH czm_writeLogDepth(v_depthFromNearPlusOne); #endif } #line 0 vec4 czm_out_FragColor; bool czm_discard = false; #line 0 in vec4 v_pickColor; #define FLAT #define FACE_FORWARD in vec4 v_color; out vec4 fragColor; void czm_log_depth_main() { float type = v_color.r; if (type == 1.0) { fragColor = vec4(1.0, 0.0, 0.0, 0.3); } else if (type == 2.0) { fragColor = vec4(0.0, 0.0, 1.0, 0.3); } else if (type == 3.0) { fragColor = vec4(1.0, 1.0, 0.0, 0.3); } else { fragColor = vec4(0.0, 0.0, 0.0, 0.0); } } #line 0 void czm_translucent_main() { czm_log_depth_main(); czm_writeLogDepth(); } #line 0 layout (location = 1) out vec4 out_FragData_1; layout (location = 0) out vec4 out_FragData_0; #line 0 void main() { czm_translucent_main(); if (czm_discard) { discard; } vec3 Ci = czm_out_FragColor.rgb * czm_out_FragColor.a; float ai = czm_out_FragColor.a; float wzi = czm_alphaWeight(ai); out_FragData_0 = vec4(Ci * wzi, ai); out_FragData_1 = vec4(ai * wzi); } Cesium.js:15497 An error occurred while rendering. Rendering has stopped. RuntimeError: Fragment shader failed to compile. Compile log: ERROR: 0:6: 'fragColor' : must explicitly specify all locations when using multiple fragment outputs 又报了一推错误,到底怎么写啊
最新发布
10-12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值