## Packing Depth into Color

New 24 bit Packing

This new approach will pack a float with range [0,1] into an RGB24 pixel.
It is designed to avoid all precision and rounding errors and give the exact same stored depth values as a D24S8 depth buffer.

Notes:
1) Subtracting multiples of 256 and 65536 from Green and Blue before scaling up reduces 32 bit float precision errors
2) Scaling by 256 or 65536 allows frac() to emulate Modulo
3) Normalizing the resulting range back to [0,1] gives full usage of 8 bits in each channel
4) Using correct unpacking factors, so unpacking float3(1, 1, 1) doesn’t overflow

I built a test harness that calculated maximum and average errors for a number of packing functions.
This approach seems to give 0e0 error across the full range.

```float3 UnitToColor24(in float depth) {

// Constants
const float3 scale  = float3(1.0, 256.0, 65536.0);
const float2 ogb    = float2(65536.0, 256.0) / 16777215.0;
const float normal  = 256.0 / 255.0;

// Avoid Precision Errors
float3 unit         = depth.xxx;
unit.gb             -= floor(unit.gb / ogb) * ogb;

// Scale Up
float3 color        = unit * scale;

// Use Fraction to emulate Modulo
color               = frac(color);

// Normalize Range
color               *= normal;

color.rg            -= color.gb / 256.0;

return color;

}//function

float ColorToUnit24(in float3 color) {
const float3 scale = float3(65536.0, 256.0, 1.0) / 65793.0;
return dot(color, scale);
}//function
```

32 bit Packing

This will pack a float with range [0,1] into an ARGB32 Pixel.

```float4 UnitToColor32(in float unit) {
const float4 factor = float4(1, 255, 65025, 16581375);
const float mask = 1.0 / 256.0;
float4 color = unit * factor;
color.gba = frac(color.gba);
color.rgb -= color.gba * mask;
return color;
}//function

float ColorToUnit32(in float4 color) {
const float4 factor = 1.0 / float4(1, 255, 65025, 16581375);
return dot(color, factor);
}//function
```

24 bit Packing

This will pack a float with range [0,1] into an RGB24 pixel.

```float3 UnitToColor24(in float unit) {
const float3 factor = float3(1, 255, 65025);
const float mask = 1.0 / 256.0;
float3 color = unit * factor.rgb;
color.gb = frac(color.gb);
color.rg -= color.gb * mask;
return saturate(color);
}//function

float ColorToUnit24(in float3 color) {
const float3 factorinv = 1.0 / float3(1, 255, 65025);
return dot(color, factorinv);
}//function
```

Notes

Using the 24 bit version matches the precision of the standard D24S8 depth stencil buffer, and releases an extra 8 bits for something else.

1. Garold Says: