This would definitely explain why I was never able to reproduce complaints about clipping. Does this mean Mac will remain at 0.5 now instead of the closer plane before this update?

**This is amazing!**

With the float point errors no longer showing up ~12k studs from origin, near infinite randomly generated maps will become a lot more viable!

Hey @zeuxcg Iāve noticed an issue with terrain water recently, I suspect it may have came from these updates itās a fairly big issue. When underwater you canāt see the surface of the water anymore so for example if there is a boat floating on water it looks like itās hovering in blue fog.

Issue:

Hereās an old photo I found of the water somewhere:

As you can see something has gone wrong with the surface of the water.

Thatās definitely a regression; weāll take a look, thanks!

Can you tell us how the z-fighting fixes work? Are you using a logarithmic depth buffer?

Hi @opplo, this will be fixed in an upcoming release. Iāll post here when the fix is live.

We donāt use a logarithmic depth buffer (itās not supported natively by GPUs; you can emulate this with shaders but doing so either requires a reasonably high level of tessellation of all objects, which we donāt have and donāt want, or having pixel shader output the depth value, which breaks some important GPU optimizations).

The way standard rasterization pipeline with perspective camera works with depth is:

- Depth is a 0ā¦1 value stored in a 24-bit fixed point value; this means at any point on this scale your precision is 2^-24
- Depth is computed from camera-space depth (letās call it Z) using approximately this equation: 1 - znear / z (this equation ignores zfar but for typical zfar/znear itās not very important). Note that this is 0 when z = znear, approximately 1 where z is big (zfar).

Because of this inverse mapping you have a property where the depth is mostly distributed near the camera. When z = znear depth is 0; when z = znear * 2 depth is 0.5 - so half of your depth range is right in front of the camera (in Roblox this is 0.5ā¦1 studs before the update). Next doubling gives you half of the remaining range or 25% of the full range (1ā¦2 studs); etc. You can see how for large z values you get smaller and smaller depth ranges in 0ā¦1; since precision is always 2^-24 this means the further the point is from the camera, the larger the āerror regionā (the region where other points map to the same depth value) is in studs, hence z-fighting.

This is also why we canāt really give you near plane for tuning - notice that changing near plane shifts the distribution dramatically - making it 0.1 instead of 0.5 means your āhigh precisionā regions shrink 5x, so if you had Z-fighting 1000 studs away from the camera now you have it 200 studs away.

What we did was two things - switch to a floating-point depth buffer and reverse the Z mapping. Iāll talk briefly about both.

Floating-point depth buffer stores a standard 32-bit depth value (well, 31-bit since sign bit isnāt used). Floating point representation is basically 2^e*m, where m is a 24-bit number between 1 and 2 (I am ignoring a lot of details here, no nitpicking please!). This means that in any region between two consecutive powers of two floating point numbers have the same precision which is 2^e * 2^-24. Around 1 your precision is still 2^-24, but it gets better when you get closer to 0 - when youāre in 0.5ā¦1 itās 2^-25, when youāre in 0.25ā¦0.5 itās 2^-26 etc.

So the first step is to use floating point depth. This gives us even more precision really close to camera (where depth is almost 0), and the same amount (24 bits) of precision far away. This alone isnāt interesting - we already had lots of precision close by and not much precision far away, so whatās the point?

Well, the point is that now we can flip the distribution around - instead of using 1 - zn / z, weāll use zn / z.

With a fixed point distribution this doesnāt help - you have 2^-24 precision everywhere so itās still get progressively worse the further away you go. But with a floating point distribution, the larger Z gets, the smaller depth becomes but this is precisely where floating point precision distribution shines.

If z is between zn and zn * 2, depth is between 1 and 0.5, with 2^-24 depth precision

If z is between zn * 2 and zn * 4, depth is between 0.5 and 0.25, with 2^-25 depth precision

etc.

Basically your depth precision for z between 2^k and 2^(k+1) is 2^-24 * 2^-k, which means that in terms of world-space units - z - itās pretty much constant and also very high. And note how in the closest region itās still not worse than it was - 2^-24. This means that z fighting behavior is uniform across the entire range (nit-pickers: Iām omitting details, it slightly fluctuates). Yay!

The fact that the precision of rendering improves compared to where it used to be if youāre far away from the origin is due to how projective transform works with floating point - basically some internal rasterization computations lose way less precision with the new transform. Iāll leave a description of this for some other time

Iāve learned more from this post than from being in classes all day. Cheers.

Understood a lot less of that then I hoped I would

I just noticed. Thank you very much! Welcome to the forum btw

Thanks

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.