From c266b98e05691c42c1e00c0b86def5bdbcbe8d1d Mon Sep 17 00:00:00 2001 From: Gopmyc Date: Sun, 30 Aug 2026 13:25:38 +0200 Subject: [PATCH 1/2] Expose global bone transforms on skinned mesh renderers --- .../ECS/Components/CSkinnedMeshRenderer.h | 21 +++++++ .../ECS/Components/CSkinnedMeshRenderer.cpp | 59 ++++++++++++++++--- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/Sources/OvCore/include/OvCore/ECS/Components/CSkinnedMeshRenderer.h b/Sources/OvCore/include/OvCore/ECS/Components/CSkinnedMeshRenderer.h index 76a4dd883..3badeef48 100644 --- a/Sources/OvCore/include/OvCore/ECS/Components/CSkinnedMeshRenderer.h +++ b/Sources/OvCore/include/OvCore/ECS/Components/CSkinnedMeshRenderer.h @@ -204,6 +204,27 @@ namespace OvCore::ECS::Components */ std::optional GetBoneLocalScale(uint32_t p_boneIndex) const; + /** + * Returns the current bone global position in skeleton/model space, excluding the owning actor's world transform + * @param p_boneIndex + * @return The bone global position, or std::nullopt if the bone index is invalid + */ + std::optional GetBoneGlobalPosition(uint32_t p_boneIndex) const; + + /** + * Returns the current bone global rotation in skeleton/model space, excluding the owning actor's world transform + * @param p_boneIndex + * @return The bone global rotation, or std::nullopt if the bone index is invalid + */ + std::optional GetBoneGlobalRotation(uint32_t p_boneIndex) const; + + /** + * Returns the current bone global scale in skeleton/model space, excluding the owning actor's world transform + * @param p_boneIndex + * @return The bone global scale, or std::nullopt if the bone index is invalid + */ + std::optional GetBoneGlobalScale(uint32_t p_boneIndex) const; + /** * Sets the local bone position * @param p_boneIndex diff --git a/Sources/OvCore/src/OvCore/ECS/Components/CSkinnedMeshRenderer.cpp b/Sources/OvCore/src/OvCore/ECS/Components/CSkinnedMeshRenderer.cpp index db3dfcced..9d4e85790 100644 --- a/Sources/OvCore/src/OvCore/ECS/Components/CSkinnedMeshRenderer.cpp +++ b/Sources/OvCore/src/OvCore/ECS/Components/CSkinnedMeshRenderer.cpp @@ -103,7 +103,7 @@ namespace return interpolate(prev, next, next.time - prev.time); } - void DecomposeLocalTransform( + void DecomposeTransform( const OvMaths::FMatrix4& p_matrix, OvMaths::FVector3& p_position, OvMaths::FQuaternion& p_rotation, @@ -571,7 +571,7 @@ std::optional OvCore::ECS::Components::CSkinnedMeshRenderer:: OvMaths::FVector3 position; OvMaths::FQuaternion rotation; OvMaths::FVector3 scale; - DecomposeLocalTransform(m_localPose[*nodeIndex], position, rotation, scale); + DecomposeTransform(m_localPose[*nodeIndex], position, rotation, scale); return position; } @@ -586,7 +586,7 @@ std::optional OvCore::ECS::Components::CSkinnedMeshRendere OvMaths::FVector3 position; OvMaths::FQuaternion rotation; OvMaths::FVector3 scale; - DecomposeLocalTransform(m_localPose[*nodeIndex], position, rotation, scale); + DecomposeTransform(m_localPose[*nodeIndex], position, rotation, scale); return rotation; } @@ -601,7 +601,52 @@ std::optional OvCore::ECS::Components::CSkinnedMeshRenderer:: OvMaths::FVector3 position; OvMaths::FQuaternion rotation; OvMaths::FVector3 scale; - DecomposeLocalTransform(m_localPose[*nodeIndex], position, rotation, scale); + DecomposeTransform(m_localPose[*nodeIndex], position, rotation, scale); + return scale; +} + +std::optional OvCore::ECS::Components::CSkinnedMeshRenderer::GetBoneGlobalPosition(uint32_t p_boneIndex) const +{ + const auto nodeIndex = GetNodeIndexFromBoneIndex(p_boneIndex); + if (!nodeIndex.has_value() || *nodeIndex >= m_globalPose.size()) + { + return std::nullopt; + } + + OvMaths::FVector3 position; + OvMaths::FQuaternion rotation; + OvMaths::FVector3 scale; + DecomposeTransform(m_globalPose[*nodeIndex], position, rotation, scale); + return position; +} + +std::optional OvCore::ECS::Components::CSkinnedMeshRenderer::GetBoneGlobalRotation(uint32_t p_boneIndex) const +{ + const auto nodeIndex = GetNodeIndexFromBoneIndex(p_boneIndex); + if (!nodeIndex.has_value() || *nodeIndex >= m_globalPose.size()) + { + return std::nullopt; + } + + OvMaths::FVector3 position; + OvMaths::FQuaternion rotation; + OvMaths::FVector3 scale; + DecomposeTransform(m_globalPose[*nodeIndex], position, rotation, scale); + return rotation; +} + +std::optional OvCore::ECS::Components::CSkinnedMeshRenderer::GetBoneGlobalScale(uint32_t p_boneIndex) const +{ + const auto nodeIndex = GetNodeIndexFromBoneIndex(p_boneIndex); + if (!nodeIndex.has_value() || *nodeIndex >= m_globalPose.size()) + { + return std::nullopt; + } + + OvMaths::FVector3 position; + OvMaths::FQuaternion rotation; + OvMaths::FVector3 scale; + DecomposeTransform(m_globalPose[*nodeIndex], position, rotation, scale); return scale; } @@ -616,7 +661,7 @@ bool OvCore::ECS::Components::CSkinnedMeshRenderer::SetBoneLocalPosition(uint32_ OvMaths::FVector3 currentPosition; OvMaths::FQuaternion currentRotation; OvMaths::FVector3 currentScale; - DecomposeLocalTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); + DecomposeTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); const OvMaths::FTransform transform(p_position, currentRotation, currentScale); m_localPose[*nodeIndex] = transform.GetLocalMatrix(); @@ -636,7 +681,7 @@ bool OvCore::ECS::Components::CSkinnedMeshRenderer::SetBoneLocalRotation(uint32_ OvMaths::FVector3 currentPosition; OvMaths::FQuaternion currentRotation; OvMaths::FVector3 currentScale; - DecomposeLocalTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); + DecomposeTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); const OvMaths::FTransform transform(currentPosition, p_rotation, currentScale); m_localPose[*nodeIndex] = transform.GetLocalMatrix(); @@ -656,7 +701,7 @@ bool OvCore::ECS::Components::CSkinnedMeshRenderer::SetBoneLocalScale(uint32_t p OvMaths::FVector3 currentPosition; OvMaths::FQuaternion currentRotation; OvMaths::FVector3 currentScale; - DecomposeLocalTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); + DecomposeTransform(m_localPose[*nodeIndex], currentPosition, currentRotation, currentScale); const OvMaths::FTransform transform(currentPosition, currentRotation, p_scale); m_localPose[*nodeIndex] = transform.GetLocalMatrix(); From f2cdf1dc963f1f409421e7e6216d0a38e0647bd2 Mon Sep 17 00:00:00 2001 From: Gopmyc Date: Sun, 30 Aug 2026 13:25:42 +0200 Subject: [PATCH 2/2] Expose global bone transforms to Lua --- .../Engine/Lua/Components/SkinnedMeshRenderer.lua | 15 +++++++++++++++ .../Lua/Bindings/LuaComponentsBindings.cpp | 3 +++ 2 files changed, 18 insertions(+) diff --git a/Resources/Engine/Lua/Components/SkinnedMeshRenderer.lua b/Resources/Engine/Lua/Components/SkinnedMeshRenderer.lua index 5790939df..f2a59f508 100644 --- a/Resources/Engine/Lua/Components/SkinnedMeshRenderer.lua +++ b/Resources/Engine/Lua/Components/SkinnedMeshRenderer.lua @@ -119,6 +119,21 @@ function SkinnedMeshRenderer:GetBoneLocalRotation(boneIndex) end ---@return Vector3|nil function SkinnedMeshRenderer:GetBoneLocalScale(boneIndex) end +--- Returns the current bone global position in skeleton/model space, excluding the owning actor's world transform, or nil +---@param boneIndex integer +---@return Vector3|nil +function SkinnedMeshRenderer:GetBoneGlobalPosition(boneIndex) end + +--- Returns the current bone global rotation in skeleton/model space, excluding the owning actor's world transform, or nil +---@param boneIndex integer +---@return Quaternion|nil +function SkinnedMeshRenderer:GetBoneGlobalRotation(boneIndex) end + +--- Returns the current bone global scale in skeleton/model space, excluding the owning actor's world transform, or nil +---@param boneIndex integer +---@return Vector3|nil +function SkinnedMeshRenderer:GetBoneGlobalScale(boneIndex) end + --- Sets local bone position ---@param boneIndex integer ---@param position Vector3 diff --git a/Sources/OvCore/src/OvCore/Scripting/Lua/Bindings/LuaComponentsBindings.cpp b/Sources/OvCore/src/OvCore/Scripting/Lua/Bindings/LuaComponentsBindings.cpp index 816842ff6..6dcaa56e9 100644 --- a/Sources/OvCore/src/OvCore/Scripting/Lua/Bindings/LuaComponentsBindings.cpp +++ b/Sources/OvCore/src/OvCore/Scripting/Lua/Bindings/LuaComponentsBindings.cpp @@ -122,6 +122,9 @@ void BindLuaComponents(sol::state& p_luaState) "GetBoneLocalPosition", &CSkinnedMeshRenderer::GetBoneLocalPosition, "GetBoneLocalRotation", &CSkinnedMeshRenderer::GetBoneLocalRotation, "GetBoneLocalScale", &CSkinnedMeshRenderer::GetBoneLocalScale, + "GetBoneGlobalPosition", &CSkinnedMeshRenderer::GetBoneGlobalPosition, + "GetBoneGlobalRotation", &CSkinnedMeshRenderer::GetBoneGlobalRotation, + "GetBoneGlobalScale", &CSkinnedMeshRenderer::GetBoneGlobalScale, "SetBoneLocalPosition", &CSkinnedMeshRenderer::SetBoneLocalPosition, "SetBoneLocalRotation", &CSkinnedMeshRenderer::SetBoneLocalRotation, "SetBoneLocalScale", &CSkinnedMeshRenderer::SetBoneLocalScale