Search Unity

Question Question about UNORM and sRGB Render Texture formats when generating Noise from Compute Shader

Discussion in 'General Graphics' started by RyanKeable, Jul 5, 2021.

  1. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    Hello!

    I have been learning how to generate noise textures with compute shaders and have run into an issue that doesn't make sense to my expectations and understanding of working with Linear colour space and textures.

    The problem exists that I want to generate my textures as linear colour space textures but Unity is requiring me to import the final texture as an sRGB texture to display the noise correctly. My understanding is that because noise is data it should be generated and imported as a linear texture.

    I have set up a few examples of what I am seeing using a simple gradient generated from a compute shader.

    Here is the basic set up:

    The compute shader:

    Code (CSharp):
    1. #pragma kernel SimpleGradient
    2.  
    3. RWTexture2D<float4> Result2D;
    4.  
    5. int SquareResolution;
    6.  
    7.  
    8. [numthreads(16, 16, 1)]
    9. void SimpleGradient(uint3 id: SV_DispatchThreadID)
    10. {
    11.     float2 gradients = id.xy / (float)SquareResolution;
    12.  
    13.     Result2D[id.xy] = gradients.x;
    14. }
    Render Texture generation code:
    Code (CSharp):
    1.         public override RenderTexture CreateRenderTexture()
    2.         {
    3.             GraphicsFormat format = GraphicsFormat.R8G8B8A8_UNorm;
    4.             RenderTexture renderTexture = new RenderTexture(rwTexture.squareResolution, rwTexture.squareResolution, 0, format);
    5.             renderTexture.enableRandomWrite = true;
    6.             renderTexture.name = name;
    7.             renderTexture.wrapMode = TextureWrapMode.Repeat;
    8.             renderTexture.filterMode = FilterMode.Bilinear;
    9.  
    10.             renderTexture.Create();
    11.  
    12.             return renderTexture;
    13.         }
    14.  

    Convert, save and re-import the Render Texture code:

    Code (CSharp):
    1.  
    2.         public static void SaveTexture2D(RenderTexture rt, string AssetName)
    3.         {
    4.             Initialize(rt);
    5.  
    6.             Texture2D newTexture = ConvertFrom2DRenderTexture();
    7.             string path = assetPath + AssetName + ".png";
    8.  
    9.             MDebug.LogPurple($"SaveTexture2D() {newTexture} at {path}");
    10.  
    11.             // other wway of writing to texture
    12.             File.WriteAllBytes(path, newTexture.EncodeToPNG());
    13.             UnityEngine.Object.DestroyImmediate(newTexture);
    14.             ReimportTexture(path);
    15.  
    16.             AssetDatabase.SaveAssets();
    17.             AssetDatabase.Refresh();
    18.  
    19.         }
    20.  
    21.         static Texture2D ConvertFrom2DRenderTexture()
    22.         {
    23.             // intitalize our new texture
    24.             int squareResolution = ActiveRenderTexture.width;
    25.             bool mipChain = false;
    26.             bool linear = true;
    27.  
    28.             Texture2D output = new Texture2D(squareResolution, squareResolution, TextureFormat.RGBA32, mipChain, linear);
    29.  
    30.             // set our RT to active to read from it
    31.             RenderTexture.active = ActiveRenderTexture;
    32.             output.ReadPixels(new Rect(0, 0, squareResolution, squareResolution), 0, 0);
    33.             output.Apply();
    34.  
    35.             return output;
    36.  
    37.         }
    38.  
    39.         static void ReimportTexture(string path)
    40.         {
    41.             TextureImporter texImporter = AssetImporter.GetAtPath(path) as TextureImporter;
    42.  
    43.             if (texImporter != null)
    44.             {
    45.                 texImporter.textureType = TextureImporterType.Default;
    46.                 texImporter.sRGBTexture = false;
    47.  
    48.                 texImporter.mipmapEnabled = false;
    49.                 texImporter.filterMode = FilterMode.Bilinear;
    50.                 texImporter.isReadable = true;
    51.  
    52.                 texImporter.textureCompression = TextureImporterCompression.Uncompressed;
    53.  
    54.                 MDebug.LogPurple($"ReimportTexture() {texImporter.sRGBTexture}, {texImporter.mipmapEnabled}, {texImporter.textureCompression}");
    55.  
    56.                 EditorUtility.SetDirty(texImporter);
    57.                 texImporter.SaveAndReimport();
    58.             }
    59.         }
    60.  
    Regardless of whether I generate my Render Texture as GraphicsFormat.R8G8B8A8_UNorm or
    GraphicsFormat.R8G8B8A8_SRGB the final Texture2D is in the same colour sRGB colour space anbd requires the sRGB conversion to display correctly:

    Here I have generated the texture using both Graphics Formats and toggling the sRGB flag in the texture import settings:
    upload_2021-7-5_9-52-40.png

    I am using Unity 2021.1.13 and the quads are being rendered with an UnlitTexture shader

    What am I missing here? Shouldn't the UNORM texture imported as linear be a linear gradient?

    Any help would be greatly appreciated!
     

    Attached Files:

    Last edited: Jul 5, 2021
  2. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    Never mind I was getting confused by perception!