Added skeletal animations and other fixes

This commit is contained in:
2026-03-16 12:57:53 +01:00
parent 2cc18b3329
commit 28c6703892
51 changed files with 1964 additions and 602 deletions

View File

@@ -22,14 +22,26 @@ target_include_directories(lightkeeper PRIVATE "${CMAKE_CURRENT_LIST_DIR}/includ
target_link_libraries(lightkeeper PRIVATE destrum::destrum)
set(ASSETS_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_src")
set(ASSETS_RUNTIME_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_runtime")
set(OUTPUT_GAME_ASSETS_DIR "${CMAKE_BINARY_DIR}/assets/game")
#set(ASSETS_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_src")
#set(ASSETS_RUNTIME_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_runtime")
#set(OUTPUT_GAME_ASSETS_DIR "${CMAKE_BINARY_DIR}/assets/game")
#
#add_custom_command(TARGET lightkeeper POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E make_directory "${OUTPUT_GAME_ASSETS_DIR}"
# COMMAND ${CMAKE_COMMAND} -E rm -rf "${OUTPUT_GAME_ASSETS_DIR}"
# COMMAND ${CMAKE_COMMAND} -E create_symlink "${ASSETS_RUNTIME_DIR}" "${OUTPUT_GAME_ASSETS_DIR}"
# VERBATIM
#)
set(ASSETS_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_src")
set(ASSETS_RUNTIME_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_runtime")
set(OUTPUT_GAME_ASSETS_DIR "${CMAKE_CURRENT_BINARY_DIR}/assets/game")
add_custom_command(TARGET lightkeeper POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${OUTPUT_GAME_ASSETS_DIR}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${OUTPUT_GAME_ASSETS_DIR}"
COMMAND ${CMAKE_COMMAND} -E create_symlink "${ASSETS_RUNTIME_DIR}" "${OUTPUT_GAME_ASSETS_DIR}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/assets"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_CURRENT_BINARY_DIR}/assets/game"
COMMAND ${CMAKE_COMMAND} -E create_symlink "${ASSETS_RUNTIME_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/assets/game"
VERBATIM
)
@@ -47,5 +59,4 @@ add_custom_target(_internal_cook_game_assets ALL
DEPENDS TheChef
)
destrum_cook_engine_assets(lightkeeper "${CMAKE_CURRENT_BINARY_DIR}")

Binary file not shown.

View File

@@ -11,6 +11,7 @@
#include "destrum/Components/OrbitAndSpin.h"
#include "destrum/ObjectModel/GameObject.h"
#include "destrum/Util/ModelLoader.h"
#include "destrum/Components/Animator.h"
LightKeeper::LightKeeper(): App(), renderer(meshCache, materialCache) {
}
@@ -52,19 +53,19 @@ void LightKeeper::customInit() {
const float orbitRadius = 5.0f;
for (int i = 0; i < count; ++i) {
auto childCube = std::make_shared<GameObject>(fmt::format("ChildCube{}", i));
auto childMeshComp = childCube->AddComponent<MeshRendererComponent>();
childMeshComp->SetMeshID(testMeshID);
childMeshComp->SetMaterialID(testMaterialID);
childCube->GetTransform().SetWorldScale(glm::vec3(0.1f));
// Add orbit + self spin
auto orbit = childCube->AddComponent<OrbitAndSpin>(orbitRadius, glm::vec3(0.0f));
orbit->Randomize(1337u + (uint32_t)i); // stable random per index
scene.Add(childCube);
// auto childCube = std::make_shared<GameObject>(fmt::format("ChildCube{}", i));
//
// auto childMeshComp = childCube->AddComponent<MeshRendererComponent>();
// childMeshComp->SetMeshID(testMeshID);
// childMeshComp->SetMaterialID(testMaterialID);
//
// childCube->GetTransform().SetWorldScale(glm::vec3(0.1f));
//
// // Add orbit + self spin
// auto orbit = childCube->AddComponent<OrbitAndSpin>(orbitRadius, glm::vec3(0.0f));
// orbit->Randomize(1337u + (uint32_t)i); // stable random per index
//
// scene.Add(childCube);
}
testCube->AddComponent<Spinner>(glm::vec3(0, 1, 0), glm::radians(10.0f)); // spin around Y, rad/sec
//rotate 180 around X axis
@@ -94,6 +95,68 @@ void LightKeeper::customInit() {
skyboxCubemap->CreateCubeMap();
renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID());
const auto planeObj = std::make_shared<GameObject>("GroundPlane");
const auto planeMeshComp = planeObj->AddComponent<MeshRendererComponent>();
const auto planeModel = ModelLoader::LoadGLTF_CPUMeshes_MergedPerMesh(AssetFS::GetInstance().GetFullPath("game://plane.glb").generic_string());
const auto planeMeshID = meshCache.addMesh(gfxDevice, planeModel[0]);
const auto planeTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("game://grass.png"));
const auto planeMaterialID = materialCache.addMaterial(gfxDevice, {
.baseColor = glm::vec3(1.f),
.textureFilteringMode = TextureFilteringMode::Nearest,
.diffuseTexture = planeTextureID,
.name = "GroundPlaneMaterial",
});
planeMeshComp->SetMeshID(planeMeshID);
planeMeshComp->SetMaterialID(planeMaterialID);
planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, -1.0f, 0.f));
planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f));
scene.Add(planeObj);
// At the bottom of customInit(), replace the incomplete CharObj block:
const auto CharObj = std::make_shared<GameObject>("Character");
auto charModel = ModelLoader::LoadSkinnedModel(
AssetFS::GetInstance().GetFullPath("engine://char.fbx").generic_string()
);
const auto charMeshID = meshCache.addMesh(gfxDevice, charModel.meshes[0]);
const auto charTextureID = gfxDevice.loadImageFromFile(
AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
const auto charMaterialID = materialCache.addMaterial(gfxDevice, {
.baseColor = glm::vec3(1.f),
.diffuseTexture = charTextureID,
.name = "CharacterMaterial",
});
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
charMeshComp->SetMeshID(charMeshID);
charMeshComp->SetMaterialID(charMaterialID);
const auto animator = CharObj->AddComponent<Animator>();
animator->setSkeleton(std::move(charModel.skeleton));
for (auto& clip : charModel.animations) {
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
}
for (const auto& clip : charModel.animations)
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
if (!charModel.animations.empty())
// animator->play(charModel.animations[0].name);
// animator->play("Armature|main");
animator->play("Armature|mixamo.com");
// or: animator->play("Run", 0.2f); // 0.2s cross-fade
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
scene.Add(CharObj);
}
void LightKeeper::customUpdate(float dt) {