Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Compute Shader darkening Colors.

Discussion in 'Shaders' started by khemistry, Apr 12, 2018.

  1. khemistry

    khemistry

    Joined:
    Jun 16, 2016
    Posts:
    18
    I am writing a very simple compute shader that copies the color data from a texture2D and stores it in a render texture. The issue I'm having is that the output Render Texture is much darker than the input texture2D.

    I've put a copy of the shader and implementation below.

    The image I'm using for this test is a 512x512 cloud render .png from photoshop with 32 bit color depth. The standard image format (RGB Compressed DXT1) and RGBA 32 bit cause the problem.

    I've found that if untick sRGB (Color Texture) or select RGB 16 bit or RGBA Half as the image format the image lightens in normal use, but looks correct after being processed by the compute shader. So I'm pretty convinced that my issue is the color format of the texture2D, the render texture or both.

    Playing with the render texture format can also resolve the problem. The problem exists with ARGB32 and Default (When the textures import format is RGBA 32 bit, so it looks correct). If I set the RenderTexture format to ARGB Half, ARGB Float or Default HDR it works.

    I would have expected the 32 bit Color depth import option to match the 32 bit depth render texture option. I have a solution that will work for this case but I would love to understand the problem so I can get more predictable results in the future.

    I've been reading through the documentation on Color formats in Unity here
    https://docs.unity3d.com/Manual/class-TextureImporterOverride.html
    and here
    https://docs.unity3d.com/ScriptReference/RenderTextureFormat.html

    But can't work out why I need to use the formats I do to get my expected result. If anyone knows whats going wrong or can point me at a better resource to understand the issue it would be much appreciated.

    This is the shader I'm using:
    Code (CSharp):
    1. #pragma kernel CopyTexture
    2.  
    3. Texture2D<float4> original;
    4. RWTexture2D<float4> output;
    5.  
    6. float w, h;
    7.  
    8. SamplerState _LinearClamp;
    9.  
    10. [numthreads(8,8,1)]
    11. void CopyTexture (uint2 id : SV_DispatchThreadID)
    12. {
    13.     float2 uv = float2(id.x/w, id.y/h);
    14.     float4 t = original.SampleLevel(_LinearClamp, uv, 0);
    15.     output[id] = t;
    16. }
    And a simplified version of my implementation:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CopyTextureTest : MonoBehaviour
    6. {
    7.     public Texture2D original;
    8.     RenderTexture rtOutput;
    9.  
    10.     public ComputeShader copyTextureShader;
    11.     int copyTextureKernelIndex;
    12.  
    13.     MeshRenderer myMeshRenderer;
    14.    
    15.     // Use this for initialization
    16.     void Start ()
    17.     {
    18.         rtOutput = new RenderTexture(original.width, original.height, 24);
    19.         rtOutput.enableRandomWrite = true;
    20.         rtOutput.Create();
    21.  
    22.         myMeshRenderer = GetComponent<MeshRenderer>();
    23.         myMeshRenderer.material.mainTexture = rtOutput;
    24.  
    25.         copyTextureKernelIndex = copyTextureShader.FindKernel("CopyTexture");
    26.  
    27.         copyTextureShader.SetTexture(copyTextureKernelIndex, "original", original);
    28.         copyTextureShader.SetTexture(copyTextureKernelIndex, "output", rtOutput);
    29.         copyTextureShader.SetFloat("w", original.width);
    30.         copyTextureShader.SetFloat("h", original.width);
    31.  
    32.         copyTextureShader.Dispatch(copyTextureKernelIndex, rtOutput.width / 8, rtOutput.height / 8, 1);
    33.     }
    34. }
     
    Middle-earth likes this.
  2. MarcoGiordanoMPC2

    MarcoGiordanoMPC2

    Joined:
    Jan 19, 2018
    Posts:
    43
    Bump, I am seeing the same issue would like to know how to solve that? In my case I am not using the sampler but accessing the texture directly using the pixel coordinates.
     
  3. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    327
    In the past I had similar problem. I had to convert pixel color in Compute Shader from linear to gamma space:

    float3 output = pow(input.rgb, 0.454545);
     
  4. MarcoGiordanoMPC2

    MarcoGiordanoMPC2

    Joined:
    Jan 19, 2018
    Posts:
    43
    Yes I think is related to that, in my case you need to be careful how you bind the texture, using renderdoc, if you bind the texture as Texture2D (read only) unity will bind it as sRGB texture, getting the gamma correction, if you bind it as RWTexture you get linear. In my case was a matter of binding both as RWTexture. Not sure performance wise if makes any difference, or would be better to keep it as read only and do the gamma conversion manually. I will try to do some profiling
     
  5. ObiOneStenobi

    ObiOneStenobi

    Joined:
    Jan 20, 2017
    Posts:
    6
    Thanks, worked for me!