Search Unity

Possible for a Compute Buffer to pass a struct containing a Vector3 array?

Discussion in 'Shaders' started by salem, Nov 27, 2015.

  1. salem

    salem

    Joined:
    May 10, 2013
    Posts:
    2
    I want to know if it is possible to pass a structured buffer to my material containing a struct that has a Vector3 array. I feel like this should be doable - my buffer stride is initialized properly.

    Ultimately my goal is to have this flexibility, given that I initialize the size of positions[] before filling and setting the data on the buffer:

    Code (CSharp):
    1. struct Line
    2. {
    3.     public Vector3[] positions;
    4. }
    As opposed to a fixed set of Vector3:

    Code (CSharp):
    1. struct Line
    2. {
    3.     public Vector3 position0;
    4.     public Vector3 position1;
    5.     public Vector3 position2;
    6.     public Vector3 position3;
    7. }
    On the shader side, I'm passing this Vector3 array along like so:

    Code (CSharp):
    1. struct Line
    2. {
    3.     float3 positions[4];
    4. };
    5.  
    6. uniform StructuredBuffer<Line> lineBuffer;
    7.  
    8. struct v2g
    9. {
    10.     float4  pos : SV_POSITION;
    11.     float3    positions[4] : LINEPOSITIONS;
    12. };
    13.  
    14. v2g vert(appdata_base v, uint id : SV_VertexID)
    15. {
    16.     Line line = lineBuffer[id];
    17.  
    18.     v2g OUT;
    19.     OUT.pos = mul(_Object2World, v.vertex);
    20.     OUT.positions = line.positions;
    21.     return OUT;
    22. }
    However, I'm getting no errors that would indicate that this isn't allowed, instead it just doesn't work. The former (fixed) count of Vector3's, and the below shader snippet does work however:

    Code (CSharp):
    1. struct Line
    2. {
    3.     float3 position0;
    4.     float3 position1;
    5.     float3 position2;
    6.     float3 position3;
    7. };
    8.  
    9. uniform StructuredBuffer<Line> lineBuffer;
    10.  
    11. struct v2g
    12. {
    13.     float4  pos : SV_POSITION;
    14.     float3    position0 : LINEPOSITION0;
    15.     float3    position1 : LINEPOSITION1;
    16.     float3    position2 : LINEPOSITION2;
    17.     float3    position3 : LINEPOSITION3;
    18. };
    19.  
    20. v2g vert(appdata_base v, uint id : SV_VertexID)
    21. {
    22.     Line line = lineBuffer[id];
    23.  
    24.     v2g OUT;
    25.     OUT.pos = mul(_Object2World, v.vertex);
    26.     OUT.position0 = line.position0;
    27.     OUT.position1 = line.position1;
    28.     OUT.position2 = line.position2;
    29.     OUT.position3 = line.position3;
    30.     return OUT;
    31. }
    Any ideas if this is doable?
     
  2. salem

    salem

    Joined:
    May 10, 2013
    Posts:
    2
    Bumping -- anyone?
     
  3. Juho_Oravainen

    Juho_Oravainen

    Unity Technologies

    Joined:
    Jun 5, 2014
    Posts:
    42
    Hi!

    The issue there is that the data fed into ComputeBuffer.SetData() must match exactly the data layout defined in the shader. In the case of a struct containing an array, C# does not seem to play nicely together with DX layout.

    So, what you can do is that in the shader define the data as you like (struct containing an array) and then ensure that the data fed from C# matches that layout. The easiest way in this case would probably be to use the fixed set of Vector3 in the struct on the C# side.

    In general the ComputeBuffer data set/get API is atm very low level, e.g. you need to understand the data layout rules in shaders. Also if you make cross platform builds you then need to handle the layout differences between platforms (for example DX packs vec3 array tightly whereas GL uses padding to vec4).

    Hopefully this helps you getting forward!
     
    Propagant, ahnat and DDeathlonger like this.