Search Unity

Size of ComputeBuffer for mesh vertices

Discussion in 'Shaders' started by mSkull, Dec 19, 2016.

  1. mSkull

    mSkull

    Joined:
    Apr 19, 2016
    Posts:
    11
    Hi,

    I've written a fairly simple compute shader that iterates through a some mesh data to build a distance field around it. It works pretty well, but I'm having an issue with my vertex compute buffer, that I don't quite understand.

    To my understanding when you're creating a ComputeBuffer you have to tell it how many elements it'll contain; in my case, the number of vertices in my mesh. And then the size of each element; in my case I'm only using the position data, which consists of Vector3, so sizeof(float) * 3.

    So I created and filled my buffers like this:
    Code (CSharp):
    1. indicesBuffer = new ComputeBuffer(mesh.triangles.Length, sizeof(int));
    2. indicesBuffer.SetData(mesh.triangles);
    3.  
    4. vertexBuffer = new ComputeBuffer(mesh.vertexCount, sizeof(float) * 3);
    5. vertexBuffer.SetData(mesh.vertices);
    6.  
    7. shader.SetBuffer(kernel, "_IndicesBuffer", indicesBuffer);
    8. shader.SetBuffer(kernel, "_VertexBuffer", vertexBuffer);
    And then I'm reconstructing the triangles from the buffers like this in the shader:
    Code (csharp):
    1. RWStructuredBuffer<float3> _VertexBuffer;
    2. RWStructuredBuffer<int> _IndicesBuffer;
    3.  
    4. void MyFunction()
    5. {
    6.     uint triangles;
    7.     uint stride;
    8.     _VertexBuffer.GetDimensions(triangles, stride);
    9.  
    10.     for (uint i = 0; i < triangles; i += 3)
    11.     {
    12.         float3 a = _VertexBuffer[_IndicesBuffer[i + 0]];
    13.         float3 b = _VertexBuffer[_IndicesBuffer[i + 1]];
    14.         float3 c = _VertexBuffer[_IndicesBuffer[i + 2]];
    15.  
    16.         // Stuff that's not relevant to my question.
    17.     }
    18. }
    The indices buffer works exactly like I'm expecting it to, but the vertex buffer seems to be missing data. Like some of the vertices didn't get copied to the buffer.
    By monkeying around with it a bit, I found that by multiplying the size of the vertex buffer by 5 got it to work as I wanted. But I don't understand how or why this solves anything. As far as I know, all this does is waste a bunch of extra memory for no real reason, which I could see becoming problematic when working with more complicated geometry.
    I could understand it if the count was actually a byte count; i.e vertices.vertexCount * sizeof(float) * 3; but this doesn't seem to be the case when looking at my indices buffer. In that case the indices buffer count should be mesh.triangles.Length * sizeof(int), but it's not.

    Code (CSharp):
    1. vertexBuffer = new ComputeBuffer(mesh.vertexCount * 5, sizeof(float) * 3); // size multiplied by 5???
    2. vertexBuffer.SetData(mesh.vertices);
    To demonstate what I mean when I'm saying missing vertices, I've attached an image displaying the results of my compute shader. Only thing that's changed between the 3 different images, is the element count of the vertex buffer.

    Does anyone know why this is happening, or what I'm doing wrong here?
     

    Attached Files:

  2. mSkull

    mSkull

    Joined:
    Apr 19, 2016
    Posts:
    11
    Code (csharp):
    1. _VertexBuffer.GetDimensions(triangles, stride);
    Well just maybe - MAYBE - if I got the size of the indices buffer, instead of the vertex buffer I just MIGHT iterate through all the triangles.
     
  3. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231
    Here is a good way to get it:

    Code (CSharp):
    1. using System.Runtime.InteropServices; // you need this
    2.  
    3. int size = Marshal.SizeOf(new Vector3()); // Change Vector3 by the struct used in your array
    4. computeBuffer = new ComputeBuffer(arraySize, size);
    5.  
    VertexBuffer are Vector3 and I think the struct take more memory than just 3 floats considering the doc:
    https://docs.unity3d.com/ScriptReference/Vector3.html

    To me you are filling a smaller memory sized buffer on your GPU.

    A good exercice is to print the size of a custom struct with 3 floats then compare it with the size of Vector3 struct.
    Take the size of one float and divide the size of Vector3 by it to know how many float it may contains.

    Maybe you should create your own Vector3 struct in your compute shader:
    Code (CSharp):
    1. struct Vector3
    2. {
    3.     float3      position;
    4.     float3      up; //? I don't know if static members are copied too
    5.     ...
    6. };
    7. RWStructuredBuffer<Vector3> _VertexBuffer;
    Or create in C# a custom 3-floats struct and copy the vertexes position in it.
     
    Last edited: Dec 19, 2016
  4. mSkull

    mSkull

    Joined:
    Apr 19, 2016
    Posts:
    11
    The issue is not the data in the vertex buffer (and if you check my own reply above, the issue is not actually the vertex buffer at all, but just the usual stupid mistake I make when I ask for help. I swear, this happens everytime!).

    But about the Vector3.
    I'm not using Marshal, as Vector3 should be pretty consistent size of 3 floats, and the Marshal is slower. Speed doesn't matter much in this case, as it's just a single look up, and not even at runtime, but sizeof(float) * 3 is just as easy and gives me C++ nostalgia. The bytesize also needs to be consistent with byte size on the GPU, so if there's ever a case where Vector3 is not the size of 3 floats, then I'm having much bigger problems.

    Also by checking the decompiled file of Vector3 on github, I confirmed that Vector3 indeed only consists of 3 floats, and a single static field, epsilon. Everything else, directions and magnitude, is properties as I expected them to be.

    And lastly, since I too was unsure how this copying worked, I initially manually copied x, y, & z to a separate float array. But I can clearly see that I'm getting the correct data, without that extra step, so I've taken that out.

    But as mentioned as above, the error was not actually in the vertex buffer, but rather just me getting the size of the vertex buffer instead of the indices buffer. And then it makes perfect sense that increasing the size of the vertex buffer fixes the issue, considering that you'll usually have more indices than vertices in a mesh.

    But thanks for your respond :)
     
    Last edited: Dec 19, 2016