Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Assigning bone weights and indices directly to a vertex buffer.

Discussion in 'General Graphics' started by pk1234dva, Feb 2, 2022.

  1. pk1234dva

    pk1234dva

    Joined:
    May 27, 2019
    Posts:
    84
    I've been attempting to set bone weights and indices by writing directly to a vertex buffer, but it doesn't seem to work.

    Assuming 4 dimensions for both weights and indices with float32 and uint32 format respectively, it seems I can read and add values correctly. Reading the floats works fine, and the bone indices can be read by casting the respective uint32 as a byte. Starting with a working mesh, and adding a few extra vertices, the extra vertices read the correct values - the following prints the correct results for the newly added vertices.

    Code (CSharp):
    1. byte* ptr = origVertexBufferStartPtr + idx * bytesPerVertex;
    2.  
    3. for (int j = 0; j < bonesDimension; j++)
    4. {
    5.     float weight = *((float*)ptr);
    6.     Debug.Log("Weight: " + weight);
    7.     ptr += bytesPerWeight;
    8. }
    9. for (int j = 0; j < bonesDimension; j++)
    10. {
    11.     byte lowerIndex = *((byte*)ptr);
    12.     Debug.Log("Index: " + lowerIndex);
    13.     ptr += bytesPerIndex;
    14. }
    Despite this however, the weights don't seem to work correctly, and the values I afterwards get using
    Code (CSharp):
    1. var bones = mesh.boneWeights;
    are not correct, sometimes being negative etc.

    Is there a way to make this work, and make the new bone related vertex values useable?
     
  2. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    you didn't show any code on how you're updating your weights
     
  3. pk1234dva

    pk1234dva

    Joined:
    May 27, 2019
    Posts:
    84
    I make a new vertex buffer. For original vertices that I want to use, I just copy the corresponding memory in the original buffer - this works fine.
    For new vertices, I update the weights similarly to the code above, writing the values directly to the vertex buffer. E.g. something like this for indices (slightly different behavior depending on vertex attributes)

    Code (CSharp):
    1. case VertexAttributeFormat.UInt32:
    2.     for (int j = 0; j < bonesDimension; j++)
    3.     {
    4.         // Get current new vertex buffer position
    5.         byte* tmp = (byte*)newVertexBufferPtr;
    6.         // Assign
    7.         *tmp = boneIndex;
    8.         // Update pointer
    9.         newVertexBufferPtr += 4;
    10.     }
    11.     break;
    I doubt there's something wrong with this, because printing out the values gives correct results - it's the same function for both new and old vertices in the buffer, so if there was something wrong, I would expect both would be wrong.
     
  4. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    and are you sure that your target architecture is Little-Endian? And are you clearing the other bytes of the index to 0? Depending on how you allocate the memory for that new buffer, it may not be zeroed out.
     
    Last edited: Feb 3, 2022
  5. pk1234dva

    pk1234dva

    Joined:
    May 27, 2019
    Posts:
    84
    I think that not clearing out the memory is a good point, thanks. I'm explicitly assigning the values to the proper byte positions of the indices, but the other 3 are skipped and are uninitialized, I'll test if zeroing them helps.

    I must admit I don't really know how the bone indices in the buffer work - the whole thing is confusing, because:
    1, Apparently up to 255 bones per vertex are somehow possible - given that a vertex stream has at most 4 dimensions *32bits per bone (using uint32), I don't see how the bones could in any way be encoded in a vertex buffer. It makes me think that perhaps using vertex buffers as source of bone weights and indices might deprecated, and skinning is now always done differently - https://docs.unity3d.com/ScriptReference/Mesh.SetBoneWeights.html would also seem to suggest this.

    2, I can't find any documentation regarding how the bone indices are actually stored in the vertex buffer. I've fooled around and noticed that the uint32 format etc is really just used as a stride, and just reading the first byte works, but it's hacky and I'm not even sure whether it's sure to always work.
     
  6. pk1234dva

    pk1234dva

    Joined:
    May 27, 2019
    Posts:
    84
    Thanks, clearing the values to zero for the indices fixed the issue.
     
    mabulous likes this.