EMotion FX: Colliders now also render without the collider plugins #7643

* Colliders only rendered in case the given plugin was active, no matter if they were enabled or not in the 3D viewport which was confusing for users. Colliders as well as ragdoll debug draw now renders independently of the plugins.
* Added debug rendering for colliders and ragdoll joint limits to the Atom debug draw class
* Automatically clear selection when closing skeleton outliner

Resolves #5982
Resolves #5980

Signed-off-by: Benjamin Jillich jillich@amazon.com
monroegm-disable-blank-issue-2
Benjamin Jillich 4 years ago committed by GitHub
commit a9d2ea660c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,6 +19,7 @@
#include <EMotionFX/Source/ActorInstance.h>
#include <EMotionFX/Source/DebugDraw.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/RagdollInstance.h>
#include <EMotionFX/Source/SubMesh.h>
#include <EMotionFX/Source/TransformData.h>
#include <EMotionFX/Source/Mesh.h>
@ -138,6 +139,35 @@ namespace AZ::Render
}
}
}
// Hit detection colliders
if (CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::HitDetectionColliders))
{
RenderColliders(debugDisplay, EMotionFX::PhysicsSetup::HitDetection, instance,
renderActorSettings.m_hitDetectionColliderColor, renderActorSettings.m_selectedHitDetectionColliderColor);
}
// Cloth colliders
if (CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::ClothColliders))
{
RenderColliders(debugDisplay, EMotionFX::PhysicsSetup::Cloth, instance,
renderActorSettings.m_clothColliderColor, renderActorSettings.m_selectedClothColliderColor);
}
// Simulated object colliders
if (CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::SimulatedObjectColliders))
{
RenderColliders(debugDisplay, EMotionFX::PhysicsSetup::SimulatedObjectCollider, instance,
renderActorSettings.m_simulatedObjectColliderColor, renderActorSettings.m_selectedSimulatedObjectColliderColor);
}
// Ragdoll
const bool renderRagdollColliders = AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::RagdollColliders);
const bool renderRagdollJointLimits = AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::RagdollJointLimits);
if (renderRagdollColliders || renderRagdollJointLimits)
{
RenderRagdoll(debugDisplay, instance, renderRagdollColliders, renderRagdollJointLimits);
}
}
float AtomActorDebugDraw::CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const
@ -813,4 +843,270 @@ namespace AZ::Render
}
}
}
void AtomActorDebugDraw::RenderColliders(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::ShapeColliderPairList& colliders,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const AZ::Color& colliderColor) const
{
if (!debugDisplay)
{
return;
}
const size_t nodeIndex = node->GetNodeIndex();
for (const auto& collider : colliders)
{
#ifndef EMFX_SCALE_DISABLED
const AZ::Vector3& worldScale = actorInstance->GetTransformData()->GetCurrentPose()->GetModelSpaceTransform(nodeIndex).m_scale;
#else
const AZ::Vector3 worldScale = AZ::Vector3::CreateOne();
#endif
const EMotionFX::Transform colliderOffsetTransform(collider.first->m_position, collider.first->m_rotation);
const EMotionFX::Transform& actorInstanceGlobalTransform = actorInstance->GetWorldSpaceTransform();
const EMotionFX::Transform& emfxNodeGlobalTransform =
actorInstance->GetTransformData()->GetCurrentPose()->GetModelSpaceTransform(nodeIndex);
const EMotionFX::Transform emfxColliderGlobalTransformNoScale =
colliderOffsetTransform * emfxNodeGlobalTransform * actorInstanceGlobalTransform;
const AZ::TypeId colliderType = collider.second->RTTI_GetType();
if (colliderType == azrtti_typeid<Physics::SphereShapeConfiguration>())
{
Physics::SphereShapeConfiguration* sphere = static_cast<Physics::SphereShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: The maximum component from the node scale will be multiplied by the radius of the sphere.
const float radius = sphere->m_radius *
MCore::Max3<float>(static_cast<float>(worldScale.GetX()), static_cast<float>(worldScale.GetY()),
static_cast<float>(worldScale.GetZ()));
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireSphere(emfxColliderGlobalTransformNoScale.m_position, radius);
}
else if (colliderType == azrtti_typeid<Physics::CapsuleShapeConfiguration>())
{
Physics::CapsuleShapeConfiguration* capsule = static_cast<Physics::CapsuleShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: The maximum of the X/Y scale components of the node scale will be multiplied by the radius of
// the capsule. The Z component of the entity scale will be multiplied by the height of the capsule.
const float radius =
capsule->m_radius * MCore::Max<float>(static_cast<float>(worldScale.GetX()), static_cast<float>(worldScale.GetY()));
const float height = capsule->m_height * static_cast<float>(worldScale.GetZ());
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireCapsule(
emfxColliderGlobalTransformNoScale.m_position, emfxColliderGlobalTransformNoScale.ToAZTransform().GetBasisZ(), radius, height);
}
else if (colliderType == azrtti_typeid<Physics::BoxShapeConfiguration>())
{
Physics::BoxShapeConfiguration* box = static_cast<Physics::BoxShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: Each component of the box dimensions will be scaled by the node's world scale.
AZ::Vector3 dimensions = box->m_dimensions;
dimensions *= worldScale;
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireBox(
emfxColliderGlobalTransformNoScale.m_position, emfxColliderGlobalTransformNoScale.m_position + dimensions);
}
}
}
void AtomActorDebugDraw::RenderColliders(AzFramework::DebugDisplayRequests* debugDisplay,
EMotionFX::PhysicsSetup::ColliderConfigType colliderConfigType,
EMotionFX::ActorInstance* actorInstance,
const AZ::Color& defaultColor,
const AZ::Color& selectedColor) const
{
if (colliderConfigType == EMotionFX::PhysicsSetup::Unknown)
{
return;
}
const EMotionFX::Actor* actor = actorInstance->GetActor();
const AZStd::shared_ptr<EMotionFX::PhysicsSetup>& physicsSetup = actor->GetPhysicsSetup();
const Physics::CharacterColliderConfiguration* colliderConfig = physicsSetup->GetColliderConfigByType(colliderConfigType);
if (colliderConfig)
{
const AZStd::unordered_set<size_t>* cachedSelectedJointIndices;
EMotionFX::JointSelectionRequestBus::BroadcastResult(
cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, actorInstance);
for (const Physics::CharacterColliderNodeConfiguration& nodeConfig : colliderConfig->m_nodes)
{
const EMotionFX::Node* joint = actor->GetSkeleton()->FindNodeByName(nodeConfig.m_name.c_str());
if (joint)
{
const bool jointSelected = cachedSelectedJointIndices &&
(cachedSelectedJointIndices->empty() || cachedSelectedJointIndices->find(joint->GetNodeIndex()) != cachedSelectedJointIndices->end());
const AzPhysics::ShapeColliderPairList& colliders = nodeConfig.m_shapes;
RenderColliders(debugDisplay, colliders, actorInstance, joint, jointSelected ? selectedColor : defaultColor);
}
}
}
}
void AtomActorDebugDraw::RenderJointFrame(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::JointConfiguration& configuration,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const AZ::Color& color) const
{
const EMotionFX::Transform& actorInstanceWorldSpaceTransform = actorInstance->GetWorldSpaceTransform();
const EMotionFX::Pose* currentPose = actorInstance->GetTransformData()->GetCurrentPose();
const EMotionFX::Transform childJointLocalSpaceTransform(AZ::Vector3::CreateZero(), configuration.m_childLocalRotation);
const EMotionFX::Transform childModelSpaceTransform =
childJointLocalSpaceTransform * currentPose->GetModelSpaceTransform(node->GetNodeIndex());
const EMotionFX::Transform jointChildWorldSpaceTransformNoScale = (childModelSpaceTransform * actorInstanceWorldSpaceTransform);
AZ::Vector3 dir = jointChildWorldSpaceTransformNoScale.ToAZTransform().GetBasisX();
debugDisplay->SetColor(color);
debugDisplay->DrawArrow(jointChildWorldSpaceTransformNoScale.m_position, jointChildWorldSpaceTransformNoScale.m_position + dir, 0.1f);
}
void AtomActorDebugDraw::JointLimitRenderData::Clear()
{
m_vertexBuffer.clear();
m_indexBuffer.clear();
m_lineBuffer.clear();
m_lineValidityBuffer.clear();
}
void AtomActorDebugDraw::RenderJointLimit(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::JointConfiguration& configuration,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const EMotionFX::Node* parentNode,
const AZ::Color& regularColor,
const AZ::Color& violatedColor)
{
const size_t nodeIndex = node->GetNodeIndex();
const size_t parentNodeIndex = parentNode->GetNodeIndex();
const EMotionFX::Transform& actorInstanceWorldTransform = actorInstance->GetWorldSpaceTransform();
const EMotionFX::Pose* currentPose = actorInstance->GetTransformData()->GetCurrentPose();
const AZ::Quaternion& parentOrientation = currentPose->GetModelSpaceTransform(parentNodeIndex).m_rotation;
const AZ::Quaternion& childOrientation = currentPose->GetModelSpaceTransform(nodeIndex).m_rotation;
m_jointLimitRenderData.Clear();
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
jointHelpers->GenerateJointLimitVisualizationData(
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions,
m_jointLimitRenderData.m_vertexBuffer, m_jointLimitRenderData.m_indexBuffer,
m_jointLimitRenderData.m_lineBuffer, m_jointLimitRenderData.m_lineValidityBuffer);
}
EMotionFX::Transform jointModelSpaceTransform = currentPose->GetModelSpaceTransform(parentNodeIndex);
jointModelSpaceTransform.m_position = currentPose->GetModelSpaceTransform(nodeIndex).m_position;
const EMotionFX::Transform jointGlobalTransformNoScale = jointModelSpaceTransform * actorInstanceWorldTransform;
const size_t numLineBufferEntries = m_jointLimitRenderData.m_lineBuffer.size();
if (m_jointLimitRenderData.m_lineValidityBuffer.size() * 2 != numLineBufferEntries)
{
AZ_ErrorOnce("EMotionFX", false, "Unexpected buffer size in joint limit visualization for node %s", node->GetName());
return;
}
for (size_t i = 0; i < numLineBufferEntries; i += 2)
{
const AZ::Color& lineColor = m_jointLimitRenderData.m_lineValidityBuffer[i / 2] ? regularColor : violatedColor;
debugDisplay->DepthTestOff();
debugDisplay->DrawLine(
jointGlobalTransformNoScale.TransformPoint(m_jointLimitRenderData.m_lineBuffer[i]),
jointGlobalTransformNoScale.TransformPoint(m_jointLimitRenderData.m_lineBuffer[i + 1]), lineColor.GetAsVector4(), lineColor.GetAsVector4()
);
}
}
void AtomActorDebugDraw::RenderRagdoll(AzFramework::DebugDisplayRequests* debugDisplay,
EMotionFX::ActorInstance* actorInstance,
bool renderColliders,
bool renderJointLimits)
{
const EMotionFX::Actor* actor = actorInstance->GetActor();
const EMotionFX::Skeleton* skeleton = actor->GetSkeleton();
const size_t numNodes = skeleton->GetNumNodes();
const AZStd::shared_ptr<EMotionFX::PhysicsSetup>& physicsSetup = actor->GetPhysicsSetup();
const Physics::RagdollConfiguration& ragdollConfig = physicsSetup->GetRagdollConfig();
const AZStd::vector<Physics::RagdollNodeConfiguration>& ragdollNodes = ragdollConfig.m_nodes;
const Physics::CharacterColliderConfiguration& colliderConfig = ragdollConfig.m_colliders;
const EMotionFX::RagdollInstance* ragdollInstance = actorInstance->GetRagdollInstance();
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
const AZ::Color& violatedColor = settings.m_violatedJointLimitColor;
const AZ::Color& defaultColor = settings.m_ragdollColliderColor;
const AZ::Color& selectedColor = settings.m_selectedRagdollColliderColor;
const AZStd::unordered_set<size_t>* cachedSelectedJointIndices;
EMotionFX::JointSelectionRequestBus::BroadcastResult(
cachedSelectedJointIndices, &EMotionFX::JointSelectionRequests::FindSelectedJointIndices, actorInstance);
for (size_t nodeIndex = 0; nodeIndex < numNodes; ++nodeIndex)
{
const EMotionFX::Node* joint = skeleton->GetNode(nodeIndex);
const size_t jointIndex = joint->GetNodeIndex();
AZ::Outcome<size_t> ragdollNodeIndex = AZ::Failure();
if (ragdollInstance)
{
ragdollNodeIndex = ragdollInstance->GetRagdollNodeIndex(jointIndex);
}
else
{
ragdollNodeIndex = ragdollConfig.FindNodeConfigIndexByName(joint->GetNameString());
}
if (!ragdollNodeIndex.IsSuccess())
{
continue;
}
const bool jointSelected = cachedSelectedJointIndices &&
(cachedSelectedJointIndices->empty() || cachedSelectedJointIndices->find(joint->GetNodeIndex()) != cachedSelectedJointIndices->end());
AZ::Color finalColor;
if (jointSelected)
{
finalColor = selectedColor;
}
else
{
finalColor = defaultColor;
}
const Physics::RagdollNodeConfiguration& ragdollNode = ragdollNodes[ragdollNodeIndex.GetValue()];
if (renderColliders)
{
const Physics::CharacterColliderNodeConfiguration* colliderNodeConfig =
colliderConfig.FindNodeConfigByName(joint->GetNameString());
if (colliderNodeConfig)
{
const AzPhysics::ShapeColliderPairList& colliders = colliderNodeConfig->m_shapes;
RenderColliders(debugDisplay, colliders, actorInstance, joint, finalColor);
}
}
if (renderJointLimits && jointSelected)
{
const AZStd::shared_ptr<AzPhysics::JointConfiguration>& jointLimitConfig = ragdollNode.m_jointConfig;
if (jointLimitConfig)
{
const EMotionFX::Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
if (ragdollParentNode)
{
RenderJointLimit(debugDisplay, *jointLimitConfig, actorInstance, joint, ragdollParentNode, finalColor, violatedColor);
RenderJointFrame(debugDisplay, *jointLimitConfig, actorInstance, joint, finalColor);
}
}
}
}
}
} // namespace AZ::Render

