EMotion FX: Extendable pose data and pose debug visualization (#6639)

* Added debug draw function to the pose class for sharable and easy-to-use pose debug visualization that includes pose data debug rendering.
* Extended the pose data factory with the ability to add pose data types from outside of the EMFX SDK and external gems.
* In order to get access to the pose data factory, it got added to the EMFX manager.

Signed-off-by: Benjamin Jillich <jillich@amazon.com>
This commit is contained in:
Benjamin Jillich
2022-01-05 09:10:12 +01:00
committed by GitHub
parent bfb1d0ad9e
commit 40ca1dcbf9
7 changed files with 86 additions and 16 deletions
@@ -6,7 +6,6 @@
*
*/
// include the required headers
#include "EMotionFXConfig.h"
#include "EMotionFXManager.h"
#include "Importer/Importer.h"
@@ -29,6 +28,7 @@
#include <EMotionFX/Source/Allocators.h>
#include <EMotionFX/Source/DebugDraw.h>
#include <EMotionFX/Source/MotionData/MotionDataFactory.h>
#include <EMotionFX/Source/PoseDataFactory.h>
#include <Integration/Rendering/RenderActorSettings.h>
namespace EMotionFX
@@ -76,6 +76,7 @@ namespace EMotionFX
gEMFX.Get()->SetRecorder (Recorder::Create());
gEMFX.Get()->SetMotionInstancePool (MotionInstancePool::Create());
gEMFX.Get()->SetDebugDraw (aznew DebugDraw());
gEMFX.Get()->SetPoseDataFactory (aznew PoseDataFactory());
gEMFX.Get()->SetGlobalSimulationSpeed (1.0f);
// set the number of threads
@@ -124,6 +125,7 @@ namespace EMotionFX
m_recorder = nullptr;
m_motionInstancePool = nullptr;
m_debugDraw = nullptr;
m_poseDataFactory = nullptr;
m_unitType = MCore::Distance::UNITTYPE_METERS;
m_globalSimulationSpeed = 1.0f;
m_isInEditorMode = false;
@@ -170,6 +172,9 @@ namespace EMotionFX
delete m_debugDraw;
m_debugDraw = nullptr;
delete m_poseDataFactory;
m_poseDataFactory = nullptr;
m_renderActorSettings.reset();
m_eventManager->Destroy();
@@ -37,6 +37,7 @@ namespace EMotionFX
class MotionInstancePool;
class EventDataFactory;
class DebugDraw;
class PoseDataFactory;
// versions
#define EMFX_HIGHVERSION 4
@@ -188,6 +189,8 @@ namespace EMotionFX
*/
MCORE_INLINE DebugDraw* GetDebugDraw() const { return m_debugDraw; }
MCORE_INLINE PoseDataFactory* GetPoseDataFactory() const { return m_poseDataFactory; }
/**
* Get the render actor settings
* @result A pointer to global render actor settings.
@@ -357,6 +360,7 @@ namespace EMotionFX
EventManager* m_eventManager; /**< The motion event manager. */
SoftSkinManager* m_softSkinManager; /**< The softskin manager. */
AnimGraphManager* m_animGraphManager; /**< The animgraph manager. */
PoseDataFactory* m_poseDataFactory;
Recorder* m_recorder; /**< The recorder. */
MotionInstancePool* m_motionInstancePool; /**< The motion instance pool. */
DebugDraw* m_debugDraw; /**< The debug drawing system. */
@@ -433,6 +437,8 @@ namespace EMotionFX
*/
void SetMotionInstancePool(MotionInstancePool* pool);
void SetPoseDataFactory(PoseDataFactory* poseDataFactory) { m_poseDataFactory = poseDataFactory; }
/**
* Set the number of threads to use.
* @param numThreads The number of threads to use internally. This must be a value of 1 or above.
@@ -520,5 +526,6 @@ namespace EMotionFX
MCORE_INLINE Recorder& GetRecorder() { return *GetEMotionFX().GetRecorder(); } /**< Get the recorder. */
MCORE_INLINE MotionInstancePool& GetMotionInstancePool() { return *GetEMotionFX().GetMotionInstancePool(); } /**< Get the motion instance pool. */
MCORE_INLINE DebugDraw& GetDebugDraw() { return *GetEMotionFX().GetDebugDraw(); } /**< Get the debug drawing. */
MCORE_INLINE PoseDataFactory& GetPoseDataFactory() { return *GetEMotionFX().GetPoseDataFactory(); }
MCORE_INLINE AZ::Render::RenderActorSettings& GetRenderActorSettings() { return *GetEMotionFX().GetRenderActorSettings(); }/**< Get the render actor settings. */
} // namespace EMotionFX
+35 -1
View File
@@ -1428,4 +1428,38 @@ namespace EMotionFX
GetEMotionFX().GetThreadData(m_actorInstance->GetThreadIndex())->GetPosePool().FreePose(tempPose);
}
} // namespace EMotionFX
void Pose::DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Color& color, bool drawPoseDatas) const
{
debugDisplay.SetColor(color);
debugDisplay.DepthTestOff();
const Skeleton* skeleton = m_actorInstance->GetActor()->GetSkeleton();
const size_t numEnabledJoints = m_actorInstance->GetNumEnabledNodes();
for (size_t i = 0; i < numEnabledJoints; ++i)
{
const size_t jointIndex = m_actorInstance->GetEnabledNode(i);
const size_t parentIndex = skeleton->GetNode(jointIndex)->GetParentIndex();
if (parentIndex != InvalidIndex)
{
const AZ::Vector3 startPos = GetWorldSpaceTransform(jointIndex).m_position;
const AZ::Vector3 endPos = GetWorldSpaceTransform(parentIndex).m_position;
debugDisplay.DrawSolidCylinder(/*center=*/(startPos + endPos) * 0.5f,
/*direction=*/(endPos - startPos).GetNormalizedSafe(),
/*radius=*/0.005f,
/*height=*/(endPos - startPos).GetLength(),
/*drawShaded=*/false);
}
}
if (drawPoseDatas)
{
for (const auto& poseDataItem : m_poseDatas)
{
PoseData* poseData = poseDataItem.second.get();
poseData->DebugDraw(debugDisplay, color);
}
}
}
} // namespace EMotionFX
+9 -5
View File
@@ -10,10 +10,10 @@
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <EMotionFX/Source/PoseData.h>
#include <EMotionFX/Source/Transform.h>
namespace EMotionFX
{
// forward declarations
@@ -25,10 +25,6 @@ namespace EMotionFX
class Skeleton;
class MotionLinkData;
/**
*
*
*/
class EMFX_API Pose
{
MCORE_MEMORYOBJECTCATEGORY(Pose, EMFX_DEFAULT_ALIGNMENT, EMFX_MEMCATEGORY_POSE);
@@ -192,6 +188,14 @@ namespace EMotionFX
template <class T>
T* GetAndPreparePoseData(ActorInstance* linkToActorInstance) { return azdynamic_cast<T*>(GetAndPreparePoseData(azrtti_typeid<T>(), linkToActorInstance)); }
/**
* Draw debug visualization for the given pose.
* @param[in] debugDisplay Debug display request bus to spawn the render commands.
* @param[in] color The color the skeletal pose should be in.
* @param[in] drawPoseDatas Draw the pose data debug visualizations (e.g. joint velocities) along with the actual skeletal pose. [Default = false]
*/
void DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Color& color, bool drawPoseDatas = false) const;
private:
mutable AZStd::vector<Transform> m_localSpaceTransforms;
mutable AZStd::vector<Transform> m_modelSpaceTransforms;
@@ -12,9 +12,9 @@
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <EMotionFX/Source/EMotionFXConfig.h>
namespace EMotionFX
{
class Actor;
@@ -40,6 +40,8 @@ namespace EMotionFX
virtual void Blend(const Pose* destPose, float weight) = 0;
virtual void DebugDraw([[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay, [[maybe_unused]] const AZ::Color& color) const {}
bool IsUsed() const { return m_isUsed; }
void SetIsUsed(bool isUsed) { m_isUsed = isUsed; }
@@ -8,13 +8,20 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <EMotionFX/Source/Allocators.h>
#include <EMotionFX/Source/EMotionFXConfig.h>
#include <EMotionFX/Source/PoseDataFactory.h>
#include <EMotionFX/Source/PoseDataRagdoll.h>
namespace EMotionFX
{
AZ_CLASS_ALLOCATOR_IMPL(PoseDataFactory, PoseAllocator, 0)
PoseDataFactory::PoseDataFactory()
{
AddPoseDataType(azrtti_typeid<PoseDataRagdoll>());
}
PoseData* PoseDataFactory::Create(Pose* pose, const AZ::TypeId& type)
{
AZ::SerializeContext* context = nullptr;
@@ -34,13 +41,13 @@ namespace EMotionFX
return result;
}
const AZStd::unordered_set<AZ::TypeId>& PoseDataFactory::GetTypeIds()
void PoseDataFactory::AddPoseDataType(const AZ::TypeId& poseDataType)
{
static AZStd::unordered_set<AZ::TypeId> typeIds =
{
azrtti_typeid<PoseDataRagdoll>()
};
m_poseDataTypeIds.emplace(poseDataType);
}
return typeIds;
const AZStd::unordered_set<AZ::TypeId>& PoseDataFactory::GetTypeIds() const
{
return m_poseDataTypeIds;
}
} // namespace EMotionFX
@@ -25,7 +25,18 @@ namespace EMotionFX
class EMFX_API PoseDataFactory
{
public:
AZ_RTTI(PoseDataFactory, "{F10014A0-2B6A-44E5-BA53-0E11ED566701}")
AZ_CLASS_ALLOCATOR_DECL
PoseDataFactory();
virtual ~PoseDataFactory() = default;
static PoseData* Create(Pose* pose, const AZ::TypeId& type);
static const AZStd::unordered_set<AZ::TypeId>& GetTypeIds();
void AddPoseDataType(const AZ::TypeId& poseDataType);
const AZStd::unordered_set<AZ::TypeId>& GetTypeIds() const;
private:
AZStd::unordered_set<AZ::TypeId> m_poseDataTypeIds;
};
} // namespace EMotionFX