Render Colliders (#5434)

* Render Colliders

Signed-off-by: rhhong <rhhong@amazon.com>

* CR feedback

Signed-off-by: rhhong <rhhong@amazon.com>
This commit is contained in:
Roman
2021-11-09 13:42:56 -08:00
committed by GitHub
parent e6a1f8ed0a
commit aa229976f3
23 changed files with 655 additions and 72 deletions
@@ -10,6 +10,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Physics/ShapeConfiguration.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzQtComponents/Components/Widgets/CardHeader.h>
#include <EMotionFX/CommandSystem/Source/ColliderCommands.h>
#include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands.h>
@@ -19,6 +20,7 @@
#include <EMotionFX/Source/Node.h>
#include <EMotionFX/Source/TransformData.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h>
#include <Editor/ColliderContainerWidget.h>
#include <Editor/ColliderHelpers.h>
#include <Editor/ObjectEditor.h>
@@ -610,7 +612,7 @@ namespace EMotionFX
return QWidget::sizeHint() + QSize(0, s_layoutSpacing);
}
void ColliderContainerWidget::RenderColliders(const AzPhysics::ShapeColliderPairList& colliders,
void ColliderContainerWidget::LegacyRenderColliders(const AzPhysics::ShapeColliderPairList& colliders,
const ActorInstance* actorInstance,
const Node* node,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
@@ -630,7 +632,6 @@ namespace EMotionFX
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;
const AZ::TypeId colliderType = collider.second->RTTI_GetType();
@@ -638,7 +639,7 @@ namespace EMotionFX
{
Physics::SphereShapeConfiguration* sphere = static_cast<Physics::SphereShapeConfiguration*>(collider.second.get());
// LY Physics scaling rules: The maximum component from the node scale will be multiplied by the radius of the sphere.
// 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()));
renderUtil->RenderWireframeSphere(radius, emfxColliderGlobalTransformNoScale.ToAZTransform(), colliderColor);
@@ -647,7 +648,7 @@ namespace EMotionFX
{
Physics::CapsuleShapeConfiguration* capsule = static_cast<Physics::CapsuleShapeConfiguration*>(collider.second.get());
// LY 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.
// 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());
@@ -657,7 +658,7 @@ namespace EMotionFX
{
Physics::BoxShapeConfiguration* box = static_cast<Physics::BoxShapeConfiguration*>(collider.second.get());
// LY Physics scaling rules: Each component of the box dimensions will be scaled by the node's world scale.
// 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;
@@ -666,7 +667,8 @@ namespace EMotionFX
}
}
void ColliderContainerWidget::RenderColliders(PhysicsSetup::ColliderConfigType colliderConfigType,
void ColliderContainerWidget::LegacyRenderColliders(
PhysicsSetup::ColliderConfigType colliderConfigType,
const MCore::RGBAColor& defaultColor,
const MCore::RGBAColor& selectedColor,
EMStudio::RenderPlugin* renderPlugin,
@@ -701,7 +703,7 @@ namespace EMotionFX
{
const bool jointSelected = selectedJointIndices.empty() || selectedJointIndices.find(joint->GetNodeIndex()) != selectedJointIndices.end();
const AzPhysics::ShapeColliderPairList& colliders = nodeConfig.m_shapes;
RenderColliders(colliders, actorInstance, joint, renderInfo, jointSelected ? selectedColor : defaultColor);
LegacyRenderColliders(colliders, actorInstance, joint, renderInfo, jointSelected ? selectedColor : defaultColor);
}
}
}
@@ -711,6 +713,121 @@ 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)