From ec02d80868083e593d339093ddc128cc5aa1cab5 Mon Sep 17 00:00:00 2001 From: Kirandeep-Singh-Khehra Date: Sat, 7 Dec 2024 22:54:34 +0530 Subject: [PATCH] [rmodels] Added example for animation blending and fixed wrap issue for blend factor Signed-off-by: Kirandeep-Singh-Khehra --- examples/models/models_animation_blending.c | 138 ++++++++++++++++++++ src/rmodels.c | 2 +- 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 examples/models/models_animation_blending.c diff --git a/examples/models/models_animation_blending.c b/examples/models/models_animation_blending.c new file mode 100644 index 000000000..8c5394ac0 --- /dev/null +++ b/examples/models/models_animation_blending.c @@ -0,0 +1,138 @@ +/******************************************************************************************* +* +* raylib [core] example - Model animation blending +* +* Example originally created with raylib 5.5 +* +* Example contributed by Kirandeep (@Kirandeep-Singh-Khehra) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Kirandeep (@Kirandeep-Singh-Khehra) +* +* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS +* +********************************************************************************************/ + +#include "raylib.h" + +#define clamp(x,a,b) ((x < a)? a : (x > b)? b : x) + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - Model Animation Blending"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 8.0f, 8.0f, 8.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Load gltf model + Model characterModel = LoadModel("resources/models/gltf/robot.glb"); // Load character model + + // Load skinning shader + Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION)); + + for (int i = 0; i < characterModel.materialCount; i++) + { + characterModel.materials[i].shader = skinningShader; + } + + // Load gltf model animations + int animsCount = 0; + unsigned int animIndex0 = 0; + unsigned int animIndex1 = 0; + unsigned int animCurrentFrame = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount); + + float blendFactor = 0.5f; + + DisableCursor(); // Limit cursor to relative movement inside the window + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_THIRD_PERSON); + + // Select current animation + if (IsKeyPressed(KEY_T)) animIndex0 = (animIndex0 + 1)%animsCount; + else if (IsKeyPressed(KEY_G)) animIndex0 = (animIndex0 + animsCount - 1)%animsCount; + if (IsKeyPressed(KEY_Y)) animIndex1 = (animIndex1 + 1)%animsCount; + else if (IsKeyPressed(KEY_H)) animIndex1 = (animIndex1 + animsCount - 1)%animsCount; + + // Select blend factor + if (IsKeyPressed(KEY_U)) blendFactor = clamp(blendFactor - 0.1, 0.0f, 1.0f); + else if (IsKeyPressed(KEY_J)) blendFactor = clamp(blendFactor + 0.1, 0.0f, 1.0f); + + // Update animation + animCurrentFrame++; + + // Update bones + // Note: Same animation frame index is used below. By default it loops both animations + UpdateModelAnimationBonesWithBlending(characterModel, modelAnimations[animIndex0], animCurrentFrame, modelAnimations[animIndex1], animCurrentFrame, blendFactor); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + // Draw character mesh, pose calculation is done in shader (GPU skinning) + for (int i = 0; i < characterModel.meshCount; i++) + { + DrawMesh(characterModel.meshes[i], characterModel.materials[characterModel.meshMaterial[i]], characterModel.transform); + } + + + DrawGrid(10, 1.0f); + + EndMode3D(); + + DrawText("Use the U/J Arrow to adjust blend factor", 10, 10, 20, GRAY); + DrawText("Use the T/G to switch animation", 10, 30, 20, GRAY); + DrawText("Use the Y/H to switch animation", 10, 50, 20, GRAY); + DrawText(TextFormat("Animations: %s, %s", modelAnimations[animIndex0].name, modelAnimations[animIndex1].name), 10, 70, 20, BLACK); + DrawText(TextFormat("Blend Factor: %f", blendFactor), 10, 86, 20, BLACK); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModelAnimations(modelAnimations, animsCount); // Unload model animation + UnloadModel(characterModel); // Unload model and meshes/material + UnloadShader(skinningShader); // Unload GPU skinning shader + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/src/rmodels.c b/src/rmodels.c index b68dc0cf4..a215bcc8c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -2315,7 +2315,7 @@ void UpdateModelAnimationBonesWithBlending(Model model, ModelAnimation animA, in { if ((animA.frameCount > 0) && (animA.bones != NULL) && (animA.framePoses != NULL) && (animB.frameCount > 0) && (animB.bones != NULL) && (animB.framePoses != NULL) && - (blendFactor >= 0.0f) && (blendFactor <= 1.0)) + (blendFactor >= 0.0f) && (blendFactor <= 1.0f)) { frameA = frameA % animA.frameCount; frameB = frameB % animB.frameCount;