Search Unity

Compute Shader SetTexture error

Discussion in 'Shaders' started by Rukas90, Jun 15, 2020.

  1. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Hello,
    I'm new to Compute Shaders, I want to write a compute shader that modifies the texture by applying the color overlay filter effect. I tested the formula in C# and it works, but I'm unable to test it in Compute Shader as I keep receiving errors when I try to set a texture.

    The texture has read and write enabled.

    These are the errors that I receive:
    1. Attempting to bind Texture ID 1395 as UAV, the texture wasn't created with the UAV usage flag set!
    UnityEngine.ComputeShader:SetTexture(Int32, String, Texture)

    2. IndexOutOfRangeException: Invalid kernelIndex (0) passed, must be non-negative less than 1.
    UnityEngine.ComputeShader.SetTexture (System.Int32 kernelIndex, System.String name, UnityEngine.Texture texture) (at <e98ed0368295432e8c11e52d6243ee11>:0)


    If I set a render texture it works fine, but I want to set a texture instead of a render texture.

    C#
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Test : MonoBehaviour
    7. {
    8.     [SerializeField] Image output = null;
    9.     [SerializeField] Texture texture = null;
    10.  
    11.     [SerializeField] Color overlay = Color.white;
    12.     [SerializeField] ComputeShader compute = null;
    13.  
    14.     private Texture final;
    15.  
    16.     private int kernel;
    17.  
    18.     void Start()
    19.     {
    20.         kernel   = compute.FindKernel("CSMain");
    21.  
    22.         //final = new RenderTexture(image.sprite.texture.width, image.sprite.texture.height, 24);
    23.         //final.enableRandomWrite = true;
    24.         //final.Create();
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         final = texture;
    30.  
    31.         compute.SetTexture(kernel, "Result", final);
    32.         compute.SetVector("color", overlay);
    33.         compute.Dispatch(kernel, output.sprite.texture.width / 8, output.sprite.texture.height / 8, 1);
    34.  
    35.         output.sprite = Sprite.Create(final as Texture2D, Rect.zero, Vector2.zero);
    36.     }
    37. }
    38.  
    Compute Shader
    Code (CSharp):
    1.  
    2. #pragma kernel CSMain
    3.  
    4. RWTexture2D<float4> Result;
    5. float3 color;
    6.  
    7. [numthreads(8, 8, 1)]
    8. void CSMain(uint3 id : SV_DispatchThreadID)
    9. {
    10.     float r = Result[float2(id.x, id.y)].r > .5f ? 2.0f * Result[float2(id.x, id.y)].r * color.x : 1.0f - 2.0f * (1.0f - Result[float2(id.x, id.y)].r) * (1.0f - color.x);
    11.     float g = Result[float2(id.x, id.y)].g > .5f ? 2.0f * Result[float2(id.x, id.y)].g * color.y : 1.0f - 2.0f * (1.0f - Result[float2(id.x, id.y)].g) * (1.0f - color.y);
    12.     float b = Result[float2(id.x, id.y)].b > .5f ? 2.0f * Result[float2(id.x, id.y)].b * color.z : 1.0f - 2.0f * (1.0f - Result[float2(id.x, id.y)].b) * (1.0f - color.z);
    13.  
    14.     Result[id.xy] = float4(r, g, b, 1.0);
    15. }
     
  2. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    So I modified the scripts and it works now.
    The problem is that I still need to call readpixels and apply methods which are expensive.. :/

    C#
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. public class Test : MonoBehaviour
    5. {
    6.     [SerializeField] Image output = null;
    7.     [SerializeField] Texture texture = null;
    8.  
    9.     [SerializeField] Color overlay = Color.white;
    10.     [SerializeField] ComputeShader compute = null;
    11.  
    12.     private RenderTexture final;
    13.     private Texture2D generated;
    14.  
    15.     private int kernel;
    16.     private bool hasKernel = false;
    17.     private Color applied = Color.white;
    18.  
    19.     void Start()
    20.     {
    21.         kernel   = compute.FindKernel("CSMain");
    22.         hasKernel = compute.HasKernel("CSMain");
    23.  
    24.         generated = new Texture2D(texture.width, texture.height);
    25.  
    26.         final = new RenderTexture(texture.width, texture.height, 24)
    27.         {
    28.             enableRandomWrite = true
    29.         };
    30.         final.Create();
    31.     }
    32.  
    33.     void Update()
    34.     {
    35.         if (!hasKernel) return;
    36.  
    37.         bool hasChanged = overlay != applied;
    38.  
    39.         compute.SetTexture(kernel, "Result", final);
    40.         compute.SetTexture(kernel, "ImageInput", texture);
    41.         compute.SetVector("color", overlay);
    42.         compute.Dispatch(kernel, texture.width / 8, texture.height / 8, 1);      
    43.  
    44.         if (hasChanged)
    45.         {
    46.             RenderTexture.active = final;
    47.  
    48.             //Expensive part
    49.             generated.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);
    50.             generated.Apply();
    51.  
    52.             output.sprite = Sprite.Create(generated, new Rect(0.0f, 0.0f, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100.0f);
    53.         }
    54.  
    55.         applied = overlay;
    56.     }
    57. }
    58.  
    CS
    Code (CSharp):
    1. // Each #kernel tells which function to compile; you can have many kernels
    2. #pragma kernel CSMain
    3.  
    4. RWTexture2D<float4> Result;
    5. Texture2D<float4> ImageInput;
    6.  
    7. float3 color;
    8.  
    9. [numthreads(8, 8, 1)]
    10. void CSMain(uint3 id : SV_DispatchThreadID)
    11. {
    12.     float r = ImageInput[float2(id.x, id.y)].r > .5f ? 2.0f * ImageInput[float2(id.x, id.y)].r * color.x : 1.0f - 2.0f * (1.0f - ImageInput[float2(id.x, id.y)].r) * (1.0f - color.x);
    13.     float g = ImageInput[float2(id.x, id.y)].g > .5f ? 2.0f * ImageInput[float2(id.x, id.y)].g * color.y : 1.0f - 2.0f * (1.0f - ImageInput[float2(id.x, id.y)].g) * (1.0f - color.y);
    14.     float b = ImageInput[float2(id.x, id.y)].b > .5f ? 2.0f * ImageInput[float2(id.x, id.y)].b * color.z : 1.0f - 2.0f * (1.0f - ImageInput[float2(id.x, id.y)].b) * (1.0f - color.z);
    15.  
    16.     Result[id.xy] = float4(r, g, b, 1.0);
    17.  
    18. }
     
    FM-Productions likes this.