使用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了解一下它的表现:
这两个绿色、蓝色的平面与红色的矩形的平面,都是共面的(z-fighting未处理)
下面是z-fighting处理后
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
蓝色应用设置:
_OffsetFactor = -2,_OffsetUnits = -2
偶然发现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