-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Depth pass unnecessarily low precision on Apple iPad Air 2 #9092
Comments
Interesting thing, if I use the old mod approach to packing depth, I get a bunch more precision (at least a couple more bits):
The result when using the above packing method: |
/ping @tschw |
Seems to be about numeric error. Unlike the decoder, the encoder wasn't broken, so I guess it's a good idea to do this revert, as the old implementation appears to be more robust under limited precision. However, I wonder whether there is a way to express it in a more readable way, somehow... Maybe a comment about 255 vs 256 will do - it's rather subtle... |
any update on this? |
@cnspaha My recommendation is to not use RGBA encoded depth on iOS. Even the revert doesn't actually fix the issue. |
yeah, but so the whole SAOPass isn't usable as it is on iOS, is there? |
I wrote the SAOPass and yeah we disable it by default on iOS. The reason is two fold, one the depth rgba encoding precision issues and also because it is very slow. |
I believe the issue is that the shading calculations are done in FP16 on iOS and our RGBA depth coding assumes FP32 precision or similar. IF you can rewrite the math to work on FP16 precision, it may work. I Suspect it will not fill up all RGBA channels but you may get two bytes of precision in depth. I believe on iOS the z-buffer by default is only 16 bits or 24 bits unsigned. I look forward to further development here. IT would be great to have a solution. |
@cnspaha Apparently SAO on Sketchfab works well on iOS: https://skfb.ly/6wMJ8 I wonder how they achieve accuracy in the depth pass? |
FF Shader console shows the following encode/decode functions. Could these be helpful for this issue? float decodeFloatRGBA( vec4 rgba ) {
return dot( rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0) );
}
vec4 encodeFloatRGBA( float v ) {
vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v;
enc = fract(enc);
enc -= enc.yzww * vec4(1.0/255.0,1.0/255.0,1.0/255.0,0.0);
return enc;
}
vec2 decodeHalfFloatRGBA( vec4 rgba ) {
return vec2(rgba.x + (rgba.y / 255.0), rgba.z + (rgba.w / 255.0));
}
vec4 encodeHalfFloatRGBA( vec2 v ) {
const vec2 bias = vec2(1.0 / 255.0, 0.0);
vec4 enc;
enc.xy = vec2(v.x, fract(v.x * 255.0));
enc.xy = enc.xy - (enc.yy * bias);
enc.zw = vec2(v.y, fract(v.y * 255.0));
enc.zw = enc.zw - (enc.ww * bias);
return enc;
} |
Interesting. So I guess we have the option of FP32 into 4 bytes, FP24 into 3 bytes and FP16 into 2 bytes. I Guess we should have the option to pick which resolution we want? I wonder if we can make them compatible with each other, so that FP16 encoded and unpacked by FP24 is still valid, just with reduced precision. |
vec4 encodeHalfFloatRGBA( vec2 v ) The given half float value is a |
IT is encoding two fp16 floats at once into a single vec4 and vice versa. (vec2 of fp16) <-> vec4 |
Ah, makes sense 😊. Thx! |
Here is some glsl that will encode either 1, 2, 3 or 4 bytes of depth information (properly rounded to the requested precision) with a decode that is compatible with any of these precisions.
Funny thing, I tested it on desktop and it produces acceptable results in SAO with 2, 3 and 4 bytes of depth precision. 1 byte of precision produces bad results. But 2 bytes of precision on iOS produces artifacts. This suggests that the issue is sort of complex. Either it is overflowing during the packing equation or an input value to the packing already has insufficient precision, or it is a precision issue inside of SAO itself and this whole depth rgba packing is a wild goose chase. |
I can confirm via the example webgl_materials_channels.html that the resulting depth buffer RGBA packing appears to be identical on iOS and desktop. Thus this leads me to believe the issue isn't in the RGBA packing but either in the precision of the input value (although this example seems to suggest it is at least roughly right), or it is the precision of something it is being compared against. Currently we are encoding gl_FragCoord.z. Could there be precisions issues with that? Maybe we could encode something else? The issues seem to be more severe further away from the camera, less so close up. I think that gl_FragCoord.z is normalized between 0 and 1 and that it is biased towards the near plane. Maybe instead of this term, we could just take the distance between the near and far plane and normalize that directly, rather than gl_FragCoord.z. Basically ( ( vPosition.z - near ) / ( far - near ) ) = depth. |
The other solution is to use an adaptive bias in the SAO calculation that is less sensitive away from the camera to match the precision of the gl_FragCoord.z. |
I think that is now the core issue, a lack of agreement in terms of the bias (which is constant across the near-far range) and gl_FragCoord.z (which has significantly more precision at the near plane.) Thus there are two solutions to fixing that, make bias adaptive and favoring the near plane, or make the precision of our depth buffer constant across the near-far range. Mathematically, it is easier to make the precision depth buffer fairly constant across the near-far range, so I'll try that. |
I've run out of time to explore this further, my apologies. I think my suggested depth packing routines pasted above are pretty decent and I'd recommend their adoption in Three.Js. Maybe just optimize out that swizzle that I do. |
I did some quick tests and found that the depth precision I am seeing on iOS is 1 full byte plus 3 bits of the next byte. That is 11 bits in total. The mantissa of a fp16 happens to be 11 bits: https://en.wikipedia.org/wiki/Half-precision_floating-point_format I am not sure if that is a coincidence or whether this identify that the core issue is that the gl_FragCoord.z value being written to the depth RGBA buffer is of limited precision. |
According to the WebGL 1.0 cheat sheet here: https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf The precision of gl_FragCoord is "mediump vec4 gl_FragCoord;". WHich would be the issue. mediump on iOS is 16 bits. |
three.js/src/renderers/shaders/ShaderLib/depth_frag.glsl Lines 37 to 41 in 707b44a
So instead of using |
Well, if we can calculate the exactly equivalent to gl_FragCoord.z but using uniforms that are highp in the depth material, and use that manually calculated value instead of gl_FragCoord.z, it would fix our issue. I believe to create it we can do this:
If you can check my math, it would be appreciated. |
/cc @WestLangley |
Here is what the depth channel now looks like with my proposed fix above -- basically perfect at first glance: But it isn't actually perfect on iOS. I've created an interactive test that shows that the issue is mostly fixed except for a few discontinuities in the depth map on iOS - a discontinuity in the depth render target. I am sort of stumped. I created a branch here with my fix above: https://github.com/bhouston/three.js/tree/depth_precision_test But this example demonstrates the new issue with the discontinuity. To make it very clear I reconstruct the normals from the derivatives of the depth map and on iOS you see clear the discontinuities. @WestLangley @tschw either you up for a challenge? Anyone else? Perfect results on desktop and all andriod devices: But on iOS (iPad Air 2) you can see the discontinuity as a line in the reconstructed normals from the depth render target (there are a few lines actually at different depths): |
If I change the depth encoding from the original base 256 to a modified version I created that is base 255, the artifact changes location on the mesh on iOS. In the code you can switch between them via the "USE_DEPTH_PACK_256" define in packing.glsl. This leads me to think that our encoder/decoder is slightly incorrect or at least suffers from precision issues? |
Thanks for investigating this @bhouston! |
I'm having an issue that i'm not sure is related to this - check out https://stackoverflow.com/questions/51465267/threejs-shadow-artifact-ios . The confusing part is that the currently online threejs examples work for me on iPad (with shadows) but my code isnt working on iPad (desktop is fine). I'm using threejs r90. |
@characteranimators Please, only post when you're sure the issue is related. For help requests use the forum instead. |
@characteranimators please, use the forum for help. |
Hi guys, I made some investigation of same issue #17935 and realize that this "tidy" algorithm not robust with cyclic GPGPU calculations, in this codepen https://codepen.io/munrocket/pen/vYYvXaE?editors=0010 I am created float16 modification of “tidy” algorithm with "0.5" approach: Original version: P.S. @bhouston can you check on your examples? Seems that we need to create one dimensional GPGPU example too. P.P.S Looks like @DanielSturk suggested the same and lines is gone. |
I am reverted all fixes with 0.5 rounding, because I don’t have real evidence with sao/dof/channels examples on my iPhone (gpgpu was fixed for me, but vsm not). If you have artifacts with lines on examples with packing please share! And we will check this approach again. |
Can somebody solve this problem correctly? Can we announce some prize who will solve packing / unpacking problem? This is a question that important in GPGPU, machine learning and 3d physics. |
Fixed via #18696. |
Description of the problem
The issue is that the dpeth pass has unecessarily low precision even with RGBA packing on some mobile devices, in particular the Apple iPad Air 2.
This example, set it to use the depth RGBA output.
http://threejs.orgexamples/#webgl_materials_channels
This is what it should look like (all channels are used):
This is what it ends up looking like on the Apple iPad Air 2 device (only blur channel and I think alpha channel are used):
So basically on lowp / mediump devices, depth RGBA pass, which is used by shadows and post effects does not function properly.
Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)
Apple iPad Air 2.
The text was updated successfully, but these errors were encountered: