Jump to content
  • Advertisement
Sign in to follow this  

Encode float to RG or RGB

This topic is 2306 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was quite interested in the idea of encoding a depth value [0, 1] to either RG (16 bits) or RGB (24 bits) using GLSL. I found a couple of posts about it, and there seems to be a rather accepted algorithm as well (even though it encodes in the range [0, 1)). After analyzing the algorithms, I found that none of them was fully using the range provided by RG, RGB or RGBA. The most common check is that an encoded value of all 1s is decoded as a number bigger than 1. In other words, the maximum RG/RGB/RGBA encoded value and a bunch more are unused.

There was one solution that followed the right path, but failed in the implementation.

For reference, here are the links I found in the process:

Implementing this with integer logic is rather straight forward:
[source lang="cpp"]// Encode:
R = value &0xff;
G = (value >> 8) & 0xff;
B = (value >> 16) & 0xff;

// Decode:
value = (B << 16) | (G << 8) | R;[/source]
The trick turns then into converting that to floating point logic that can be used in GLSL. Well, here is the solution to encode it in 16 bits:
[source lang="cpp"]// Encode:
const float max16int = 256.0 * 256.0 - 1.0;
value *= max16int;
vec2 result = floor(value / vec2(256.0, 1.0));
result.g -= result.r * 256.0;
result /= 255.0;

// Decode
const float max16int = 256.0 * 256.0 - 1.0;
float result = 255.0 * dot(value, vec2(256.0, 1.0)) / max16int;[/source]
The same idea can be used to encode the value in 24 bits:
[source lang="cpp"]// Encode:
const float max24int = 256.0 * 256.0 * 256.0 - 1.0;
value *= max24int;
vec3 result = floor(value / vec3(256.0 * 256.0, 256.0, 1.0));
result.gb -= result.rg * 256.0;
result /= 255.0;

// Decode:
const float max24int = 256.0 * 256.0 * 256.0 - 1.0;
float result = 255.0 * dot(value, vec3(256.0 * 256.0, 256.0, 1.0)) / max24int;[/source]
Find attached the results of the same scene where the encoded depth is used as the fragment color. One uses RG, the other RGB.
Notice how the plane color seems to repeat in a color band fashion. The farthest red is (255, 3, 0), the next one is (254, 3, 0), then (253, 3, 0). The algorithms also encode 1 as all 1s, so no values are wasted.

As a bonus, I include a greenscale version of the scene that uses a very simple sort of encoding that roughly makes the input value linear (again, just roughly), using the following code:
[source lang="cpp"]result = pow(value, 128.0);[/source]
NOTE: This way of encoding values does not play nicely with filtering. As an example consider the RG encoding of 0.5 (which cannot be represented exactly) and that of linearly interpolating between 0 and 1 (byte values are used for clarity):

0.5: (127, 255)
0.0: (0, 0)
1.0: (255, 255)
0.5 (interpolated): (127, 127)

The real encoding of 0.5 and the interpolation of it are close, yet off (by 128 in G). If "close" is good enough, then you may use interpolation.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!