Context: I invented a way to get ugly GI for low end platform (target being Mali 400 mp GPU) through texture feedback and texture PVS.

Problem: In order to bypass the precision limit of 8bits textures, when I accumulate light in multiple pass, I tried to encode the result as YCoCg with 16bits float packing of the Y components in the RG channel. However the result don't work as intended, in the test case I have no colors, but the decoding back to RGB show red and green results instead of shades of gray.

enter image description here

Note: the two planes on the right scene panels are test objects with shaders that validate the algorithm, the left quad show the encoding and decoding, the right one is the control objects with a regular unlit shader, as the two are similar, it shows the result are correctly encoded and decoded in this case

Here is the raw Encoded data as RG as Y, and CoCg as BA (all textures data are R8G8B8A8)

RG as 16bits luminance encoding split enter image description here

BA as Chroma CoCg encoding enter image description here

Here is the code that encode to chromalum in fragment:

            //chromaLum encoding
            float3 chromalum = RgbToYCoCg(irradiance);
            //divide lum by num ray
            chromalum.x /= numRays;
            //turn the Y (lum) into 16bits
            float4 lum = Float32ToIntrgba(chromalum.x);
            //encode split lum and chroma
            float4 result = float4(lum.x,lum.y, chromalum.y,chromalum.z);

            //return 16bit encoding to accumulation //display material must reconstruct RGB from chroma lum
            return result;

And here is the part that decode it back

            fixed4 color = tex2D(_MainTex, input.uv);
            fixed4 GI = tex2D(_GI, input.uv);   //return GI;
            //decode GI (16bit -> chromalum -> RGB)
            float luminance = IntrgbaToFloat32(float4(GI.xy,0,0));      //return luminance*16;
            float3 lighting = YCoCgToRgb(float3(luminance,GI.z,GI.w));        
            // return  float4(lighting,1);

            GI = float4(lighting,1);
            color += GI; //should mask albedo with light, not adding light, currently color is black, so add is a hack
            return color;

Function details are here:

float3 RgbToYCoCg(float3 c){
    float Y  =  0.25 * c.r + 0.5  * c.g + 0.25 * c.b;
    float Cb =  0.5  * c.r - 0.0  * c.g - 0.50 * c.b;
    float Cr = -0.25 * c.r + 0.5  * c.g - 0.25 * c.b;
    return float3(Y, Cb, Cr);

float3 YCoCgToRgb(float3 c){
    float R = c.x + c.y - c.z;
    float G = c.x       + c.z;
    float B = c.x - c.y - c.z;
    return float3(R, G, B);

float4 Float32ToIntrgba(float floatValue){
    const float toFixed = 255.0/256;
    float4 output;
    output.r = frac(floatValue*toFixed*1);
    output.g = frac(floatValue*toFixed*255);
    output.b = frac(floatValue*toFixed*255*255);
    output.a = frac(floatValue*toFixed*255*255*255);
    return output;
float IntrgbaToFloat32(float4 Value){
    const float fromFixed = 256.0/255;
    float input;
    input =
    return input;
  • \$\begingroup\$ Can you tell us anything about the texture format you're storing this in? Is there any chance gamma encoding/decoding is being applied on write, or later when you read from it? \$\endgroup\$
    – DMGregory
    Oct 30, 2022 at 16:59
  • \$\begingroup\$ Are the colours that you pass to RgbToYCoCg() all in the 0-1 range? \$\endgroup\$
    – Adam
    Oct 31, 2022 at 0:01
  • \$\begingroup\$ added image, I had an outing of this site, couldn't reach it for a while. The format is basic R8G8B8A8, I thought about gamma, but zero should still be zero right? Color should be in the 0-1 range, will double check, but since the color data are 0 (black) I don't see how this could be a problem, and the test (added with the image) reproduce color faithfully from a Rainbow tiled UV test texture. I'm kinda at loss how where the problem could be. Shame I don't have a way to log (float) number easily from shader. \$\endgroup\$
    – user29244
    Oct 31, 2022 at 14:52
  • \$\begingroup\$ Can you select your GI texture or Render texture so we can see its settings in detail — particularly, whether any compression is applied? \$\endgroup\$
    – DMGregory
    Oct 31, 2022 at 15:11
  • \$\begingroup\$ more context: The quad in the scene on the left has the texture after decoding, since I'm doing feedbacking, i have actually 2 texture for double buffering and the result of that texture in the old image is after at least 2 bounces, the background is all green because the second update (after swap) give us a whole green texture before resolving to lightmap looking unwrapping. The raw data is RG as Y and BA and CoCg. I'll add the raw data as soon as possible (done). \$\endgroup\$
    – user29244
    Oct 31, 2022 at 15:22


You must log in to answer this question.

Browse other questions tagged .