@ -43,7 +43,6 @@ namespace AZ::Render
void DebugDraw(const EMotionFX::ActorRenderFlags& renderFlags, EMotionFX::ActorInstance* instance);
private:
float CalculateBoneScale(EMotionFX::ActorInstance* actorInstance, EMotionFX::Node* node);
float CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const;
void PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM);
@ -83,6 +82,37 @@ namespace AZ::Render
bool selected, //!< Set to true if you want to render the axis using the selection color. */
bool renderAxisName = false);
void RenderColliders(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::ShapeColliderPairList& colliders,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const AZ::Color& colliderColor) const;
void RenderColliders(AzFramework::DebugDisplayRequests* debugDisplay,
EMotionFX::PhysicsSetup::ColliderConfigType colliderConfigType,
EMotionFX::ActorInstance* actorInstance,
const AZ::Color& defaultColor,
const AZ::Color& selectedColor) const;
void RenderJointFrame(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::JointConfiguration& configuration,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const AZ::Color& color) const;
// Ragdoll
void RenderJointLimit(AzFramework::DebugDisplayRequests* debugDisplay,
const AzPhysics::JointConfiguration& configuration,
const EMotionFX::ActorInstance* actorInstance,
const EMotionFX::Node* node,
const EMotionFX::Node* parentNode,
const AZ::Color& regularColor,
const AZ::Color& violatedColor);
void RenderRagdoll(AzFramework::DebugDisplayRequests* debugDisplay,
EMotionFX::ActorInstance* actorInstance,
bool renderColliders,
bool renderJointLimits);
EMotionFX::Mesh* m_currentMesh = nullptr; //!< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer.
//!< NULL in case we haven't pre-calculated any positions yet.
AZStd::vector<AZ::Vector3> m_worldSpacePositions; //!< The buffer used to store world space positions for rendering normals
@ -97,6 +127,22 @@ namespace AZ::Render
AZStd::vector<AZ::Color> m_auxColors;
EntityId m_entityId;
// Joint limits
static constexpr float s_scale = 0.1f;
static constexpr AZ::u32 s_angularSubdivisions = 32;
static constexpr AZ::u32 s_radialSubdivisions = 2;
struct JointLimitRenderData
{
AZStd::vector<AZ::Vector3> m_vertexBuffer;
AZStd::vector<AZ::u32> m_indexBuffer;
AZStd::vector<AZ::Vector3> m_lineBuffer;
AZStd::vector<bool> m_lineValidityBuffer;
void Clear();
};
JointLimitRenderData m_jointLimitRenderData;
AzFramework::TextDrawParameters m_drawParams;
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;
};

