From ada82e546ced2767d9ed6baa2aef8485ddf626dd Mon Sep 17 00:00:00 2001 From: Tyler Bezera Date: Sat, 29 Feb 2020 00:44:24 -0800 Subject: [PATCH] Load joints in gltf models --- examples/models/models_animation_gltf.c | 104 ++++++++++++++++++ .../models/resources/models/RiggedFigure.glb | Bin 0 -> 49532 bytes src/models.c | 61 ++++++++++ 3 files changed, 165 insertions(+) create mode 100644 examples/models/models_animation_gltf.c create mode 100644 examples/models/resources/models/RiggedFigure.glb diff --git a/examples/models/models_animation_gltf.c b/examples/models/models_animation_gltf.c new file mode 100644 index 000000000..a599c5f85 --- /dev/null +++ b/examples/models/models_animation_gltf.c @@ -0,0 +1,104 @@ +/******************************************************************************************* +* +* raylib [models] example - Load 3d model with animations and play them +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5) +* +******************************************************************************************** +* +* To export a model from blender, make sure it is not posed, the vertices need to be in the +* same position as they would be in edit mode. +* and that the scale of your models is set to 0. Scaling can be done from the export menu. +* +********************************************************************************************/ + +#include +#include "raylib.h" + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.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.type = CAMERA_PERSPECTIVE; // Camera mode type + + Model model2 = LoadModel("resources/models/RiggedFigure.glb"); + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + // Load animation data + int animsCount = 0; + ModelAnimation *anims = LoadModelAnimations("resources/guy/guyanim.iqm", &animsCount); + int animFrameCounter = 0; + + SetCameraMode(camera, CAMERA_FREE); // Set free camera mode + + 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); + + // Play animation when spacebar is held down + if (IsKeyDown(KEY_SPACE)) + { + animFrameCounter++; + //UpdateModelAnimation(model, anims[0], animFrameCounter); + if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModelEx(model2, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE); + + for (int i = 0; i < model2.boneCount; i++) + { + //DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED); + } + + DrawGrid(10, 1.0f); // Draw a grid + + EndMode3D(); + + DrawText("PRESS SPACE to PLAY GLTF MODEL ANIMATION", 10, 10, 20, MAROON); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // Unload model animations data + for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); + RL_FREE(anims); + + UnloadModel(model2); // Unload model + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/resources/models/RiggedFigure.glb b/examples/models/resources/models/RiggedFigure.glb new file mode 100644 index 0000000000000000000000000000000000000000..d1b4f4d4f1fc18738021a7f117d409c4d9ee17bb GIT binary patch literal 49532 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 literal 0 HcmV?d00001 diff --git a/src/models.c b/src/models.c index 6d95441fe..24e1b0547 100644 --- a/src/models.c +++ b/src/models.c @@ -3462,12 +3462,14 @@ static Model LoadGLTF(const char *fileName) - Supports embedded (base64) or external textures - Loads all raylib supported material textures, values and colors - Supports multiple mesh per model and multiple primitives per model + - Loading joints for a single skin Some restrictions (not exhaustive): - Triangle-only meshes - Not supported node hierarchies or transforms - Only supports unsigned short indices (no byte/unsigned int) - Only supports float for texture coordinates (no byte/unsigned short) + - Multiple skins (armatures) *************************************************************************************/ @@ -3529,6 +3531,63 @@ static Model LoadGLTF(const char *fileName) for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); + // Currenly only support one skin + model.boneCount = data->skins[0].joints_count; + model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo)); + model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform)); + for (int i = 0; i < model.boneCount; i++) + { + if (data->skins[0].joints[i]->name) { + // Raylib only supports names up to 34 characters.. + if (strlen(data->skins[0].joints[i]->name) <= 34) { + strcpy(model.bones[i].name, data->skins[0].joints[i]->name); + } + } + + // Mark parents in array + if (data->skins[0].joints[i]->children_count > 0) { + int numOfChildrenJoints = data->skins[0].joints[i]->children_count; + for (int j = i; j < numOfChildrenJoints; j++) { + model.bones[j].parent = i; + } + } + + // Set the tranlation for this joint + if (data->skins[0].joints[i]->has_translation) { + model.bindPose[i].translation.x = data->skins[0].joints[i]->translation[0]; + model.bindPose[i].translation.y = data->skins[0].joints[i]->translation[1]; + model.bindPose[i].translation.z = data->skins[0].joints[i]->translation[2]; + } + + // Set the rotation for this joint + if (data->skins[0].joints[i]->has_rotation) { + model.bindPose[i].rotation.x = data->skins[0].joints[i]->rotation[0]; + model.bindPose[i].rotation.y = data->skins[0].joints[i]->rotation[1]; + model.bindPose[i].rotation.z = data->skins[0].joints[i]->rotation[2]; + model.bindPose[i].rotation.w = data->skins[0].joints[i]->rotation[3]; + } + + // Set the scale for this joint + if (data->skins[0].joints[i]->has_scale) { + model.bindPose[i].scale.x = data->skins[0].joints[i]->scale[0]; + model.bindPose[i].scale.y = data->skins[0].joints[i]->scale[1]; + model.bindPose[i].scale.z = data->skins[0].joints[i]->scale[2]; + } + } + + // Build bind pose from parent joints... Same IQM Loader + for (int i = 0; i < model.boneCount; i++) + { + if (model.bones[i].parent >= 0) + { + model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation); + model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation); + model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation); + model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale); + } + } + + TRACELOG(LOG_INFO, "[%s][%d] Joints loaded", fileName, data->skins[0].joints_count); for (int i = 0; i < model.materialCount - 1; i++) { model.materials[i] = LoadMaterialDefault(); @@ -3613,6 +3672,8 @@ static Model LoadGLTF(const char *fileName) cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; model.meshes[primitiveIndex].vertexCount = acc->count; model.meshes[primitiveIndex].vertices = RL_MALLOC(sizeof(float)*model.meshes[primitiveIndex].vertexCount*3); + model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); + model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); LOAD_ACCESSOR(float, 3, acc, model.meshes[primitiveIndex].vertices) }