Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cca7047
Minor Change
doyoung413 Jan 16, 2026
b6dd40d
Fix model visibility issue related to vertex structure
doyoung413 Jan 29, 2026
138a42e
Fix model visibility issue related to vertex structure
doyoung413 Jan 29, 2026
6bcd77b
Fix mesh explosion by removing redundant GlobalInverseTransform
doyoung413 Feb 17, 2026
744227f
Merge branch 'SkeletalAnimation' of https://github.com/CubeBerry/Cube…
doyoung413 Feb 17, 2026
e3ca3c0
Fix mesh explosion and PreRotation issues in animations
doyoung413 Mar 4, 2026
a900405
Implement Root Motion
doyoung413 Mar 4, 2026
a7bc4b0
Optimize SkeletalAnimation
doyoung413 Mar 5, 2026
4cfe0cc
Minor Change
doyoung413 Mar 5, 2026
921b304
Add SkeletalAnimationDemo and change debug visualization
doyoung413 Mar 12, 2026
9d7288f
Fix model visibility issue related to vertex structure
doyoung413 Jan 29, 2026
463fd70
Fix mesh explosion by removing redundant GlobalInverseTransform
doyoung413 Feb 17, 2026
bd456c4
Fix model visibility issue related to vertex structure
doyoung413 Jan 29, 2026
7768eb5
Fix mesh explosion and PreRotation issues in animations
doyoung413 Mar 4, 2026
c1e5358
Implement Root Motion
doyoung413 Mar 4, 2026
ec49381
Optimize SkeletalAnimation
doyoung413 Mar 5, 2026
4acfb5f
Minor Change
doyoung413 Mar 5, 2026
3c463ad
Add SkeletalAnimationDemo and change debug visualization
doyoung413 Mar 12, 2026
94c9d6e
Minor change
doyoung413 Mar 26, 2026
071a8ee
Skeletal Animation On Vulkan
doyoung413 Mar 31, 2026
310c321
Merge branch 'SkeletalAnimation' of https://github.com/CubeBerry/Cube…
doyoung413 Mar 31, 2026
6c6eb08
Fixed .gitignore
CubeBerry Mar 31, 2026
a56b6cd
Skeletal Animation On DX and Enhance Component Logging
doyoung413 Mar 31, 2026
9eb1545
Fix skinning error for un-animated bones in SkeletalAnimator
doyoung413 Apr 1, 2026
0ccb1c5
Adjust skeletal animation to support standard hierarchies
doyoung413 Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,8 @@ FodyWeavers.xsd
# /** makes entire folders or formats that should be excluded (bin for example) are ignored
!Engine/libs/FidelityFX-SDK-v1.1.4/**
Engine/libs/FidelityFX-SDK-v1.1.4/sdk/build
!Engine/libs/FidelityFX-SDK-v2.0.0/**
!Engine/libs/FidelityFX-SDK-v2.0.0/**

# Include bin directories under Tools
!Tools/**/bin/
!Tools/**/bin/**
83 changes: 65 additions & 18 deletions Engine/common_gl/source/GLVertexArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,89 @@ void GLVertexArray::Initialize()

void GLVertexArray::AddVertexBuffer(GLVertexBuffer&& buffer, size_t size, std::initializer_list<GLAttributeLayout> layout)
{
//glCheck(glBindVertexArray(vaoHandle));
////glCheck(glBindVertexArray(vaoHandle));

GLuint vboHandle = buffer.GetHandle();
//glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboHandle));
//GLuint vboHandle = buffer.GetHandle();
////glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboHandle));

//for (int index = 0; index < layout.size(); ++index)
//{
// const GLAttributeLayout* attribute = layout.begin() + index;
////for (int index = 0; index < layout.size(); ++index)
////{
//// const GLAttributeLayout* attribute = layout.begin() + index;

//// glCheck(glEnableVertexArrayAttrib(vaoHandle, index));
//// glCheck(glVertexAttribPointer(index, attribute->component_dimension, attribute->component_type, attribute->normalized, size, reinterpret_cast<const void*>(attribute->relative_offset)));
////}

////glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
////glCheck(glBindVertexArray(0));

// glCheck(glEnableVertexArrayAttrib(vaoHandle, index));
// glCheck(glVertexAttribPointer(index, attribute->component_dimension, attribute->component_type, attribute->normalized, size, reinterpret_cast<const void*>(attribute->relative_offset)));
////bind a buffer to a vertex buffer bind point
//glCheck(glVertexArrayVertexBuffer(vaoHandle, 0, vboHandle, 0, static_cast<GLsizei>(size)));

//for (const GLAttributeLayout& attribute : layout)
//{
// glCheck(glEnableVertexArrayAttrib(vaoHandle, attribute.vertex_layout_location));
// switch (attribute.component_type)
// {
// case GL_FLOAT:
// //For Float
// glCheck(glVertexArrayAttribFormat(vaoHandle, attribute.vertex_layout_location, attribute.component_dimension, attribute.component_type, attribute.normalized, attribute.relative_offset));
// break;
// case GL_INT:
// case GL_UNSIGNED_INT:
// //For Int
// glCheck(glVertexArrayAttribIFormat(vaoHandle, attribute.vertex_layout_location, attribute.component_dimension, attribute.component_type, attribute.relative_offset));
// break;
// }
// glCheck(glVertexArrayAttribBinding(vaoHandle, attribute.vertex_layout_location, 0));
//}

//glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
//glCheck(glBindVertexArray(0));
GLuint vboHandle = buffer.GetHandle();

// Save current VAO state
GLint previousVAO;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previousVAO);

//bind a buffer to a vertex buffer bind point
glCheck(glVertexArrayVertexBuffer(vaoHandle, 0, vboHandle, 0, static_cast<GLsizei>(size)));
// Bind VAO and VBO
glCheck(glBindVertexArray(vaoHandle));
glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboHandle));

for (const GLAttributeLayout& attribute : layout)
{
glCheck(glEnableVertexArrayAttrib(vaoHandle, attribute.vertex_layout_location));
glCheck(glEnableVertexAttribArray(attribute.vertex_layout_location));

switch (attribute.component_type)
{
case GL_FLOAT:
//For Float
glCheck(glVertexArrayAttribFormat(vaoHandle, attribute.vertex_layout_location, attribute.component_dimension, attribute.component_type, attribute.normalized, attribute.relative_offset));
// For Float attributes
glCheck(glVertexAttribPointer(
attribute.vertex_layout_location,
attribute.component_dimension,
attribute.component_type,
attribute.normalized ? GL_TRUE : GL_FALSE,
static_cast<GLsizei>(size), // stride
reinterpret_cast<const void*>(static_cast<uintptr_t>(attribute.relative_offset))
));
break;
case GL_INT:
case GL_UNSIGNED_INT:
//For Int
glCheck(glVertexArrayAttribIFormat(vaoHandle, attribute.vertex_layout_location, attribute.component_dimension, attribute.component_type, attribute.relative_offset));
// For Integer attributes (boneIDs)
glCheck(glVertexAttribIPointer(
attribute.vertex_layout_location,
attribute.component_dimension,
attribute.component_type,
static_cast<GLsizei>(size), // stride
reinterpret_cast<const void*>(static_cast<uintptr_t>(attribute.relative_offset))
));
break;
}
glCheck(glVertexArrayAttribBinding(vaoHandle, attribute.vertex_layout_location, 0));
}

// Unbind
glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));

// Restore previous VAO state
glCheck(glBindVertexArray(previousVAO));
}

void GLVertexArray::SetIndexBuffer(GLIndexBuffer&& buffer)
Expand Down
17 changes: 3 additions & 14 deletions Engine/include/BasicComponents/Physics3D.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@

#include "Interface/IComponent.hpp"
#include "Object.hpp"
#ifdef _DEBUG
#include "BasicComponents/DynamicSprite.hpp"
#endif

enum class CollisionDetectionMode
{
Expand All @@ -29,13 +26,7 @@ struct CollisionResult
glm::vec3 collisionNormal = { 0.f, 0.f, 0.f };
};

#ifdef _DEBUG
struct Point3D
{
glm::vec3 pos = { 0.f,0.f,0.f };
DynamicSprite* sprite = nullptr;
};
#endif


enum class BodyType3D
{
Expand Down Expand Up @@ -113,6 +104,7 @@ class Physics3D : public IComponent

//2d->3d
std::vector<glm::vec3> GetCollidePolyhedron() { return collidePolyhedron; }
float GetSphereRadius() const { return sphere.radius; }
bool CheckCollision(Object* obj);
bool CollisionPP(Object* obj, Object* obj2);
bool CollisionSS(Object* obj, Object* obj2);
Expand Down Expand Up @@ -168,8 +160,5 @@ class Physics3D : public IComponent
Sphere sphere;

//2d->3d
#ifdef _DEBUG
void AddPoint(glm::vec3 pos);
std::vector<Point3D> points;
#endif

};
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class SkeletalAnimationStateMachine : public IComponent
std::string GetCurrentStateName() const;

private:
void AddStateForQueue(const std::string& name, std::shared_ptr<SkeletalAnimation> anim);
void AddStateForQueue(const std::string& name, const std::string& animationFilePath);
void ChangeStateForQueue(const std::string& name, bool isLoop = true, float speed = 1.f, float blendDuration = 0.25f);
// Internal class representing a single animation state
class State
{
Expand Down
48 changes: 27 additions & 21 deletions Engine/include/BasicComponents/SkeletalAnimator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
#include <vector>
#include <memory>
#include <memory>
#include <map>
#include <string>

Expand All @@ -25,9 +25,9 @@ enum class PlaybackState
struct RootMotionBakeOptions
{
bool bakePositionX = false;
bool bakePositionY = true;
bool bakePositionY = true; // Remove vertical movement by default
bool bakePositionZ = false;
bool bakeRotation = true;
bool bakeRotation = true; // Remove rotation by default
};

class SkeletalAnimator : public IComponent
Expand All @@ -39,16 +39,17 @@ class SkeletalAnimator : public IComponent
void Update(float dt) override;
void End() override;

// Animation Control
void PlayAnimation(SkeletalAnimation* newAnimation, bool isLoop = true, float speed = 1.f, float blendDuration = 0.25f);

void Play();
void Pause();
void Stop();

// Getters
SkeletalAnimation* GetCurrentAnimation() const { return currentAnimation; }
const std::vector<glm::mat4>& GetFinalBoneMatrices() const;
const std::vector<glm::mat4>& GetFinalBoneMatrices() const { return finalBoneMatrices; }
const std::map<std::string, glm::mat4>& GetGlobalBoneTransforms() const { return globalBoneTransforms; }
float GetCurrentAnimationTime() const;
float GetCurrentAnimationTime() const { return currentTime; }
float GetDuration() const;
float GetSpeed() const { return animationSpeed; }
const RootMotionBakeOptions& GetBakeOptions() const { return bakeOptions; }
Expand All @@ -59,47 +60,52 @@ class SkeletalAnimator : public IComponent
const std::string& GetRootBoneName() const { return rootBoneName; }
bool IsScrubbing() const { return isScrubbing; }

void SetLooping(bool loop);
void SetCurrentAnimationTime(float time);
// Setters
void SetLooping(bool loop) { isLooping = loop; };
void SetCurrentAnimationTime(float time) { currentTime = time; justLooped = false; };
void SetSpeed(float speed) { animationSpeed = std::max(0.0f, speed); }
void SetEnableRootMotion(bool enabled) { enableRootMotion = enabled; }
void SetBakeOptions(const RootMotionBakeOptions& options) { bakeOptions = options; }
void SetRootBoneName(const std::string& name) { rootBoneName = name; }
void SetIsScrubbing(bool scrubbing) { isScrubbing = scrubbing; }

// Immediately updates root motion transform based on absolute time
// Apply root motion transform directly for scrubbing or stopping
void UpdateRootMotionTransformToTime(float time);

private:
glm::mat4 CalculateAbsoluteRootMotion(SkeletalAnimation* anim, float time, glm::mat4 startTransform);
glm::mat4 GetRootTransformAtTime(SkeletalAnimation* anim, float time);
glm::mat4 ExtractRootMotionDelta(SkeletalAnimation* anim, float timeStart, float timeEnd);

void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform, const glm::mat4& encodeMatrix, bool parentIsDummy = false);
bool HasDummyNodeParent(const AssimpNodeData* node, const std::string& boneName) const;

void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform);

// Skinning and bone hierarchy
// Skinning Data
std::vector<glm::mat4> finalBoneMatrices;
std::map<std::string, glm::mat4> globalBoneTransforms;

// Current animation state
// Current Animation State
SkeletalAnimation* currentAnimation = nullptr;
PlaybackState playbackState = PlaybackState::Stopped;
float currentTime = 0.0f;
float animationSpeed = 1.0f;
bool isLooping = true;
bool justLooped = false;
bool isLooping = true;
bool justLooped = false;

// Blending
// Blending Data
SkeletalAnimation* previousAnimation = nullptr;
float previousTime = 0.0f;
float blendFactor = 1.0f;
float currentBlendDuration = 0.0f;
float lastRootMotionTime = 0.0f;

// Root motion
bool enableRootMotion = false;
bool isScrubbing = false; // Whether the UI slider is being manipulated
// Root Motion Data
bool enableRootMotion = false;
bool isScrubbing = false;
std::string rootBoneName = "";
RootMotionBakeOptions bakeOptions;
glm::mat4 rootMotionStartTransform = glm::mat4(1.0f);
glm::mat4 previousRootMotionStartTransform = glm::mat4(1.0f);

// Hierarchy

const int maxBones = 128;
};
10 changes: 7 additions & 3 deletions Engine/include/BufferWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ struct BufferWrapper
// std::unique_ptr<DXConstantBuffer<ThreeDimension::FragmentUniform>>
// > fragmentUniformBuffer;
// std::variant<
// std::monostate,
// std::unique_ptr<GLUniformBuffer<ThreeDimension::Material>>,
// std::unique_ptr<DXConstantBuffer<ThreeDimension::Material>>
// std::monostate,
// std::unique_ptr<GLUniformBuffer<ThreeDimension::Material>>,
// std::unique_ptr<DXConstantBuffer<ThreeDimension::Material>>
// > materialUniformBuffer;
//
// void Initialize()
Expand Down Expand Up @@ -279,6 +279,10 @@ struct BufferWrapper
std::map<std::string, ThreeDimension::BoneInfo> boneInfoMap;
int boneCount = 0;

// Global inverse transform from the MODEL's root node (not animation file)
glm::mat4 modelGlobalInverseTransform{ 1.0f };
glm::mat4 meshNormalizationTransform{ 1.0f };

// GPU Buffers
//std::variant<std::monostate, GLBuffer, VKBuffer, DXBuffer> buffer;
std::variant<
Expand Down
8 changes: 8 additions & 0 deletions Engine/include/ComponentTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ inline ComponentTypes StringToComponent(const std::string& string)
return ComponentTypes::PHYSICS3D;
else if (string == "LIGHT")
return ComponentTypes::LIGHT;
else if (string == "SKETANIMATOR")
return ComponentTypes::SKETANIMATOR;
else if (string == "SKETANIMASTATE")
return ComponentTypes::SKETANIMASTATE;

return ComponentTypes::INVALID;
}
Expand All @@ -39,6 +43,10 @@ inline std::string ComponentToString(ComponentTypes type)
return "PHYSICS3D";
else if (type == ComponentTypes::LIGHT)
return "LIGHT";
else if (type == ComponentTypes::SKETANIMATOR)
return "SKETANIMATOR";
else if (type == ComponentTypes::SKETANIMASTATE)
return "SKETANIMASTATE";

return "INVALID";
}
1 change: 1 addition & 0 deletions Engine/include/Logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class LogCategory
Level,
Object,
Physics,
SkelAnimation,
Sound,
Camera,
Game,
Expand Down
17 changes: 9 additions & 8 deletions Engine/include/Material.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ namespace ThreeDimension

struct alignas(16) Vertex
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 uv;
glm::vec3 position{};
glm::vec3 normal{};
glm::vec2 uv{};
int texSubIndex{ 0 };

int boneIDs[MAX_BONE_INFLUENCE];
float weights[MAX_BONE_INFLUENCE];
// Initialize bone data with default values
int boneIDs[MAX_BONE_INFLUENCE]{ -1, -1, -1, -1 };
float weights[MAX_BONE_INFLUENCE]{ 0.0f, 0.0f, 0.0f, 0.0f };
};

// @TODO Should add alignas(16) for 3D pipeline but mesh pipeline does not require alignas(16) for Structured Buffer
Expand All @@ -75,8 +76,8 @@ namespace ThreeDimension
int texSubIndex{ 0 };

// Bone IDs and Weights (For simplicity in this guide, we use raw types not packed)
glm::ivec4 boneIDs;
glm::vec4 weights;
int boneIDs[MAX_BONE_INFLUENCE];
float weights[MAX_BONE_INFLUENCE];
};

// For StaticSprite, Check Material.hpp ThreeDimension::DynamicQuantizedVertex for StaticQuantizedVertex
Expand All @@ -102,7 +103,7 @@ namespace ThreeDimension
glm::mat4 decode;
glm::vec4 color;
// @TODO move to push constants later
glm::vec3 viewPosition;
glm::vec4 viewPosition;

// Array of final bone matrices for shader
glm::mat4 finalBones[MAX_BONES];
Expand Down
Loading
Loading