@ -713,121 +713,6 @@ namespace EMotionFX
renderUtil->EnableLighting(oldLightingEnabled);
}
void ColliderContainerWidget::RenderColliders(
const AzPhysics::ShapeColliderPairList& colliders,
const ActorInstance* actorInstance,
const Node* node,
const AZ::Color& colliderColor)
{
const size_t nodeIndex = node->GetNodeIndex();
for (const auto& collider : colliders)
{
#ifndef EMFX_SCALE_DISABLED
const AZ::Vector3& worldScale = actorInstance->GetTransformData()->GetCurrentPose()->GetModelSpaceTransform(nodeIndex).m_scale;
#else
const AZ::Vector3 worldScale = AZ::Vector3::CreateOne();
#endif
const Transform colliderOffsetTransform(collider.first->m_position, collider.first->m_rotation);
const Transform& actorInstanceGlobalTransform = actorInstance->GetWorldSpaceTransform();
const Transform& emfxNodeGlobalTransform =
actorInstance->GetTransformData()->GetCurrentPose()->GetModelSpaceTransform(nodeIndex);
const Transform emfxColliderGlobalTransformNoScale =
colliderOffsetTransform * emfxNodeGlobalTransform * actorInstanceGlobalTransform;
AZ::s32 viewportId = -1;
EMStudio::ViewportPluginRequestBus::BroadcastResult(viewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId);
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, viewportId);
AzFramework::DebugDisplayRequests* debugDisplay = nullptr;
debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
if (!debugDisplay)
{
return;
}
const AZ::TypeId colliderType = collider.second->RTTI_GetType();
if (colliderType == azrtti_typeid<Physics::SphereShapeConfiguration>())
{
Physics::SphereShapeConfiguration* sphere = static_cast<Physics::SphereShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: The maximum component from the node scale will be multiplied by the radius of the sphere.
const float radius = sphere->m_radius *
MCore::Max3<float>(static_cast<float>(worldScale.GetX()), static_cast<float>(worldScale.GetY()),
static_cast<float>(worldScale.GetZ()));
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireSphere(emfxColliderGlobalTransformNoScale.m_position, radius);
}
else if (colliderType == azrtti_typeid<Physics::CapsuleShapeConfiguration>())
{
Physics::CapsuleShapeConfiguration* capsule = static_cast<Physics::CapsuleShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: The maximum of the X/Y scale components of the node scale will be multiplied by the radius of
// the capsule. The Z component of the entity scale will be multiplied by the height of the capsule.
const float radius =
capsule->m_radius * MCore::Max<float>(static_cast<float>(worldScale.GetX()), static_cast<float>(worldScale.GetY()));
const float height = capsule->m_height * static_cast<float>(worldScale.GetZ());
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireCapsule(
emfxColliderGlobalTransformNoScale.m_position, emfxColliderGlobalTransformNoScale.ToAZTransform().GetBasisZ(), radius, height);
}
else if (colliderType == azrtti_typeid<Physics::BoxShapeConfiguration>())
{
Physics::BoxShapeConfiguration* box = static_cast<Physics::BoxShapeConfiguration*>(collider.second.get());
// O3DE Physics scaling rules: Each component of the box dimensions will be scaled by the node's world scale.
AZ::Vector3 dimensions = box->m_dimensions;
dimensions *= worldScale;
debugDisplay->DepthTestOff();
debugDisplay->SetColor(colliderColor);
debugDisplay->DrawWireBox(
emfxColliderGlobalTransformNoScale.m_position, emfxColliderGlobalTransformNoScale.m_position + dimensions);
}
}
}
void ColliderContainerWidget::RenderColliders(PhysicsSetup::ColliderConfigType colliderConfigType,
const AZ::Color& defaultColor, const AZ::Color& selectedColor)
{
if (colliderConfigType == PhysicsSetup::Unknown)
{
return;
}
const AZStd::unordered_set<size_t>& selectedJointIndices = EMStudio::GetManager()->GetSelectedJointIndices();
const ActorManager* actorManager = GetEMotionFX().GetActorManager();
const size_t actorInstanceCount = actorManager->GetNumActorInstances();
for (size_t i = 0; i < actorInstanceCount; ++i)
{
const ActorInstance* actorInstance = actorManager->GetActorInstance(i);
const Actor* actor = actorInstance->GetActor();
const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = actor->GetPhysicsSetup();
const Physics::CharacterColliderConfiguration* colliderConfig = physicsSetup->GetColliderConfigByType(colliderConfigType);
if (colliderConfig)
{
for (const Physics::CharacterColliderNodeConfiguration& nodeConfig : colliderConfig->m_nodes)
{
const Node* joint = actor->GetSkeleton()->FindNodeByName(nodeConfig.m_name.c_str());
if (joint)
{
const bool jointSelected =
selectedJointIndices.empty() || selectedJointIndices.find(joint->GetNodeIndex()) != selectedJointIndices.end();
const AzPhysics::ShapeColliderPairList& colliders = nodeConfig.m_shapes;
RenderColliders(colliders, actorInstance, joint, jointSelected ? selectedColor : defaultColor);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
ColliderContainerWidget::ColliderEditedCallback::ColliderEditedCallback(ColliderContainerWidget* parent, bool executePreUndo, bool executePreCommand)

@ -167,17 +167,6 @@ namespace EMotionFX
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo);
static void RenderColliders(
const AzPhysics::ShapeColliderPairList& colliders,
const ActorInstance* actorInstance,
const Node* node,
const AZ::Color& colliderColor);
static void RenderColliders(
PhysicsSetup::ColliderConfigType colliderConfigType,
const AZ::Color& defaultColor,
const AZ::Color& selectedColor);
static int s_layoutSpacing;
signals:

@ -195,15 +195,4 @@ namespace EMotionFX
renderPlugin,
renderInfo);
}
void ClothJointInspectorPlugin::Render(EMotionFX::ActorRenderFlags renderFlags)
{
if (!AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::ClothColliders))
{
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
ColliderContainerWidget::RenderColliders(PhysicsSetup::Cloth, settings.m_clothColliderColor, settings.m_selectedClothColliderColor);
}
} // namespace EMotionFX

@ -48,7 +48,6 @@ namespace EMotionFX
void OnContextMenu(QMenu* menu, const QModelIndexList& selectedRowIndices) override;
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void Render(EMotionFX::ActorRenderFlags renderFlags) override;
static bool IsJointInCloth(const QModelIndex& index);
public slots:

@ -180,18 +180,4 @@ namespace EMotionFX
renderPlugin,
renderInfo);
}
void HitDetectionJointInspectorPlugin::Render(EMotionFX::ActorRenderFlags renderFlags)
{
if (!AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::HitDetectionColliders))
{
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
ColliderContainerWidget::RenderColliders(
PhysicsSetup::HitDetection, settings.m_hitDetectionColliderColor,
settings.m_selectedHitDetectionColliderColor);
}
} // namespace EMotionFX

