Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions Resources/Engine/Lua/Components/SkinnedMeshRenderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ function SkinnedMeshRenderer:SetPlaybackSpeed(speed) end
---@return number
function SkinnedMeshRenderer:GetPlaybackSpeed() end

--- Sets the bounds scale used during frustum culling for skinned meshes
--- Values below 1.0 are clamped to 1.0
---@param scale number
function SkinnedMeshRenderer:SetMeshBoundsScale(scale) end

--- Returns the bounds scale used during frustum culling for skinned meshes
--- Returned value is always >= 1.0
---@return number
function SkinnedMeshRenderer:GetMeshBoundsScale() end

--- Sets playback time in seconds
---@param timeSeconds number
function SkinnedMeshRenderer:SetTime(timeSeconds) end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,4 @@ namespace OvCore::ECS::Components
{
static constexpr std::string_view Name = "class OvCore::ECS::Components::CModelRenderer";
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ namespace OvCore::ECS::Components
*/
float GetPlaybackSpeed() const;

/**
* Returns the scale applied to mesh bounds during frustum culling
* Returned value is always >= 1.0f
*/
float GetMeshBoundsScale() const;

/**
* Sets the scale applied to mesh bounds during frustum culling
* Any value below 1.0f will be clamped to 1.0f
* @param p_scale
*/
void SetMeshBoundsScale(float p_scale);

/**
* Sets the current playback time in seconds
* @param p_timeSeconds
Expand Down Expand Up @@ -187,6 +200,7 @@ namespace OvCore::ECS::Components
bool m_playing = true;
bool m_looping = true;
float m_playbackSpeed = 1.0f;
float m_meshBoundsScale = 1.5f;
float m_poseEvaluationRate = 60.0f;
float m_poseEvaluationAccumulator = 0.0f;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ namespace OvCore::Rendering
const OvMaths::FMatrix4* matrices = nullptr;
uint32_t count = 0;
uint64_t poseVersion = 0;
float boundsScale = 1.0f;
};
}
14 changes: 14 additions & 0 deletions Sources/OvCore/src/OvCore/ECS/Components/CSkinnedMeshRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ float OvCore::ECS::Components::CSkinnedMeshRenderer::GetPlaybackSpeed() const
return m_playbackSpeed;
}

float OvCore::ECS::Components::CSkinnedMeshRenderer::GetMeshBoundsScale() const
{
return m_meshBoundsScale;
}

void OvCore::ECS::Components::CSkinnedMeshRenderer::SetMeshBoundsScale(float p_scale)
{
m_meshBoundsScale = std::max(1.0f, p_scale);
}

void OvCore::ECS::Components::CSkinnedMeshRenderer::SetTime(float p_timeSeconds)
{
if (!HasCompatibleModel() || !m_animationIndex.has_value())
Expand Down Expand Up @@ -347,6 +357,7 @@ void OvCore::ECS::Components::CSkinnedMeshRenderer::OnSerialize(tinyxml2::XMLDoc
OvCore::Helpers::Serializer::SerializeBoolean(p_doc, p_node, "playing", m_playing);
OvCore::Helpers::Serializer::SerializeBoolean(p_doc, p_node, "looping", m_looping);
OvCore::Helpers::Serializer::SerializeFloat(p_doc, p_node, "playback_speed", m_playbackSpeed);
OvCore::Helpers::Serializer::SerializeFloat(p_doc, p_node, "mesh_bounds_scale", m_meshBoundsScale);
OvCore::Helpers::Serializer::SerializeFloat(p_doc, p_node, "pose_eval_rate", m_poseEvaluationRate);
OvCore::Helpers::Serializer::SerializeFloat(p_doc, p_node, "time_ticks", m_currentTimeTicks);
OvCore::Helpers::Serializer::SerializeString(p_doc, p_node, "animation", GetActiveAnimationName().value_or(std::string{}));
Expand All @@ -357,9 +368,11 @@ void OvCore::ECS::Components::CSkinnedMeshRenderer::OnDeserialize(tinyxml2::XMLD
OvCore::Helpers::Serializer::DeserializeBoolean(p_doc, p_node, "playing", m_playing);
OvCore::Helpers::Serializer::DeserializeBoolean(p_doc, p_node, "looping", m_looping);
OvCore::Helpers::Serializer::DeserializeFloat(p_doc, p_node, "playback_speed", m_playbackSpeed);
OvCore::Helpers::Serializer::DeserializeFloat(p_doc, p_node, "mesh_bounds_scale", m_meshBoundsScale);
OvCore::Helpers::Serializer::DeserializeFloat(p_doc, p_node, "pose_eval_rate", m_poseEvaluationRate);
OvCore::Helpers::Serializer::DeserializeFloat(p_doc, p_node, "time_ticks", m_currentTimeTicks);
OvCore::Helpers::Serializer::DeserializeString(p_doc, p_node, "animation", m_deserializedAnimationName);
SetMeshBoundsScale(m_meshBoundsScale);
m_poseEvaluationRate = std::max(0.0f, m_poseEvaluationRate);
m_poseEvaluationAccumulator = 0.0f;

Expand All @@ -375,6 +388,7 @@ void OvCore::ECS::Components::CSkinnedMeshRenderer::OnInspector(OvUI::Internal::
GUIDrawer::DrawBoolean(p_root, "Playing", m_playing);
GUIDrawer::DrawBoolean(p_root, "Looping", m_looping);
GUIDrawer::DrawScalar<float>(p_root, "Playback Speed", m_playbackSpeed, 0.01f, -10.0f, 10.0f);
GUIDrawer::DrawScalar<float>(p_root, "Mesh Bounds Scale", m_meshBoundsScale, 0.05f, 1.0f, 10.0f);
GUIDrawer::DrawScalar<float>(p_root, "Pose Eval Rate", m_poseEvaluationRate, 1.0f, 0.0f, 240.0f);
m_poseEvaluationRate = std::max(0.0f, m_poseEvaluationRate);
GUIDrawer::DrawScalar<float>(
Expand Down
17 changes: 12 additions & 5 deletions Sources/OvCore/src/OvCore/Rendering/SceneRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ SceneRenderer::SceneDrawablesDescriptor OvCore::Rendering::SceneRenderer::ParseS
if (!materialRenderer) continue;
const auto* skinnedRenderer = owner.GetComponent<CSkinnedMeshRenderer>();
const bool hasSkinning = SkinningUtils::IsSkinningActive(skinnedRenderer);

const auto& transform = owner.transform.GetFTransform();
const auto& materials = materialRenderer->GetMaterials();

Expand Down Expand Up @@ -314,7 +314,7 @@ SceneRenderer::SceneDrawablesDescriptor OvCore::Rendering::SceneRenderer::ParseS
drawable.AddDescriptor<SceneDrawableDescriptor>({
.actor = modelRenderer->owner,
.visibilityFlags = materialRenderer->GetVisibilityFlags(),
.bounds = bounds,
.bounds = bounds
});

drawable.AddDescriptor<EngineDrawableDescriptor>({
Expand Down Expand Up @@ -359,7 +359,8 @@ SceneRenderer::SceneFilteredDrawablesDescriptor OvCore::Rendering::SceneRenderer
for (const auto& drawable : p_drawables.drawables)
{
const auto& desc = drawable.GetDescriptor<SceneDrawableDescriptor>();
const bool hasSkinningDescriptor = drawable.HasDescriptor<SkinningDrawableDescriptor>();
OvTools::Utils::OptRef<const SkinningDrawableDescriptor> skinningDescriptor;
const bool hasSkinningDescriptor = drawable.TryGetDescriptor<SkinningDrawableDescriptor>(skinningDescriptor);

// Skip drawables that do not satisfy the required visibility flags
if (!SatisfiesVisibility(desc.visibilityFlags, p_filteringInput.requiredVisibilityFlags))
Expand All @@ -386,11 +387,17 @@ SceneRenderer::SceneFilteredDrawablesDescriptor OvCore::Rendering::SceneRenderer
}

// Perform frustum culling if enabled
if (frustum && desc.bounds.has_value() && !hasSkinningDescriptor)
if (frustum && desc.bounds.has_value())
{
ZoneScopedN("Frustum Culling");

if (!frustum->BoundingSphereInFrustum(desc.bounds.value(), desc.actor.transform.GetFTransform()))
auto cullingBounds = desc.bounds.value();
if (hasSkinningDescriptor)
{
cullingBounds.radius *= skinningDescriptor->boundsScale;
}

if (!frustum->BoundingSphereInFrustum(cullingBounds, desc.actor.transform.GetFTransform()))
{
continue; // Skip this drawable as it's outside the frustum
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/OvCore/src/OvCore/Rendering/SkinningUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ void OvCore::Rendering::SkinningUtils::ApplyDescriptor(
p_drawable.SetDescriptor<OvCore::Rendering::SkinningDrawableDescriptor>({
.matrices = boneMatrices.data(),
.count = static_cast<uint32_t>(boneMatrices.size()),
.poseVersion = p_renderer.GetPoseVersion()
.poseVersion = p_renderer.GetPoseVersion(),
.boundsScale = p_renderer.GetMeshBoundsScale()
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ void BindLuaComponents(sol::state& p_luaState)
"IsLooping", &CSkinnedMeshRenderer::IsLooping,
"SetPlaybackSpeed", &CSkinnedMeshRenderer::SetPlaybackSpeed,
"GetPlaybackSpeed", &CSkinnedMeshRenderer::GetPlaybackSpeed,
"SetMeshBoundsScale", &CSkinnedMeshRenderer::SetMeshBoundsScale,
"GetMeshBoundsScale", &CSkinnedMeshRenderer::GetMeshBoundsScale,
"SetTime", &CSkinnedMeshRenderer::SetTime,
"GetTime", &CSkinnedMeshRenderer::GetTime,
"GetAnimationCount", &CSkinnedMeshRenderer::GetAnimationCount,
Expand Down