ShaderMaterial and StandardMaterial Depth/Z Fighting Issue

At any given point I may have 2 objects that share mostly the same space (sometimes clones, sometimes sharing a single face), One will have DepthFunction Less and the other LessEqual on their respective materials.

When both object’s materials are StandardMaterials or both are ShaderMaterials there is no issue with how I want them to draw.

When one object has a Standard Material and the other has ShaderMaterial there is an insane amount of z/depth fighting between the two objects even though the object with DepthFunction Less should be drawn over. The properties (as far as I know) being assigned to the materials are identical after construction.

Playerground:
Matching StandardMaterials (no issue): Babylon.js Playground
Matching ShaderMaterials (no issue): https://playground.babylonjs.com/#1OH09K#2652
Mismatched Materials (issue): https://playground.babylonjs.com/#1OH09K#2653

The need for the 2 materials comes from wanting some objects to use babylon’s default shader with lighting and clipping, but others do not have that requirement and/or have unique gl_frag_color calculations.

I have tried creating a simple version of the StandardMaterial as a ShaderMaterial by attempting to hook the lighting shader includes into a lightweight custom shader but I did not have much success.

The best solution would be one that allows me to resolve this z-fighting between the 2 different material types, or at least understand why its not possible to layer the different materials like this since it works as intended when the materials are of the same type.

Did you try tweaking zoffset?
https://doc.babylonjs.com/typedoc/classes/BABYLON.Material#zOffset

The z-offsets are currently intended to be equal because of some interactions with other objects, but in my testing even modifying the zoffset of the top object to be closer still had some z-fighting issues between the 2 objects.

It’s my understanding the 2 depth functions I am using should accurately be drawing the correct object on top of the other. Modifying the z-index may be have to be a backup solution though if there is no way to get the materials to cooperate.

The first thing to do is to use exactly the same calculation in the vertex shader in both cases (standard and shader materials) when setting the gl_Position value. If the calculation is not exactly the same, you may encounter accuracy problems which will lead to triangles not being rasterized in exactly the same way. The standard material makes viewProjection * worldPoint, so you should:

As you can see, it still doesn’t work.

This is because the viewProjection matrix is passed through a uniform buffer by the StandardMaterial, but as a regular uniform by the ShaderMaterial. This is most likely a bug in Angle, and we opened a bug almost a year ago about it:

https://issues.chromium.org/issues/40934464

You can fix it by using the Scene uniform buffer in the ShaderMaterial case:

4 Likes

Exactly what I was looking for, thanks for the explanation as well!