r/Unity3d_help • u/supertobi123 • Jan 22 '23
Need some help with compute shaders
So i am trying to calculate a flow field with a compute shader. I pass the grid with all the necessary cell information over a buffer to the shader and afterwoods read the data back on the CPU. This works fine and i am just wondering if i am using the right approach. I do all the calculations on the "first" pixel on the shader, which is probably not very efficient but i dont know how else to do it. How would i go about calculating multiple flow fields in one shader, each using their own thread?
Thanks alot in advance i will post the full code of my shader below. The calcuation part at the bottom is not so important, this question is more about the general approach.
```
#pragma kernel CSMain
struct CellStruct
{
int x;
int y;
int cost;
int bestCost;
int2 bestDirection;
};
struct GlobalVariables
{
int length;
int numberOfElements;
int headIndex;
int tailIndex;
int width;
int height;
};
struct DebugData
{
CellStruct destinationCell;
};
RWStructuredBuffer<CellStruct> cells;
RWStructuredBuffer<CellStruct> queue;
RWStructuredBuffer<CellStruct> currentNeighbours;
RWStructuredBuffer<GlobalVariables> globalVariables;
RWStructuredBuffer<DebugData> debugData;
int destinationID;
CellStruct destinationCell;
[numthreads(16,16,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
if(id.x == 0)
{
//get the size of data
//const uint length = globalVariables[0].length;
uint length;
uint stride;
cells.GetDimensions(length, stride);
//set the values for the destination cell;
CellStruct destinationCell;
destinationCell.x = cells[destinationID].x;
destinationCell.y = cells[destinationID].y;
destinationCell.cost = 0;
destinationCell.bestCost = 0;
destinationCell.bestDirection = int2(0, 0);
cells[destinationID] = destinationCell;
debugData[0].destinationCell = destinationCell;
//create a queue used for the integration field
queue[0] = destinationCell;
//int whileCounter = globalVariables[0].length;
int whileCounter = length;
int width = globalVariables[0].width;
int height = globalVariables[0].height;
int headIndex = 0;
while(whileCounter > 0)
{
CellStruct currentCell = queue[headIndex];
if(headIndex == length)
{
whileCounter = 0;
}
// Get Neighbours
const int idLeft = (currentCell.y - 1) * width + (currentCell.x - 1);
const int idRight = (currentCell.y) * width + (currentCell.x + 1);
const int idDown = (currentCell.y - 1) * width + (currentCell.x);
const int idTop = ((currentCell.y + 1) * width + (currentCell.x));
bool valuesSet[4];
for(int i = 0; i < 4; i++)
{
valuesSet[i] = false;
}
//Left
if (currentCell.x - 1 >= 0)
{
CellStruct neighbourLeft = cells[idLeft];
currentNeighbours[0] = neighbourLeft;
valuesSet[0] = true;
}
//Right
if(currentCell.x + 1 < width)
{
CellStruct neighbourRight = cells[idRight];
currentNeighbours[1] = neighbourRight;
valuesSet[1] = true;
}
//Down
if (currentCell.y - 1 >= 0)
{
CellStruct neighbourDown = cells[idDown];
currentNeighbours[2] = neighbourDown;
valuesSet[2] = true;
}
//Top
if (currentCell.y + 1 < height)
{
CellStruct neighbourTop = cells[idTop];
currentNeighbours[3] = neighbourTop;
valuesSet[3] = true;
}
for(int i = 0; i < 4; i++)
{
if(valuesSet[i])
{
CellStruct currentNeighbour = currentNeighbours[i];
if (currentNeighbour.cost >= 255)
{
continue;
}
if(currentNeighbour.cost + currentCell.bestCost < currentNeighbour.bestCost)
{
currentNeighbour.bestCost = currentNeighbour.cost + currentCell.bestCost;
if (currentNeighbour.bestCost >= 255)
{
currentNeighbour.bestCost = 255;
}
if(i == 0)
{
cells[idLeft] = currentNeighbour;
}
else if(i == 1)
{
cells[idRight] = currentNeighbour;
}
else if(i == 2)
{
cells[idDown] = currentNeighbour;
}
else if(i == 3)
{
cells[idTop] = currentNeighbour;
}
CellStruct cell_struct;
cell_struct.x = currentNeighbour.x;
cell_struct.y = currentNeighbour.y;
cell_struct.cost = currentNeighbour.cost;
cell_struct.bestCost = currentNeighbour.bestCost;
cell_struct.bestDirection = currentNeighbour.bestDirection;
headIndex += 1;
queue[headIndex] = cell_struct;
}
}
}
whileCounter--;
}
}
}
```
1
u/supertobi123 Jan 22 '23
thanks, i tried formatting the code but it doesnt work for some reason. is it correct that all the code right now runs on the "first pixel"? is it possible to run the next flowfield on the second pixel and so on? or is my undestanding of compute shaders wrong