I was having a similar problem trying to make the “RayTracedSphere” node work without artifacts and I think I found a better solution.
Add a custom node that passes the argument through MakePrecise and feed everything that goes into the pixel depth offset pin through it before outputting.
return MakePrecise(Val);
This will prevent the compiler from optimizing the math differently in the base pass and the pre-pass and avoid all of the artifacts. It may slow things down in general though, avoiding some approximation stuff that somehow runs differently between the two passes?
The big benefit of this vs adding a bias to the prepass is this allows you to keep using depth equality testing (r.EarlyZPassOnlyMaterialMasking=True, important for grass and foliage performance though probably doesn’t speed anything using pixeldepthoffset since it has to calculate offset to know if it is equal?), whereas adding a bias would break it.
I found it by searching for early z pass z fighting issues and finding this thread that mentions opengl’s ‘invariant’ keyword:
https://stackoverflow.com/questions/…***-on-gtx-980
‘precise’ seems to be the HLSL equivalent, and ‘MakePrecise’ is just the engine’s wrapper around ‘precise’. It seems to add around 15 instructions to RayTracedSphere and some stuff I was using to calculate the offset, so if it adds anything close to that in the interior of the POM loop using Deathrey’s bias method will probably still be better and you’d have to do without EarlyZPassOnlyMaterialMasking unless you could choose which type of early reject you wanted per-material.