Compute Shader, absolute minimum

 First make a compute shader - right click in the project window-  create shader, compute shader

The default code will look as follows


// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    // TODO: insert actual code here!

    Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}


 

To keep things simple, lets just replace that last Result... line with

   Result[id.xy]=float4(1,1,0,0);

 This will make our shader produce a yellow colour. Note the #pragma kernel is called CSMain. This is basically the function name we'll be calling from the C# script.

 

To go with the compute shader, we need a C# script that assigns the shader to our geometry. Let's use a Quad as our test geo. Again, in the project window, create a C# script, call it something and open it up.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class new : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

This looks pretty standard.. Lets add some stuff to help us use the compute shader.

public class test : MonoBehaviour
{
    public ComputeShader shader; //define a public shader which we put our compute shader script into
    public int texResolution = 512; //public integer for the "resolution"

    Renderer rend;
    RenderTexture outputTexture;


    int kernelHandle;

    // Start is called before the first frame update
    void Start()
    {
        outputTexture = new RenderTexture(texResolution, texResolution, 0);
        outputTexture.enableRandomWrite = true;
        outputTexture.Create();

        rend = GetComponent<Renderer>(); //get mesh component renderer
        rend.enabled = true; //even if user disables the mesh this makes it enabled.

        InitShader();

    }

    private void InitShader()
    {
        kernelHandle = shader.FindKernel("CSMain");
        shader.SetTexture(kernelHandle, "Result", outputTexture);
        rend.material.SetTexture("_MainTex", outputTexture);
        DispatchShader(texResolution / 8, texResolution / 8);
    }


    private void DispatchShader(int x, int y)
    {
        shader.Dispatch(kernelHandle, x, y, 1);//dispatch shader using the handle, thread groups in x,y and z

    }


    // Update is called once per frame
    void Update()
    {
        
    }
}

 So, as you can see, in Red - we create some variables, public and private, which let us specify the compute shader we're using, the resolution of the texture we're calculating, a renderer for the texture and the texture itself & a "kernelHandle", which we use to identify the Kernel in the compute shader.

In the Start function, in Green we're initialising the texture, setting it's resolution and depth, enabling reading & writing and creating it. We also get the renderer from the object we've attached this script to & enable it so that it renders even if the user disables the mesh renderer. We then call InitShader, a function we define.

In Blue, we define the InitShader function. Firstly, we access the shader and find a kernel called CSMain (remember that?) and put that "in" our kernelHandle.Then we set our compute shader to write into the outputTexture. We also put the texture into the material which we've assigned to the quad. Lastly we call DispatchShader, which we've not yet written.

In Orange, is the DispatchShader. It takes an x and y argument. These are used to specify how many threads are in x & y. We're not specifying the z threads in this basic example, so we've just set it to 1.

Something to note is we've divided texResolution by 8. This is because in the Compute Shader, we set the threads to [8,8,1]....which is 8x8x1=64 threads. Think of it as a grid. If we divide texResolution by a different value in the C# script - say 16, the steps we're taking across the texture (we are still using 8,8,1 in the compute shader) will be half the size required to make it across the whole texture.


 

 


Comments

Popular posts from this blog

setting VFX graph properties using C#