I have been toying with ComputeShaders for a while now, and have been trying to use them to leverage the hair physics calculations I was doing in my game. The hair is based off a series of points that use springs to create hair. Each strand is a list of these points.
I had success moving the physics code into a compute shader for one strand, and would be able to calculate 10,000 hair bodies at solid 60fps on one strand, but multiple strands would crash performance.
So I need to instead run a threadgroup for each hair strand, and dispatch these hair strands x amount of times. So I make a structure of hair strands, fill it with a max-sized array of 'hair body' structs. I would then access the hair strand by the groupID, and the hair bodies by the thread index.
Theoretically this should work, but I am not having these results. Due to limitations with StrucuredBuffer element sizes being max 2048 bytes, I can only store certain lengths of hair bodies per strand. When I try to change these values and read them from my C# script, they are null.
I have provided a test scenario that should duplicate my problem. I have simplified this only to get the base functionality working, which is setting the indexes of the array within the hair strand. The code is below:
ShaderTest.cs:
public class ShaderTest : MonoBehaviour
{
public struct TestStruct1
{
public int groupID;
public int[] threadIDs;
}
public ComputeShader computeShader;
private ComputeBuffer computeBuffer;
private int kernelID;
void Start()
{
var stopWatch = new System.Diagnostics.Stopwatch();
TestStruct1[] data = new TestStruct1[256];
for (int i = 0; i < 256; i++)
{
TestStruct1 s1 = data[i];
s1.threadIDs = new int[50];
}
this.kernelID = computeShader.FindKernel("CSMain");
computeBuffer = new ComputeBuffer(256, sizeof(int) + (50 * sizeof(int)));
computeBuffer.SetData(data);
computeShader.SetBuffer(kernelID, "Buf", computeBuffer);
stopWatch.Start();
computeShader.Dispatch(kernelID, 256, 1, 1);
computeBuffer.GetData(data);
stopWatch.Stop();
Debug.Log("Took: " + stopWatch.ElapsedMilliseconds + " milliseconds to compute");
foreach(TestStruct1 d in data)
{
Debug.Log(d.threadIDs[0]); // Crashes here
}
computeBuffer.Release();
}
}
ShaderTest.compute:
#pragma kernel CSMain
struct TestStruct1
{
int groupID;
int threadIDs[50];
};
RWStructuredBuffer Buf;
[numthreads(64,1,1)]
void CSMain(int3 threadID : SV_GroupThreadID, int3 groupID : SV_GroupID)
{
if (threadID.x <= 50)
{
Buf[groupID.x].threadIDs[threadID.x] = 7;
}
}
All I am trying to do in the above code is properly index through the buffer and set each threadID to 7 for proof that this structure works. For whatever reason, it is not giving me the expected results that were so clear before.
Any help would be greatly appreciated
↧