[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.
This commit is contained in:
Benjamin Jillich
2021-06-08 08:41:58 +02:00
committed by GitHub
parent 4e79e6004c
commit 863aac2cb9
4 changed files with 130 additions and 3 deletions
@@ -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.
@@ -18,6 +18,7 @@
#include <Integration/System/SystemCommon.h>
#include <Integration/System/SystemComponent.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/DebugDraw.h>
#include <EMotionFX/Source/MorphSetup.h>
#include <EMotionFX/Source/MorphSetupInstance.h>
#include <EMotionFX/Source/MorphTargetStandard.h>
@@ -27,6 +28,8 @@
#include <EMotionFX/Source/Node.h>
#include <MCore/Source/AzCoreConversions.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
@@ -57,6 +60,8 @@ namespace AZ
Activate();
AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId);
}
m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity<RPI::AuxGeomFeatureProcessorInterface>(m_entityId);
}
AtomActorInstance::~AtomActorInstance()
@@ -88,7 +93,119 @@ namespace AZ
AZ::Interface<AzFramework::IEntityBoundsUnion>::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<EMotionFX::DebugDraw::Line>& 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;
}
@@ -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<AZ::Vector3> m_auxVertices;
AZStd::vector<AZ::Color> m_auxColors;
AZStd::intrusive_ptr<AZ::Render::SkinnedMeshInputBuffers> m_skinnedMeshInputBuffers = nullptr;
AZStd::intrusive_ptr<SkinnedMeshInstance> m_skinnedMeshInstance;
AZ::Data::Instance<AZ::RPI::Buffer> m_boneTransforms = nullptr;
@@ -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);
}
}