@ -44,7 +44,6 @@ namespace EMotionFX
void OnContextMenu(QMenu* menu, const QModelIndexList& selectedRowIndices) override;
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void Render(EMotionFX::ActorRenderFlags renderFlags) override;
public slots:
void OnAddCollider();

@ -32,10 +32,6 @@
namespace EMotionFX
{
float RagdollNodeInspectorPlugin::s_scale = 0.1f;
AZ::u32 RagdollNodeInspectorPlugin::s_angularSubdivisions = 32;
AZ::u32 RagdollNodeInspectorPlugin::s_radialSubdivisions = 2;
RagdollNodeInspectorPlugin::RagdollNodeInspectorPlugin()
: EMStudio::DockWidgetPlugin()
, m_nodeWidget(nullptr)
@ -520,7 +516,6 @@ namespace EMotionFX
const Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
if (ragdollParentNode)
{
LegacyRenderJointLimit(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderPlugin, renderInfo, finalColor);
LegacyRenderJointFrame(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderInfo, finalColor);
}
}
@ -528,54 +523,6 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::LegacyRenderJointLimit(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color)
{
const EMStudio::RenderOptions* renderOptions = renderPlugin->GetRenderOptions();
const MCore::RGBAColor violatedColor = renderOptions->GetViolatedJointLimitColor();
const size_t nodeIndex = node->GetNodeIndex();
const size_t parentNodeIndex = parentNode->GetNodeIndex();
const Transform& actorInstanceWorldTransform = actorInstance->GetWorldSpaceTransform();
const Pose* currentPose = actorInstance->GetTransformData()->GetCurrentPose();
const AZ::Quaternion& parentOrientation = currentPose->GetModelSpaceTransform(parentNodeIndex).m_rotation;
const AZ::Quaternion& childOrientation = currentPose->GetModelSpaceTransform(nodeIndex).m_rotation;
m_vertexBuffer.clear();
m_indexBuffer.clear();
m_lineBuffer.clear();
m_lineValidityBuffer.clear();
if(auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
jointHelpers->GenerateJointLimitVisualizationData(
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions, m_vertexBuffer,
m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
}
Transform jointModelSpaceTransform = currentPose->GetModelSpaceTransform(parentNodeIndex);
jointModelSpaceTransform.m_position = currentPose->GetModelSpaceTransform(nodeIndex).m_position;
const Transform jointGlobalTransformNoScale = jointModelSpaceTransform * actorInstanceWorldTransform;
MCommon::RenderUtil* renderUtil = renderInfo->m_renderUtil;
const size_t numLineBufferEntries = m_lineBuffer.size();
if (m_lineValidityBuffer.size() * 2 != numLineBufferEntries)
{
AZ_ErrorOnce("EMotionFX", false, "Unexpected buffer size in joint limit visualization for node %s", node->GetName());
return;
}
for (size_t i = 0; i < numLineBufferEntries; i += 2)
{
renderUtil->RenderLine(jointGlobalTransformNoScale.TransformPoint(m_lineBuffer[i]),
jointGlobalTransformNoScale.TransformPoint(m_lineBuffer[i + 1]), m_lineValidityBuffer[i / 2] ? color : violatedColor);
}
}
void RagdollNodeInspectorPlugin::LegacyRenderJointFrame(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
@ -594,192 +541,4 @@ namespace EMotionFX
renderInfo->m_renderUtil->RenderArrow(0.1f, jointChildWorldSpaceTransformNoScale.m_position, MCore::GetRight(jointChildWorldSpaceTransformNoScale.ToAZTransform()), color);
}
void RagdollNodeInspectorPlugin::Render(EMotionFX::ActorRenderFlags renderFlags)
{
const bool renderColliders = AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::RagdollColliders);
const bool renderJointLimits = AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::RagdollJointLimits);
if (!renderColliders && !renderJointLimits)
{
return;
}
const size_t actorInstanceCount = GetActorManager().GetNumActorInstances();
for (size_t i = 0; i < actorInstanceCount; ++i)
{
ActorInstance* actorInstance = GetActorManager().GetActorInstance(i);
RenderRagdoll(actorInstance, renderColliders, renderJointLimits);
}
}
void RagdollNodeInspectorPlugin::RenderRagdoll(
ActorInstance* actorInstance,
bool renderColliders,
bool renderJointLimits)
{
const Actor* actor = actorInstance->GetActor();
const Skeleton* skeleton = actor->GetSkeleton();
const size_t numNodes = skeleton->GetNumNodes();
const AZStd::shared_ptr<EMotionFX::PhysicsSetup>& physicsSetup = actor->GetPhysicsSetup();
const Physics::RagdollConfiguration& ragdollConfig = physicsSetup->GetRagdollConfig();
const AZStd::vector<Physics::RagdollNodeConfiguration>& ragdollNodes = ragdollConfig.m_nodes;
const Physics::CharacterColliderConfiguration& colliderConfig = ragdollConfig.m_colliders;
const RagdollInstance* ragdollInstance = actorInstance->GetRagdollInstance();
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
const AZ::Color& violatedColor = settings.m_violatedJointLimitColor;
const AZ::Color& defaultColor = settings.m_ragdollColliderColor;
const AZ::Color& selectedColor = settings.m_selectedRagdollColliderColor;
const AZStd::unordered_set<size_t>& selectedJointIndices = EMStudio::GetManager()->GetSelectedJointIndices();
for (size_t nodeIndex = 0; nodeIndex < numNodes; ++nodeIndex)
{
const Node* joint = skeleton->GetNode(nodeIndex);
const size_t jointIndex = joint->GetNodeIndex();
AZ::Outcome<size_t> ragdollNodeIndex = AZ::Failure();
if (ragdollInstance)
{
ragdollNodeIndex = ragdollInstance->GetRagdollNodeIndex(jointIndex);
}
else
{
ragdollNodeIndex = ragdollConfig.FindNodeConfigIndexByName(joint->GetNameString());
}
if (!ragdollNodeIndex.IsSuccess())
{
continue;
}
const bool jointSelected = selectedJointIndices.empty() || selectedJointIndices.find(jointIndex) != selectedJointIndices.end();
AZ::Color finalColor;
if (jointSelected)
{
finalColor = selectedColor;
}
else
{
finalColor = defaultColor;
}
const Physics::RagdollNodeConfiguration& ragdollNode = ragdollNodes[ragdollNodeIndex.GetValue()];
if (renderColliders)
{
const Physics::CharacterColliderNodeConfiguration* colliderNodeConfig =
colliderConfig.FindNodeConfigByName(joint->GetNameString());
if (colliderNodeConfig)
{
const AzPhysics::ShapeColliderPairList& colliders = colliderNodeConfig->m_shapes;
ColliderContainerWidget::RenderColliders(colliders, actorInstance, joint, finalColor);
}
}
if (renderJointLimits && jointSelected)
{
const AZStd::shared_ptr<AzPhysics::JointConfiguration>& jointLimitConfig = ragdollNode.m_jointConfig;
if (jointLimitConfig)
{
const Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
if (ragdollParentNode)
{
RenderJointLimit(*jointLimitConfig, actorInstance, joint, ragdollParentNode, finalColor, violatedColor);
RenderJointFrame(*jointLimitConfig, actorInstance, joint, ragdollParentNode, finalColor);
}
}
}
}
}
void RagdollNodeInspectorPlugin::RenderJointLimit(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
const AZ::Color& regularColor,
const AZ::Color& violatedColor)
{
const size_t nodeIndex = node->GetNodeIndex();
const size_t parentNodeIndex = parentNode->GetNodeIndex();
const Transform& actorInstanceWorldTransform = actorInstance->GetWorldSpaceTransform();
const Pose* currentPose = actorInstance->GetTransformData()->GetCurrentPose();
const AZ::Quaternion& parentOrientation = currentPose->GetModelSpaceTransform(parentNodeIndex).m_rotation;
const AZ::Quaternion& childOrientation = currentPose->GetModelSpaceTransform(nodeIndex).m_rotation;
m_vertexBuffer.clear();
m_indexBuffer.clear();
m_lineBuffer.clear();
m_lineValidityBuffer.clear();
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
jointHelpers->GenerateJointLimitVisualizationData(
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions, m_vertexBuffer,
m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
}
Transform jointModelSpaceTransform = currentPose->GetModelSpaceTransform(parentNodeIndex);
jointModelSpaceTransform.m_position = currentPose->GetModelSpaceTransform(nodeIndex).m_position;
const Transform jointGlobalTransformNoScale = jointModelSpaceTransform * actorInstanceWorldTransform;
const size_t numLineBufferEntries = m_lineBuffer.size();
if (m_lineValidityBuffer.size() * 2 != numLineBufferEntries)
{
AZ_ErrorOnce("EMotionFX", false, "Unexpected buffer size in joint limit visualization for node %s", node->GetName());
return;
}
AZ::s32 viewportId = -1;
EMStudio::ViewportPluginRequestBus::BroadcastResult(viewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId);
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, viewportId);
AzFramework::DebugDisplayRequests* debugDisplay = nullptr;
debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
if (!debugDisplay)
{
return;
}
for (size_t i = 0; i < numLineBufferEntries; i += 2)
{
const AZ::Color& lineColor = m_lineValidityBuffer[i / 2] ? regularColor : violatedColor;
debugDisplay->DrawLine(
jointGlobalTransformNoScale.TransformPoint(m_lineBuffer[i]),
jointGlobalTransformNoScale.TransformPoint(m_lineBuffer[i + 1]), lineColor.GetAsVector4(), lineColor.GetAsVector4()
);
}
}
void RagdollNodeInspectorPlugin::RenderJointFrame(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
const AZ::Color& color)
{
AZ_UNUSED(parentNode);
const Transform& actorInstanceWorldSpaceTransform = actorInstance->GetWorldSpaceTransform();
const Pose* currentPose = actorInstance->GetTransformData()->GetCurrentPose();
const Transform childJointLocalSpaceTransform(AZ::Vector3::CreateZero(), configuration.m_childLocalRotation);
const Transform childModelSpaceTransform =
childJointLocalSpaceTransform * currentPose->GetModelSpaceTransform(node->GetNodeIndex());
const Transform jointChildWorldSpaceTransformNoScale = (childModelSpaceTransform * actorInstanceWorldSpaceTransform);
AZ::Vector3 dir = jointChildWorldSpaceTransformNoScale.ToAZTransform().GetBasisX();
AZ::s32 viewportId = -1;
EMStudio::ViewportPluginRequestBus::BroadcastResult(viewportId, &EMStudio::ViewportPluginRequestBus::Events::GetViewportId);
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, viewportId);
AzFramework::DebugDisplayRequests* debugDisplay = nullptr;
debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
if (!debugDisplay)
{
return;
}
debugDisplay->SetColor(color);
debugDisplay->DrawArrow(jointChildWorldSpaceTransformNoScale.m_position, jointChildWorldSpaceTransformNoScale.m_position + dir, 0.1f);
}
} // namespace EMotionFX

