- Home /
How do you pass data from a compute shader to a C# script
I am trying to learn how to use compute shaders to do the heavy lifting in my mesh generation, but I'm struggling to get the most basic thing to work. I'm currently just trying to pass an int array into a shader get it to, then alter and return it using an RWStructuredBuffer. However no matter what I try it only seams to fill the very first position of the returned array. I have got it to return a texture but it doesn't seam to work using the buffer. This is probably a simple mistake but I cant seem to find the issue. Thanks.
My C# script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Testing : MonoBehaviour
{
[SerializeField] private ComputeShader TestingShader;
void Start()
{
int[] ints = new int[8];
ComputeBuffer buffer = new ComputeBuffer(8, 8 * sizeof(int));
buffer.SetData(ints);
TestingShader.SetBuffer(0, "CBuffer", buffer);
TestingShader.Dispatch(0, 8, 8, 1);
buffer.GetData(ints);
buffer.Dispose();
for (int i = 0; i < ints.Length; i++)
{
Debug.Log(i + " // " + ints[i]);
}
}
}
My Compute shader:
#pragma kernel CSMain
RWStructuredBuffer<int> CBuffer;
[numthreads(8,8,1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
CBuffer[id.x] = 10;
}
Answer by Namey5 · Nov 15, 2021 at 09:03 AM
There's a few things to point out:
1. The parameters to the constructor of a ComputeBuffer are, in order, the number of items and the size of a single item. So in this case, a ComputeBuffer of 8 ints would take the following contstructor;
ComputeBuffer buffer = new ComputeBuffer (8, sizeof (int));
Because you aren't using the values in the shader, there's no need to call SetData.
2. Your threads are laid out in 2 dimensions, but you are only filling a single dimensional array - in this case it means that you will end up writing to the same points in the buffer multiple times for no reason (and your threads total (8*8)x(8*8)x1 so you end up writing way outside the bounds of the buffer). If you wanted to split the workload for this array, you could instead write to 2 groups of 4 threads on just the x axis;
// Dispatch 2 threadgroups on the x-axis
TestingShader.Dispatch (0, 2, 1, 1);
// Then in the shader, just have 4 threads on the x-axis per-group
[numthreads (4, 1, 1)]
void CSMain (...)
I personally like to fetch the number of threads per-group and dispatch the shader based on the number of threads, i.e:
// Get the kernel by name
int kernelID = TestingShader.FindKernel ("CSMain");
// Find the sizes of a thread group in each dimension
GetKernelThreadGroupSizes (kernelID, out uint xThreads, out uint yThreads, out uint zThreads);
// Then, we can dispatch the shader with the total number of threads we need to fill the array (in our case 8)
TestingShader.Dispatch (kernelID, Mathf.Max (1, (int)(8 / xThreads)), 1, 1);
Other than that, the rest of your usage looks fine to me.
Its been a while but i just implemented the changes and it works thank you.
Your answer
Follow this Question
Related Questions
Shader / Compute Shader in Unity 1 Answer
DepthNormalsTexture access in Compute Shader 0 Answers
How to disable Warnings in Compute Shaders ? 1 Answer
Unity compute shader is blocked or not after Dispatch kernel? 0 Answers
Replacing a geometry shader with a compute shader. How do I output an arbitrary number of triangles? 0 Answers