From 863aac2cb95a5738570389be7e5881cc10541b40 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Tue, 8 Jun 2021 08:41:58 +0200 Subject: [PATCH] [LYN-3727] Actor Draw Bounds Draw Bounds & [LYN-3725] Actor Draw Skeleton Doesn't Draw Skeleton (#1168) * [LYN-3727] Actor Draw Bounds Draw Bounds & [LYN-3725] Actor Draw Skeleton Doesn't Draw Skeleton * Added skeleton, aabb and emfx debug drawing to the actor component. * Aux geom rendering is flickering as also reported in the Discord channels. Trick with using the scene notification bus did not work as the actor instance is not bound to a given scene as far as I am aware. --- .../Atom/RPI.Public/AuxGeom/AuxGeomDraw.h | 2 +- .../Code/Source/AtomActorInstance.cpp | 119 +++++++++++++++++- .../Code/Source/AtomActorInstance.h | 11 +- .../Components/EditorActorComponent.cpp | 1 + 4 files changed, 130 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h index 0e7f11e46e..525bbc1521 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h @@ -81,7 +81,7 @@ namespace AZ //! Common arguments for free polygon (point, line, Triangle) draws. struct AuxGeomDynamicDrawArguments { - const AZ::Vector3* m_verts = nullptr; //!< An array of points, 1 for each vertice. + const AZ::Vector3* m_verts = nullptr; //!< An array of points, 1 for each vertex. uint32_t m_vertCount = 0; //!< The number of vertices. const AZ::Color* m_colors; //!< An array of colors, must have either vertCount entries or 1 entry. uint32_t m_colorCount = 0; //!< The number of colors, must equal 1 or vertCount. diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 9079f639ba..532c8720b5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,8 @@ #include #include +#include +#include #include #include @@ -57,6 +60,8 @@ namespace AZ Activate(); AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId); } + + m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(m_entityId); } AtomActorInstance::~AtomActorInstance() @@ -88,7 +93,119 @@ namespace AZ AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } - AZ::Aabb AtomActorInstance:: GetWorldBounds() + void AtomActorInstance::DebugDraw(const DebugOptions& debugOptions) + { + if (m_auxGeomFeatureProcessor) + { + if (RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue()) + { + if (debugOptions.m_drawAABB) + { + const MCore::AABB emfxAabb = m_actorInstance->GetAABB(); + const AZ::Aabb azAabb = AZ::Aabb::CreateFromMinMax(emfxAabb.GetMin(), emfxAabb.GetMax()); + auxGeom->DrawAabb(azAabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); + } + + if (debugOptions.m_drawSkeleton) + { + RenderSkeleton(auxGeom.get()); + } + + if (debugOptions.m_emfxDebugDraw) + { + RenderEMFXDebugDraw(auxGeom.get()); + } + } + } + } + + void AtomActorInstance::RenderSkeleton(RPI::AuxGeomDraw* auxGeom) + { + AZ_Assert(m_actorInstance, "Valid actor instance required."); + const EMotionFX::TransformData* transformData = m_actorInstance->GetTransformData(); + const EMotionFX::Skeleton* skeleton = m_actorInstance->GetActor()->GetSkeleton(); + const EMotionFX::Pose* pose = transformData->GetCurrentPose(); + + const AZ::u32 transformCount = transformData->GetNumTransforms(); + const AZ::u32 lodLevel = m_actorInstance->GetLODLevel(); + const AZ::u32 numJoints = skeleton->GetNumNodes(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numJoints * 2); + + for (AZ::u32 jointIndex = 0; jointIndex < numJoints; ++jointIndex) + { + const EMotionFX::Node* joint = skeleton->GetNode(jointIndex); + if (!joint->GetSkeletalLODStatus(lodLevel)) + { + continue; + } + + const AZ::u32 parentIndex = joint->GetParentIndex(); + if (parentIndex == InvalidIndex32) + { + continue; + } + + const AZ::Vector3 parentPos = pose->GetWorldSpaceTransform(parentIndex).mPosition; + m_auxVertices.emplace_back(parentPos); + + const AZ::Vector3 bonePos = pose->GetWorldSpaceTransform(jointIndex).mPosition; + m_auxVertices.emplace_back(bonePos); + } + + const AZ::Color skeletonColor(0.604f, 0.804f, 0.196f, 1.0f); + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = m_auxVertices.size(); + lineArgs.m_colors = &skeletonColor; + lineArgs.m_colorCount = 1; + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + void AtomActorInstance::RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom) + { + EMotionFX::DebugDraw& debugDraw = EMotionFX::GetDebugDraw(); + debugDraw.Lock(); + EMotionFX::DebugDraw::ActorInstanceData* actorInstanceData = debugDraw.GetActorInstanceData(m_actorInstance); + actorInstanceData->Lock(); + const AZStd::vector& lines = actorInstanceData->GetLines(); + if (lines.empty()) + { + actorInstanceData->Unlock(); + debugDraw.Unlock(); + return; + } + + m_auxVertices.clear(); + m_auxVertices.reserve(lines.size() * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (const EMotionFX::DebugDraw::Line& line : actorInstanceData->GetLines()) + { + m_auxVertices.emplace_back(line.m_start); + m_auxColors.emplace_back(line.m_startColor); + m_auxVertices.emplace_back(line.m_end); + m_auxColors.emplace_back(line.m_endColor); + } + + AZ_Assert(m_auxVertices.size() == m_auxColors.size(), + "Number of vertices and number of colors need to match."); + actorInstanceData->Unlock(); + debugDraw.Unlock(); + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = m_auxVertices.size(); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = m_auxColors.size(); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + AZ::Aabb AtomActorInstance::GetWorldBounds() { return m_worldAABB; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index e05280e896..98e47e7128 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -42,6 +42,8 @@ namespace EMotionFX } namespace AZ::RPI { + class AuxGeomDraw; + class AuxGeomFeatureProcessorInterface; class Model; class Buffer; class StreamingImage; @@ -89,7 +91,7 @@ namespace AZ // RenderActorInstance overrides ... void OnTick(float timeDelta) override; void UpdateBounds() override; - void DebugDraw(const DebugOptions& debugOptions) override { AZ_UNUSED(debugOptions) }; + void DebugDraw(const DebugOptions& debugOptions) override; void SetMaterials(const EMotionFX::Integration::ActorAsset::MaterialList& materialPerLOD) override { AZ_UNUSED(materialPerLOD); }; void SetSkinningMethod(EMotionFX::Integration::SkinningMethod emfxSkinningMethod); SkinningMethod GetAtomSkinningMethod() const; @@ -177,6 +179,13 @@ namespace AZ void InitWrinkleMasks(); void UpdateWrinkleMasks(); + // Helper and debug geometry rendering + void RenderSkeleton(RPI::AuxGeomDraw* auxGeom); + void RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom); + RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr; + AZStd::vector m_auxVertices; + AZStd::vector m_auxColors; + AZStd::intrusive_ptr m_skinnedMeshInputBuffers = nullptr; AZStd::intrusive_ptr m_skinnedMeshInstance; AZ::Data::Instance m_boneTransforms = nullptr; diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index 4b4685ebb1..5c085e96f7 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -553,6 +553,7 @@ namespace EMotionFX RenderActorInstance::DebugOptions debugOptions; debugOptions.m_drawAABB = m_renderBounds; debugOptions.m_drawSkeleton = m_renderSkeleton; + debugOptions.m_emfxDebugDraw = true; m_renderActorInstance->DebugDraw(debugOptions); } }