Working on some effects that require depth (Z) data in Unity, I saw that these use a method to store the depth data encoded in the RGBA channels of a regular texture.

half4 frag(v2f i) : SV_Target 
    float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.xy);
    d = Linear01Depth(d);

    return EncodeFloatRGBA(d); 

Main question: why do this? Why not just store the result in a single-channel 16-bit float (R16F) texture?

Sub question:

What also surprises me is that the data is used as if these were independent RGBA channels. (the _EncodedDepth below contains the output of function above)

half4 color = float4 (0,0,0,0);
color += 0.40 * tex2D (_EncodedDepth, i.uv);

Then after that, information is decoded into a float value again.

float4 depth = tex2D(_ProcessedDepth, i.uv);
depth.a = DecodeFloatRGBA(hrDepth);
// do something with depth.a

Does this mean that linear operations applied to the encoded values are equivalent to linear operations applied to the original float? I.e.:

DecodeFloatRGBA( 0.5 * EncodeFloatRGBA(d) ) == 0.5 * d   // really?
  • \$\begingroup\$ There are depth encodings that will encode the depth and depth^2 in the R and G channels. This helps with fuzzy shadows as after interpolation you can derive where the shadow is. \$\endgroup\$ – ratchet freak Mar 9 '15 at 10:42
  • 1
    \$\begingroup\$ Floating-point texture formats were not always supported by D3D. On older hardware you have to encode the depth to a traditional 4 channel 8-bit unorm texture if you want 32-bit depth. \$\endgroup\$ – Andon M. Coleman Mar 9 '15 at 19:21
  • \$\begingroup\$ @AndonM.Coleman , that constitutes an answer as far as I'm concerned :) \$\endgroup\$ – noio Mar 10 '15 at 10:25

Hardware has not always supported floating-point texture formats. In fact, D3D has not always supported depth textures.

When you see this sort of thing, it is usually because the application is trying to support an older API or older hardware. To store depth on these systems, they must be converted to fixed-point and packed into 4 channels of a traditional unsigned normalized (UNORM) texture.

I do not know how EncodeFloatRGBA (...) is implemented, but it is probably a dot product and a few divisions by numbers like 255.0 and 65535.0.

  • \$\begingroup\$ Adding onto this, Unity is limited in what texture formats are supported for manipulating CPU-side. So if you want to write a C# script that uses the depth of the scene, you often have to convert to an 8bpc format when handing the data back and forth. \$\endgroup\$ – DMGregory Mar 10 '15 at 16:19
  • \$\begingroup\$ Ah! And being a dot product means that an element-wise multiplication (like the 0.5 in my example) would indeed scale the decoded value too! However, an element wise MAX or MIN operation would not make sense... \$\endgroup\$ – noio Mar 10 '15 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.