@ -57,14 +57,6 @@ namespace EMotionFX
//! Deprecated: All legacy render function is tied to openGL. Will be removed after openGLPlugin is completely removed.
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void LegacyRenderRagdoll(ActorInstance* actorInstance, bool renderColliders, bool renderJointLimits, EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo);
void LegacyRenderJointLimit(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
void LegacyRenderJointFrame(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
@ -73,26 +65,6 @@ namespace EMotionFX
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
//! Those function replaces legacyRender function and calls atom auxGeom render internally.
void Render(EMotionFX::ActorRenderFlags renderFlags) override;
void RenderRagdoll(
ActorInstance* actorInstance,
bool renderColliders,
bool renderJointLimits);
void RenderJointLimit(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
const AZ::Color& regularColor,
const AZ::Color& violatedColor);
void RenderJointFrame(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
const AZ::Color& color);
public slots:
void OnAddToRagdoll();
void OnAddCollider();
@ -103,14 +75,6 @@ namespace EMotionFX
private:
bool IsPhysXGemAvailable() const;
RagdollNodeWidget* m_nodeWidget;
static float s_scale;
static AZ::u32 s_angularSubdivisions;
static AZ::u32 s_radialSubdivisions;
AZStd::vector<AZ::Vector3> m_vertexBuffer;
AZStd::vector<AZ::u32> m_indexBuffer;
AZStd::vector<AZ::Vector3> m_lineBuffer;
AZStd::vector<bool> m_lineValidityBuffer;
RagdollNodeWidget* m_nodeWidget;
};
} // namespace EMotionFX

