Skip to main content

Zfighting flickering on iOS on a single object with multiple materials

This is likely happening due to on iOS (and other platforms) floating point imprecision can cause flickering issues, as the vertices which make up the model can end up being slightly off.

E.g. the vertex on the first pass is at position 1.00000000003, but the second render pass the vertex is calculated at being in position 1.00000000001 which places it slightly behind the first vertex and therefore appears to be overlaying it.

The change in precision as the mesh or camera moves causes the flickering effect.

Possible solution:

  • Adjust the shader to give a slight offset between each of the render passes.

    For instance; on the first pass give the vertex a slight offset of 1.00000000001, and for the second pass offset the vertex by 1.00000000003. This forces the vertex to be rendered further forward in the Z order when being rendered.

    See below for a code example.

Pass 1. Line 10 pushes the vertex forward in the Z direction by 0.004 if running on a mobile device.

v2f vert(appdata v)
{
v2f o;
float3 wsNormal = normalize(UnityObjectToWorldDir(v.normal).xyz);
float4 wsPosition = mul(unity_ObjectToWorld, v.vertex);
wsPosition.xyz += wsNormal * _OutsideWallWidth;
o.vertex = mul(UNITY_MATRIX_VP, wsPosition);
o.screenCoords = ComputeScreenPos(o.vertex);
#ifdef SHADER_API_MOBILE
o.vertex.z += 0.004;
#endif
return o;

Pass 2. Line 10, pushes the vertex forward in the Z direction by 0.002 if running on a mobile device.

v2f vert(appdata v)
{
v2f o;

float3 wsNormal = normalize(UnityObjectToWorldDir(v.normal).xyz);
float4 wsPosition = mul(unity_ObjectToWorld, v.vertex);
wsPosition.xyz += wsNormal * _OutlineWidth;
o.vertex = mul(UNITY_MATRIX_VP, wsPosition);
#ifdef SHADER_API_MOBILE
o.vertex.z += 0.002;
#endif
return o;