ADDED: Complete support for M3D animations! #2648
This commit is contained in:
parent
64cca24526
commit
fb1037a241
7 changed files with 263 additions and 194 deletions
|
@ -1,97 +1,101 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Load M3D model (with optional animations) and play them
|
||||
* raylib [models] example - Load models M3D
|
||||
*
|
||||
* Example static mesh Suzanne from Blender
|
||||
* Example animated seagull model from Scorched 3D, licensed GPLv2
|
||||
* Example originally created with raylib 4.5-dev, last time updated with raylib 4.5-dev
|
||||
*
|
||||
* Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* NOTES:
|
||||
* - Model3D (M3D) fileformat specs: https://gitlab.com/bztsrc/model3d
|
||||
* - Bender M3D exported: https://gitlab.com/bztsrc/model3d/-/tree/master/blender
|
||||
* WARNING: Make sure to add "(action)" markers to the timeline if you want multiple animations.
|
||||
*
|
||||
* 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) 2019-2022 Culacant (@culacant) and Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2022 bzt (@bztsrc)
|
||||
*
|
||||
********************************************************************************************
|
||||
*
|
||||
* NOTE: To export a model from blender, just use https://gitlab.com/bztsrc/model3d/-/tree/master/blender
|
||||
* and make sure to add "(action)" markers to the timeline if you want multiple animations.
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
char *model_fn = argc > 1 ? argv[1] : "resources/models/m3d/seagull.m3d";
|
||||
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - M3D model");
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - M3D model loading");
|
||||
|
||||
// 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.position = (Vector3){ 1.5f, 1.5f, 1.5f }; // Camera position
|
||||
camera.target = (Vector3){ 0.0f, 0.4f, 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 mode type
|
||||
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
|
||||
|
||||
char modelFileName[128] = "resources/models/m3d/CesiumMan.m3d";
|
||||
bool drawMesh = 1;
|
||||
bool drawSkeleton = 1;
|
||||
bool animPlaying = false; // Store anim state, what to draw
|
||||
|
||||
// Load model
|
||||
Model model = LoadModel(model_fn); // Load the animated model mesh and basic data
|
||||
Model model = LoadModel(modelFileName); // Load the bind-pose model mesh and basic data
|
||||
|
||||
// Load animation data
|
||||
unsigned int animsCount = 0, animsSkel = 1, animsMesh = 1;
|
||||
ModelAnimation *anims = LoadModelAnimations(model_fn, &animsCount);
|
||||
// Load animations
|
||||
unsigned int animsCount = 0;
|
||||
int animFrameCounter = 0, animId = 0;
|
||||
ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data
|
||||
|
||||
SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
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
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
if (animsCount)
|
||||
{
|
||||
if (IsKeyDown(KEY_SPACE))
|
||||
// Play animation when spacebar is held down (or step one frame with N)
|
||||
if (IsKeyDown(KEY_SPACE) || IsKeyPressed(KEY_N))
|
||||
{
|
||||
animFrameCounter++;
|
||||
UpdateModelAnimation(model, anims[animId], animFrameCounter);
|
||||
|
||||
if (animFrameCounter >= anims[animId].frameCount) animFrameCounter = 0;
|
||||
//printf("anim %u, frame %u / %u\n",animId,animFrameCounter,anims[animId].frameCount);
|
||||
|
||||
UpdateModelAnimation(model, anims[animId], animFrameCounter);
|
||||
animPlaying = true;
|
||||
}
|
||||
if (IsKeyDown(KEY_S))
|
||||
{
|
||||
animsSkel ^= 1;
|
||||
}
|
||||
if (IsKeyDown(KEY_M))
|
||||
{
|
||||
animsMesh ^= 1;
|
||||
}
|
||||
|
||||
// Select animation on mouse click
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
||||
|
||||
// Select animation by pressing A
|
||||
if (IsKeyPressed(KEY_A))
|
||||
{
|
||||
animFrameCounter = 0;
|
||||
animId++;
|
||||
|
||||
if (animId >= animsCount) animId = 0;
|
||||
UpdateModelAnimation(model, anims[animId], 0);
|
||||
animPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle skeleton drawing
|
||||
if (IsKeyPressed(KEY_S)) drawSkeleton ^= 1;
|
||||
|
||||
// Toggle mesh drawing
|
||||
if (IsKeyPressed(KEY_M)) drawMesh ^= 1;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
|
@ -102,25 +106,53 @@ int main(int argc, char **argv)
|
|||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (animsMesh)
|
||||
DrawModel(model, position, 1.0f, WHITE); // Draw 3d model with texture
|
||||
// Draw 3d model with texture
|
||||
if (drawMesh) DrawModel(model, position, 1.0f, WHITE);
|
||||
|
||||
if (anims && animsSkel)
|
||||
for (int i = 0; i < model.boneCount; i++)
|
||||
// Draw the animated skeleton
|
||||
if (drawSkeleton)
|
||||
{
|
||||
// Loop to (boneCount - 1) because the last one is a special "no bone" bone,
|
||||
// needed to workaround buggy models
|
||||
// without a -1, we would always draw a cube at the origin
|
||||
for (int i = 0; i < model.boneCount - 1; i++)
|
||||
{
|
||||
DrawCube(anims[animId].framePoses[animFrameCounter][i].translation, 0.05f, 0.05f, 0.05f, RED);
|
||||
if (anims[animId].bones[i].parent >= 0)
|
||||
DrawLine3D(anims[animId].framePoses[animFrameCounter][i].translation,
|
||||
anims[animId].framePoses[animFrameCounter][anims[animId].bones[i].parent].translation, RED);
|
||||
// By default the model is loaded in bind-pose by LoadModel().
|
||||
// But if UpdateModelAnimation() has been called at least once
|
||||
// then the model is already in animation pose, so we need the animated skeleton
|
||||
if (!animPlaying || !animsCount)
|
||||
{
|
||||
// Display the bind-pose skeleton
|
||||
DrawCube(model.bindPose[i].translation, 0.04f, 0.04f, 0.04f, RED);
|
||||
|
||||
if (model.bones[i].parent >= 0)
|
||||
{
|
||||
DrawLine3D(model.bindPose[i].translation,
|
||||
model.bindPose[model.bones[i].parent].translation, RED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display the frame-pose skeleton
|
||||
DrawCube(anims[animId].framePoses[animFrameCounter][i].translation, 0.05f, 0.05f, 0.05f, RED);
|
||||
|
||||
if (anims[animId].bones[i].parent >= 0)
|
||||
{
|
||||
DrawLine3D(anims[animId].framePoses[animFrameCounter][i].translation,
|
||||
anims[animId].framePoses[animFrameCounter][anims[animId].bones[i].parent].translation, RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, GetScreenHeight() - 30, 10, MAROON);
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE THROUGH ANIMATIONS", 10, GetScreenHeight() - 20, 10, DARKGRAY);
|
||||
DrawText("(c) Seagull model by Scorched3D", screenWidth - 200, screenHeight - 20, 10, GRAY);
|
||||
DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, GetScreenHeight() - 60, 10, MAROON);
|
||||
DrawText("PRESS A to CYCLE THROUGH ANIMATIONS", 10, GetScreenHeight() - 40, 10, DARKGRAY);
|
||||
DrawText("PRESS M to toggle MESH, S to toggle SKELETON DRAWING", 10, GetScreenHeight() - 20, 10, DARKGRAY);
|
||||
DrawText("(c) CesiumMan model by KhronosGroup", GetScreenWidth() - 210, GetScreenHeight() - 20, 10, GRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -130,8 +162,7 @@ int main(int argc, char **argv)
|
|||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Unload model animations data
|
||||
for (unsigned int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
|
||||
RL_FREE(anims);
|
||||
UnloadModelAnimations(anims, animsCount);
|
||||
|
||||
UnloadModel(model); // Unload model
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue