5 ms·
If you’re wondering why there’s no demo graphic, it’s because this idea is meant to produce correct results (in a bug-robust way), not anything different. One
by tylerneylon 2y ago
If you’re wondering why there’s no demo graphic, it’s because this idea is meant to produce correct results (in a bug-robust way), not anything different.
One thing that can go wrong in 3d graphics is z-fighting, where a scene has rendering artifacts because two objects are touching or intersect each other, and the triangles that are close to each other look bad when their z values (distance from the camera) hit machine tolerance differences. Basically the rendering has errors due to floating point limitations.
The post is pointing out that the float32 format represents many, many more values near 0 than near 1. Over 99% of all values represented in [0,1] are in [0,0.5]. And when you standardize the distances, it’s common to map the farthest distance you want to 1 and the nearest to 0. But this severely restricts your effective distances for non-close objects, enough that z-fighting becomes possible. If you switch the mapping so that z=0 represents the farthest distance, then you get many, many more effective distance values for most of your rendered view distance because of the way float32 represents [0,1].
- ajconway 2y agoThere is also a technique called logarithmic depth buffer (which should be self-explanatory): https://threejs.org/examples/?q=dept#webgl_camera_logarithmicdepthbuffer https://threejs.org/examples/?q=dept#webgl_camera_logarithmi...
- rendaw 2y agoThat's a pretty stunning visualization too
- indigoabstract 2y agoI wasn't aware that logarithmic depth buffer could be implemented in WebGL since it lacks glClipControl(). It's cool that someone found a way to do it eventually (apparently by writing to gl_FragDepth).
- Const-me 2y ago> apparently by writing to gl_FragDepth If they do that, this disables early Z rejection performance optimization implemented in most GPUs. For some scenes, the performance cost of that can be huge. When rendering opaque objects in front-to-back order, early Z rejection sometimes saves many millions of pixel shader calls per frame.
- xeonmc 2y agoAnd not to mention, floating point numbers are already roughly logarithmically distributed. Logarithmic distributions are most important in large differing orders of magnitude, so having the piecewise-linear approximation of logarithm is good enough for proximity buffers.
- Const-me 2y agoIndeed, logarithmic depth is pretty much useless on modern hardware, but it wasn’t always the case. On Windows, the support for DXGI_FORMAT_D32_FLOAT is required on feature level 10.0 and newer, but missing (not even optional) on feature level 9.3 and older. Before Windows Vista and Direct3D 10.0 GPUs, people used depth formats like D16_UNORM or D24_UNORM_S8_UINT i.e. 16-24 bits integers. Logarithmic Z made a lot of sense with these integer depth formats.
- indigoabstract 2y agoYeah, I agree, but I guess it's fine for a demo, which otherwise would not have been possible.
- Const-me 2y ago> which otherwise would not have been possible I wonder is it possible to implement logarithmic depth in the vertex shader, as opposed to pixel shader? After gl_Position is computed, adjust the vector to apply the logarithm, preserving `xy/w` to keep the 2D screen-space position. To be clear, I have never tried that and it could be issues with that approach, especially with large triangles. I’m not sure this gonna work, but it might.
- rowanG077 2y agoAt least on my GPU this is extremely slow compared to disabling it.
- hypertele-Xii 2y agoI'm getting obvious Z-fighting issues on that.
- wk_end 2y agoThanks - this is much clearer than the original article, which somehow never actually defines "reverse Z" before going on and on about it. Why is it that most things you render are far away rather than close? I guess I'd expect the opposite, at least depending on what you're rendering. And I'd also assume you'd want better visual fidelity for closer things, so I find this a little counter-intuitive. Are there certain cases where you'd want "regular Z" rather than "reverse Z"? Or cases where you'd want to limit your Z to [0, 0.5] instead of [0, 1]?
- CamperBob2 2y agoWhy is it that most things you render are far away rather than close? Because most things are far away rather than close...?
- wk_end 2y agoI guess…but in terms of what you see on screen most of what you see is going to be dominated by closer things, is what I’m getting at. The world is very big but right now most of what I see is relatively speaking close to me. I don’t care much about the precise positions of stuff in China right now, but as for the stuff in my apartment in Canada it’s very important for my sense of reality that the positioning is quite exact - even though there’s a lot more stuff in China.
- cornstalks 2y agoThe reason for this is in the article: > The reason for this bunching up of values near 1.0 is down to the non linear perspective divide. The function in question is nonlinear. So using "normal" z, values in the range [0, 0.5] are going to be very, very close to the camera. The vast majority of things aren't going to be that close to the camera. Most typical distances are going to be in the [0.5, 1] range. Hence, reversing that gives you more precision where it matters.
- xboxnolifes 2y agoIf you're standing outside holding a phone up to your face, you have 2 things close (hand/phone) and everything else (trees, buildings, cars, furniture, animals, etc) around you is not close.
- deleted 2y ago[deleted]
- Jasper_ 2y agoHere's a demo graphic for reversed Z in WebGPU; requires a capable browser. https://webgpu.github.io/webgpu-samples/?sample=reversedZ https://webgpu.github.io/webgpu-samples/?sample=reversedZ
- forrestthewoods 2y ago> Over 99% of all values represented in [0,1] are in [0,0.5]. Is that true if you exclude denormals?
- cornstalks 2y agoYes. Subnormals start at <1.0 * 2^(-126). Between [1.0 * 2^(-126), 0.5] there are 125x more distinct float values than there are in the range [0.5, 1].
- edflsafoiewq 2y agoYes. The floats in [0,1) come in blocks: [1/2, 1), [1/4, 1/2), [1/8, 1/4), etc. There are 2^23 floats in each block and there are 127 blocks. The reason there are so many floats in [0, 0.5] is only one block, [1/2, 1), is outside that range. If you exclude the denormals (which have a special block that stretches to 0, [0, 1/2^126)), you still just excluded a single block.
- forrestthewoods 2y agoAhhh that makes sense. That’s a much more clear explanation. Thanks!
- jstanley 2y agoThen you could show some example scenes that render wrong the "standard" way but are fixed by the reverse z idea.
- kazinator 2y agoThe demo graphic you need is not of the rendered scene, but the behind the scenes. Like the diagrams in the old Foley and Van Dam text. A visual of the perspective-transformed scene, but from a different angle, where you can see the Z coordinates.