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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user