Extracting Character Transform Table into a TBO

Hi. I’m currently hitting a bottleneck with hardware skinning control. I’m planning to make a large dense forest of animated trees (with bones to simulate wind) and need control over the frame times and bone amounts for each instance. To fix this, I want to put the transform table into a TBO. currently i’m working like this:

uniform samplerBuffer TBO_TransformTable;
uniform int TBO_SkinningFrame;
uniform int TBO_NumJoints;

this will be passed into the shader. However, the TBO needs to store the entirety of the animation so that I can pass any frame number in and it will index the right position in the TBO. However I’m struggling to actually get the animation information extracted from the animated tree. How do I extract the bone data from Character and put it into the TBO?

I was thinking of storing each matrix row side by side in a rgba32 texture and reconstruct the matrix in the shader.

I’m using TBO for hardware skinning too, but I end up writing my own Character/Actor class alternative, which is represented as tree of bone nodes and I’m writing only the current animation frame into TBO - panda3d-kphys/kphys/core/panda/armature.cxx at master · kitsune-ONE-team/panda3d-kphys · GitHub
I’m using this simple structure for serializing the current frame of the animation into TBO - panda3d-kphys/kphys/core/panda/types.h at master · kitsune-ONE-team/panda3d-kphys · GitHub
The whole project could be overkill for your task, but maybe you can find some useful parts from it.

1 Like

yea that would be overkill. My trees only need one animation at once. And to reduce CPU overhead, it would be good to just put the entire animation in one TBO.

I noticed in your code, you also create another TBO _bone_id_tree_tex. I’m interested how you exactly referenced in uvec4 transform_index; in you shaders. What is you structure exactly?

I noticed in your code, you also create another TBO _bone_id_tree_tex.

I’m not using _bone_id_tree_tex atm. I made it for some future optimizations.

This is how I’m referencing the transform_index:

mat4 get_transform_matrix(samplerBuffer transform_tex, int bone_id) {
    int index = bone_id * 4;
    vec4 row0 = texelFetch(transform_tex, index);
    vec4 row1 = texelFetch(transform_tex, index + 1);
    vec4 row2 = texelFetch(transform_tex, index + 2);
    vec4 row3 = texelFetch(transform_tex, index + 3);
    return mat4(row0, row1, row2, row3);
}

I’m using only 1 animation frame, but you can put all the frames and calculate the offset by frame index.

So this is generic hardware skinning in vertex shader for up to 4 bones:

    mat4 skin_matrix = (
        get_transform_matrix(bone_transform_tex, int(transform_index.x)) * transform_weight.x +
        get_transform_matrix(bone_transform_tex, int(transform_index.y)) * transform_weight.y +
        get_transform_matrix(bone_transform_tex, int(transform_index.z)) * transform_weight.z +
        get_transform_matrix(bone_transform_tex, int(transform_index.w)) * transform_weight.w);
    model_matrix *= skin_matrix;
1 Like

hmm. Like you said you built your own Character class. How do you extract animation information that is in the correct order for transform_index? Could I potentially use the same method for the default Character class? I think storing the information won’t be too hard. Just need to multiply the frame time with the animation offset for the TBO as an extension to the function you showed.
I’m not actually to sure where to actually get the animation skinning data?

Like you said you built your own Character class. How do you extract animation information that is in the correct order for transform_index?

I built my own Animation class too. :laughing:
So it all up to me for match the bone index in character and animation. I’m just sorting all the bones by it’s name for simplicity and referencing bones by it’s name in the animation.

This is where I sort the bones by name and generating a new transform_index for each bone:

This is where I write the new transform_index into GeomVertexData during the loading mesh from glTF:

You can use the same methods to get transform_index from the mesh or rewrite it.

I’m not actually to sure where to actually get the animation skinning data?

The animation is basically array of matrices. I don’t know how to parse the panda animaions, but since you want to animate the model by yourself in shader you can use any animation format. I’m using BVH, but I have extended it with quaternions. It’s a simple text-based format where the bone order is defined in HIERARCHY section.

1 Like

Surely there is a simpler way to store the matrix deform of each bone to the transform index. Maybe since I am using the original panda3d library, somewhere in the source code I could find how the uniform p3d_TransformTable is constructed. It would save me some time re-formatting my Character’s geometry.

looking through the documentation and source code, I might be able to extract animation data from the geometry’s TransformTable. From my understanding of the C++ function:

void CLP(ShaderContext)::
update_transform_table(const TransformTable *table) {
  LMatrix4f *matrices = (LMatrix4f *)alloca(_transform_table_size * 64);

  size_t i = 0;
  if (table != nullptr) {
    size_t num_transforms = min((size_t)_transform_table_size, table->get_num_transforms());
    for (; i < num_transforms; ++i) {
#ifdef STDFLOAT_DOUBLE
      LMatrix4 matrix;
      table->get_transform(i)->get_matrix(matrix);
      matrices[i] = LCAST(float, matrix);
#else
      table->get_transform(i)->get_matrix(matrices[i]);
#endif
    }
  }
  for (; i < (size_t)_transform_table_size; ++i) {
    matrices[i] = LMatrix4f::ident_mat();
  }

  _glgsg->_glUniformMatrix4fv(_transform_table_index, _transform_table_size,
                              GL_FALSE, (float *)matrices);
}

The transform table object gets filled every frame but I can’t find from where. Looking at the documentation, I can get the TransformTable from a GeomVertexData object. I’m not very familiar of how the data is stored. Is there a new GeomVertexData object per frame of character animation? Does this mean I have to go through the animation frame by frame and extract a TransformTable? I’m just trying to keep my code as simple as possible. I would prefer to avoid making an entire new Character class as all I need is one animation playing at a time.

Or maybe it could be worth investing in what you currently have for future proof reasons. Not sure. Maybe panda3d will eventually add a shader uniform option to store skinning data on a TBO.