Animated characters performance

I want to optimize the rendering of the animated (with skeletal animations) characters. Where should I start from?

My target is to render 8 characters (without LODs) on screen with 70 bones (default blender armature without face bones) for each character with at least 120 FPS on GeForce GTX 1050. I did some tests and figured out that performance depends on the bones count and polygons count. I can’t reduce the number of bones, so I’m going to reduce the number of polygons. How far should I go?

I have checked the polygon count of the characters from some games:
Quake [1996] - 200
Quake 4 [2006] - 2500
Unreal Tournament [1999] - 800
Unreal Tournament 2k3 [2003] - 3000

I don’t think I would be able to reduce the number of polygons lower than 1000. So I’m thinking about 2000-3000 polygons.

What else should I do? Can I remove some data from vertex buffer like colors and tangents, because I’m not using normal-mapping. Could it help?

Does the performance depends of the number of frames (duration) and frame rate of the currently playing animation? Should I reduce the number of keyframes of the animation and rely on the frames interpolation?

Does the Panda3D animation system is not optimized well, because I’ve seen some people recommends going up to 25k polygons per character. Or is it my GPU is too slow for those tasks?

Did you enable hardware skinning or are you using software skinning?

I have tried both, but I didn’t made any custom skinning shaders for it.
I have tested with “hardware-animated-vertices #f” and “hardware-animated-vertices #t”. I don’t see any difference in performance. How could I check if it’s working, does this option creates some specific OpenGL calls, which I could see in NVIDIA Nsight Graphics debugger?

It requires a custom shader. If the ShaderAttrib isn’t flagged as supporting skinning, it will fall back to CPU animation. Perhaps in a future version of Panda3D we can automatically inject this into the shader.

I highly recommend this, because doing the calculations on the CPU is quite slow. It just requires a small change to the vertex shader.

See this post for an example shader:

1 Like

Nice. It works. Now the rendering is 10x times faster.

But how do I test that I’m not using the CPU skinning. It is possible to completely disable CPU skinning? I’m trying to add GPU skinning to RenderPipeline by modifying existing ShaderAttrib of the NodePath. I have already added the GLSL code, which modifies the matrices.

I have added hardware skinning to RP. I also made some usage example:

The example is based on RP’s Roaming Ralph - https://github.com/tobspr/RenderPipeline-Samples/tree/master/02-Roaming-Ralph

“hardware_skinning.yaml” effect file (“fragment” part is copied from “scene-effect.yaml”):

fragment:
    material:
        m.shading_model = SHADING_MODEL_DEFAULT;
        m.basecolor = texture(p3d_Texture0, texcoord).xyz;
        m.roughness = 0.9;
        m.specular_ior = 1.51;
        m.metallic = 0;
        m.normal = vOutput.normal;
        m.shading_model_param0 = 0.0; // unused

vertex:
  inout: |
    in vec4 transform_weight;
    in uvec4 transform_index;
    uniform mat4 p3d_TransformTable[100];

  transform: |
    mat4 skin_matrix = (
        p3d_TransformTable[transform_index.x] * transform_weight.x +
        p3d_TransformTable[transform_index.y] * transform_weight.y +
        p3d_TransformTable[transform_index.z] * transform_weight.z +
        p3d_TransformTable[transform_index.w] * transform_weight.w);
    mat4 model_matrix = p3d_ModelMatrix * skin_matrix;

    vOutput.normal = normalize(model_matrix * vec4(p3d_Normal.xyz, 0)).xyz;
    vOutput.position = (model_matrix * p3d_Vertex).xyz;

“main.py” file modifications:

self.render_pipeline.set_effect(self.ralph, 'hardware_skinning.yaml', options={}, sort=25)
sattrib = self.ralph.get_attrib(ShaderAttrib)
sattrib = sattrib.set_flag(ShaderAttrib.F_hardware_skinning, True)
self.ralph.set_attrib(sattrib)

I also found a way to test it. If I remove matrices multiplication, then I should see not skinned mesh (in some default static pose).

1 Like

No, but I think it is a good idea for Panda3D to display a warning if it can’t be used due to a custom shader not supporting it.