So I have been making an octree to accelerate a ray tracing compute shader, but I have hit a major block on the last hurdle to testing it, actually sending it to the compute shader. What I am trying to do is send a List(with OctreeData being a struct with 2 arrays in it among other things) to a compute shader via a structured buffer, but turns out this is not blittable(so cant be sent). Is there any way for me to be able to send this at all, or do I have to unroll the arrays into individual elements(and then unroll 512 loops worth of code in the shader)? alternatively, can I send an array within a list easily to a compute shader? Thank you for any help, as this is driving me nuts, as ive come so close to testing it
Incase it matters, extra information: I do know the size of the arrays in the struct, I just dont know how to tell it that and make it blittable, and one array is for storing children nodes(will have 8 integers always in it), and the other one is to index which triangles in a mesh a leaf node(final nodes) contains(will have 16 integers always in it)
I’m sure you’ve either solved this or given up by now, but I found your question while working on my own GPU octree code, and others might do the same.
The below struct definition (1) allows the HLSL compute shader to define it’s own struct using an array; (2) is blittable when you put your data in a ComputeBuffer and send it to the shader; and (3) has array-like syntax if you need to access your data on the C# side. (In my case, I have a line-for-line C# prototype for all my HLSL code.) It admittedly only works if you know the size of your arrays ahead of time, but at least you only have to unroll a single getter and a setter.
[Serializable]
public struct Node
{
public float width;
public Vector3 originPosition; //float3 in HLSL
public uint bitFlags;
// ... etc for all per-Node data
// The HLSL uses a fixed-size array, like so:
//int Children[8];
// ...but C# doesn't allow fixed-size arrays in blittable structs!
// Yet we still want our prototype code to use array syntax, i.e., WITHOUT
// having to access each of these individually each time:
//public int children0;
//public int children1;
//public int children2;
//public int children3;
//public int children4;
//public int children5;
//public int children6;
//public int children7;
// ...so, we have to use a "pretend" array:
public ChildrenArray children;
// ...defined locally, like so:
[Serializable]
public struct ChildrenArray
{
private int children0;
private int children1;
private int children2;
private int children3;
private int children4;
private int children5;
private int children6;
private int children7;
// The key ingredient is this indexer, which makes the "children"
// field's API look like an array of ints:
public int this[int i]
{
get { return GetChildFromNode(i); }
set { SetChildOnNode(i, value); }
}
private int GetChildFromNode(int octantIndex)
{
switch (octantIndex)
{
case 0: return children0;
case 1: return children1;
case 2: return children2;
case 3: return children3;
case 4: return children4;
case 5: return children5;
case 6: return children6;
case 7: return children7;
default:
throw new IndexOutOfRangeException($"Children array index i must be 0 <= i < 7; got {octantIndex}");
}
}
private void SetChildOnNode(int octantIndex, int newValue)
{
switch (octantIndex)
{
case 0: children0 = newValue;
break;
case 1:
children1 = newValue;
break;
case 2:
children2 = newValue;
break;
case 3:
children3 = newValue;
break;
case 4:
children4 = newValue;
break;
case 5:
children5 = newValue;
break;
case 6:
children6 = newValue;
break;
case 7:
children7 = newValue;
break;
default:
throw new IndexOutOfRangeException($"Children array index i must be 0 <= i < 7; got {octantIndex}");
}
}
}
}