@ -577,7 +577,6 @@ namespace EMotionFX
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
const AZStd::unordered_set<size_t>& selectedJointIndices = EMStudio::GetManager()->GetSelectedJointIndices();
if (AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::SimulatedJoints) && !selectedJointIndices.empty())
{
@ -611,12 +610,6 @@ namespace EMotionFX
}
}
}
if (AZ::RHI::CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::SimulatedObjectColliders))
{
ColliderContainerWidget::RenderColliders(PhysicsSetup::SimulatedObjectCollider,
settings.m_simulatedObjectColliderColor, settings.m_selectedSimulatedObjectColliderColor);
}
}
void SimulatedObjectWidget::RenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color)

@ -16,11 +16,8 @@
#include <QVBoxLayout>
#include <QHeaderView>
namespace EMotionFX
{
int SkeletonOutlinerPlugin::s_iconSize = 16;
SkeletonOutlinerPlugin::SkeletonOutlinerPlugin()
: EMStudio::DockWidgetPlugin()
, m_mainWidget(nullptr)
@ -30,13 +27,19 @@ namespace EMotionFX
SkeletonOutlinerPlugin::~SkeletonOutlinerPlugin()
{
// Reset selection on close.
if (m_skeletonModel)
{
m_skeletonModel->GetSelectionModel().clearSelection();
m_skeletonModel.reset();
}
for (MCore::Command::Callback* callback : m_commandCallbacks)
{
CommandSystem::GetCommandManager()->RemoveCommandCallback(callback, true);
}
m_commandCallbacks.clear();
SkeletonOutlinerNotificationBus::Broadcast(&SkeletonOutlinerNotifications::SingleNodeSelectionChanged, nullptr, nullptr);
EMotionFX::SkeletonOutlinerRequestBus::Handler::BusDisconnect();
}

@ -19,7 +19,6 @@
#include <QTreeView>
#endif
QT_FORWARD_DECLARE_CLASS(QLabel)
namespace EMotionFX
@ -73,7 +72,7 @@ namespace EMotionFX
AZStd::unique_ptr<SkeletonModel> m_skeletonModel;
QModelIndexList m_selectedRows;
SkeletonSortFilterProxyModel* m_filterProxyModel;
static int s_iconSize;
static constexpr int s_iconSize = 16;
// Callbacks
// Works for all commands that use the actor id as well as the joint name mixins

Loading…
Cancel
Save