0
votes

Can someone who has experience with compute shaders explain what is an id parameter?

void CSMain (uint3 id : SV_DispatchThreadID)

I believe it's an index, but an index of what? How do you manipulate certain texture pixels in compute shader? How do you access them?

Let's say I have an 8x8 image and whenever I click on the texture I want to colorize the clicked on pixel and its surrounding pixels depending on the radius.

E.g. enter image description here

I have created this simple EditorWindow, where I listen for clicks and if I click I Dispatch the compute shader to process all the data

using System;
using System.IO;
using UnityEditor;
using UnityEngine;

public class DrawingEditor : EditorWindow
{
    bool pressed = false;

    ComputeShader computeShader = null; 
    RenderTexture dest;

    bool dragged = false;

    int radius = 5;
    Color color = Color.black;

    [MenuItem("Window/Drawing Editor")]
    public static void Open()
    {
        var window = EditorWindow.GetWindow<DrawingEditor>();

        window.ShowUtility();
    }

    private void OnEnable()
    {
        dest = new RenderTexture(1200, 514, 0, RenderTextureFormat.ARGB32, 0);
        dest.enableRandomWrite = true; dest.Create();
    }

    private void OnGUI()
    {
        var tex = new Rect(0, 0, 350, 150);

        GUI.DrawTexture(tex, dest);

        var shader = new Rect(25, tex.y + tex.height + 25, tex.width - 50, 17);

        computeShader = (ComputeShader)EditorGUI.ObjectField(shader, new GUIContent("Shader"), computeShader, typeof(ComputeShader), allowSceneObjects: false);

        var rad = new Rect(25, shader.y + shader.height + 25, tex.width - 50, 17);
        radius = EditorGUI.IntSlider(rad, radius, 1, 50);

        var col = new Rect(25, rad.y + rad.height + 25, tex.width - 50, 17);
        color = EditorGUI.ColorField(col, color);
        
        var e = Event.current; bool paint = false;

        if (e.rawType == EventType.MouseDown)
        {
            pressed = true;
        }
        else if (e.rawType == EventType.MouseUp && pressed)
        {
            if (!dragged)
            {
                paint = true;
            }
            pressed = false; dragged = false;
        }
        if (e.rawType == EventType.MouseDrag && pressed)
        {
            paint = true;
            dragged = true;
        }
        if (paint)
        {
            Paint(new Vector2Int(Convert.ToInt32(e.mousePosition.x), Convert.ToInt32(e.mousePosition.y)), tex);
        }    
    }
    void Paint(Vector2Int mousePos, Rect canvas)
    {
        var p = mousePos;

        var xP = p.x / canvas.width;
        var yP = p.y / canvas.height;

        if (computeShader)
        {
            computeShader.SetTexture(0, "Result", dest);
            computeShader.SetFloat("mouseX", dest.width * xP); computeShader.SetFloat("mouseY", dest.height * yP);
            computeShader.SetInt("radius", radius);
            computeShader.SetVector("color", color);
            computeShader.SetInt("width", dest.width); computeShader.SetInt("height", dest.height);

            computeShader.Dispatch(0, dest.width / 8, dest.height / 8, 1);

            Repaint();
        }
    }
}

And this is the compute shader:

#pragma kernel CSMain

RWTexture2D<float4> Result;
float mouseX, mouseY;
int radius;
float4 color;
int width, height;

float4 Calc(uint x, uint y, float4 de)
{
    if (x >= mouseX - ((float)radius / 2) && x < mouseX + radius)
    {
        if (y >= mouseY - ((float)radius / 2) && y < mouseY + radius)
        {
            return color;
        }
    }
    return de;
}

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    Result[id.xy] = Calc(id.x, id.y, Result[id.xy]);
}

Nothing is happening when I dispatch the compute shader, so I reckon I am doing something really wrong here.

How do you alter specific pixels? Can someone help me understand how things work with compute shaders?

1

1 Answers

0
votes

Well since I haven't got any answers I did some trial and error and I managed to create something that works. I'm still miles away from fully grasping the compute shaders as a whole and how they work, but I'm slowly starting to understand a little bit.

This is the code I've used if anyone is interested:

#pragma kernel CSMain

RWTexture2D<float4> Result;
float mouseX, mouseY;
int radius;
vector<float, 4> color;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    if (id.x > mouseX - (radius / 2) && id.x < mouseX + (radius / 2) && id.y > mouseY - (radius / 2) && id.y < mouseY + (radius / 2))
        Result[id.xy] = color;
}

Also, I passed mouse positions as floats which needed to be integers instead.