Unity Shader - Offset 的测试,解决简单的z-fighting情况

使用OpenGL Polygon Offset解决简单的z-fighting,复杂的就没办法了,只能使用其他方法,如:模板缓存

其对应Unity中使用的是Shader中的Subshader/Pass Tags中的Offset factors, units
参考ShaderLab: Culling & Depth Testing中的Offset。

z-fighting

z-fighting(直译,就是z值的竞争)

原因是因为我们的不同的多边形共面时,在光栅阶段生成的fragment的屏幕xy坐标一样,但depth值又不一样的浮点误差引起的问题,然后浮点round-off的四舍五入,导致z-fighting。

来看个GIF了解一下它的表现:
Unity Shader - Offset 的测试,解决简单的z-fighting情况_第1张图片

这两个绿色、蓝色的平面与红色的矩形的平面,都是共面的(z-fighting未处理)
Unity Shader - Offset 的测试,解决简单的z-fighting情况_第2张图片
下面是z-fighting处理后
Unity Shader - Offset 的测试,解决简单的z-fighting情况_第3张图片
Unity Shader - Offset 的测试,解决简单的z-fighting情况_第4张图片

Shader

Shader "Test/Quad"
{
    Properties
    {
        _OffsetFactor ("Offset Factor", Float) = 0
        _OffsetUnits ("Offset Units", Float) = 0
        _Color ("Main Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Offset [_OffsetFactor], [_OffsetUnits]
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 wnormal : NORMAL;
            };
            fixed4 _Color;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.wnormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                return _Color * (dot(normalize(_WorldSpaceLightPos0.xyz), i.wnormal) * 0.5 + 0.5);
            }
            ENDCG
        }
    }
}

从shader代码中我们可以看到在pass tags中设置了这么一句:

Offset [_OffsetFactor], [_OffsetUnits]

两个factor,unit分别在:properties中

_OffsetFactor ("Offset Factor", Float) = 0
_OffsetUnits ("Offset Units", Float) = 0

这两个参数,可以参考:

  • 参考ShaderLab: Culling & Depth Testing中的Offset。
  • 调用glPolygonOffset()中的两个参数是什么?它们是什么意思?
  • Shader Depth Offset [Polygon Offset]
finalOffset = s * Factor + d * Unit;
//看上面的连接了解详情,这里我就不说了

所以最终我们在绿色正方形中,将设置:

_OffsetFactor = -1,_OffsetUnits = -1

Unity Shader - Offset 的测试,解决简单的z-fighting情况_第5张图片

蓝色应用设置:

_OffsetFactor = -2,_OffsetUnits = -2

Unity Shader - Offset 的测试,解决简单的z-fighting情况_第6张图片

偶然发现Vulkan中的设置类似的效果

Vulkan Tutoiral - Fixed func - Rasterizer - depth bias

rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f; // Optional
rasterizer.depthBiasClamp = 0.0f; // Optional
rasterizer.depthBiasSlopeFactor = 0.0f; // Optional

References

  • Vulkan Tutoiral - Fixed func - Rasterizer - depth bias
  • [OpenGL][SharpGL]用Polygon Offset解决z-fighting和stitching问题
  • OpenGL - Drawing Lines over Polygons and Using Polygon Offset 在多边形上画线并使用多边形偏移量
  • Shader Depth Offset [Polygon Offset]

你可能感兴趣的:(unity,unity-shader)