raylib-py icon indicating copy to clipboard operation
raylib-py copied to clipboard

Model Animation bug

Open nuclearshadow opened this issue 8 months ago • 2 comments

Loading 3D skeletal animation or updating model with said animation doesn't seem to work properly. I have tried almost identical pieces of code for both python and the Zig binding for raylib. It works correctly for the zig version.

Here's the comparison:

Python

Screenshot

animation_python

Code

import raylibpy as rl

def main():
    width = 800
    height = 600
    rl.init_window(width, height, "Model animation test")
    rl.set_target_fps(60)

    camera = rl.Camera(
        position = rl.Vector3( x = 0, y = 5, z = 15 ),
        target = rl.Vector3( x = 0, y = 0, z = 0 ),
        up = rl.Vector3( x = 0, y = 1, z = 0 ),
        fovy = 45,
        projection = rl.CAMERA_PERSPECTIVE
    )

    modelPath = "resources/3d_models/avatar_rigged.glb"

    model = rl.load_model(modelPath)
    
    animCount = 0
    anims = rl.load_model_animations(modelPath, animCount)
    for anim in anims:
        print("%s" % anim.name)

    anim = anims[0]
    print(f"{anim}")

    frameCounter = 0

    while not rl.window_should_close():
        rl.begin_drawing()
        rl.clear_background(rl.RAYWHITE)

        rl.update_model_animation(model, anim, 0)
        # rl.update_model_animation(model, anim, frameCounter)
        frameCounter = (frameCounter + 1) % anim.frame_count

        rl.begin_mode3d(camera)

        rl.draw_model_ex(model, rl.vector3_zero(), rl.Vector3(1, 0, 0), 0, rl.Vector3(1, 1, 1), rl.WHITE)
        
        rl.end_mode3d()
        
        rl.end_drawing()
    
    model.unload()
    rl.close_window()

if __name__ == '__main__':
    main()

Zig

Screenshot

animation_zig

Code

const std = @import("std");
const rl = @import("raylib");

pub fn main() !void {
    const width = 800;
    const height = 600;
    rl.initWindow(width, height, "Model animation test");
    defer rl.closeWindow();
    rl.setTargetFPS(60);

    var camera = rl.Camera{
        .position = .{ .x = 0, .y = 5, .z = 15 },
        .target = .{ .x = 0, .y = 0, .z = 0 },
        .up = .{ .x = 0, .y = 1, .z = 0 },
        .fovy = 45,
        .projection = .camera_perspective,
    };

    const modelPath = "../resources/3d_models/avatar_rigged.glb";

    var model = rl.loadModel(modelPath);
    defer model.unload();

    const anims = try rl.loadModelAnimations(modelPath);
    for (anims) |anim| {
        std.debug.print("{s}\n", .{anim.name});
    }

    const anim = anims[0];
    std.debug.print("{any}", .{anim});

    var frameCounter: c_int = 0;

    while (!rl.windowShouldClose()) {
        rl.beginDrawing();
        rl.clearBackground(rl.Color.ray_white);

        rl.updateModelAnimation(model, anim, 0);
        // rl.updateModelAnimation(model, anim, frameCounter);
        frameCounter = @mod(frameCounter + 1, anim.frameCount);

        camera.begin();

        model.drawEx(rl.Vector3.zero(), rl.Vector3{ .x = 1, .y = 0, .z = 0 }, 0, rl.Vector3{ .x = 1, .y = 1, .z = 1 }, rl.Color.white);

        camera.end();

        rl.endDrawing();
    }
}

It shows as expected on the zig version but breaks in the python version.

Another thing is that python version seems to load 1 less frame of animation compared to zig version Here are the log messages for animations loading:

Python

INFO: MODEL: [resources/3d_models/avatar_rigged.glb] Loaded animation: ArmatureAction (3 frames, 0.066667s)
INFO: MODEL: [resources/3d_models/avatar_rigged.glb] Loaded animation: Armature|mixamo.com|Layer0 (3 frames, 0.066667s)

Zig

INFO: MODEL: [../resources/3d_models/avatar_rigged.glb] Loaded animation: ArmatureAction (4 frames, 0.066667s)
INFO: MODEL: [../resources/3d_models/avatar_rigged.glb] Loaded animation: Armature|mixamo.com|Layer0 (4 frames, 0.066667s)

And from my testing with 2 different animations, this only occurred when I used an animation with duplicate or hold keyframes in animation (in blender, don't how gltf stores animation. The animation in the screenshot only has 1 keyframe for the pose at the very beginning and another duplicate keyframe in blender) but not for an animation where every keyframe is unique (again, in blender) for the animation I downloaded from mixamo. I don't know how helpful this bit of information is.

I think the combination of 1 less frame and duplicate keyframes appears to cause this.

nuclearshadow avatar Jun 18 '24 08:06 nuclearshadow