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
@@ -137,6 +137,18 @@ namespace AtomToolsFramework
m_viewportContext->SetRenderScene(nullptr);
return;
}
// Check if the scene already has an atom scene attached. In this case we don't need to create a new atom scene.
if (auto existingScene = scene->FindSubsystem<AZ::RPI::ScenePtr>())
{
m_viewportContext->SetRenderScene(*existingScene);
if (auto auxGeomFP = existingScene->get()->GetFeatureProcessor<AZ::RPI::AuxGeomFeatureProcessorInterface>())
{
m_auxGeom = auxGeomFP->GetOrCreateDrawQueueForView(m_defaultCamera.get());
}
return;
}
AZ::RPI::ScenePtr atomScene;
auto initializeScene = [&](AZ::Render::Bootstrap::Request* bootstrapRequests)
{
@@ -24,8 +24,6 @@
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConfig.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/PostFxLayerComponentConstants.h>
@@ -122,22 +120,15 @@ namespace EMStudio
const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs<AZ::Render::LightingPreset>();
SetLightingPreset(preset);
// Create grid
// Create the ground plane
AzFramework::EntityContextRequestBus::EventResult(
m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid");
AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity.");
m_groundEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel");
AZ_Assert(m_groundEntity != nullptr, "Failed to create model entity.");
AZ::Render::GridComponentConfig gridConfig;
gridConfig.m_secondarySpacing = m_renderOptions->GetGridUnitSize();
gridConfig.m_axisColor = m_renderOptions->GetMainAxisColor();
gridConfig.m_primaryColor = m_renderOptions->GetGridColor();
gridConfig.m_secondaryColor = m_renderOptions->GetSubStepColor();
auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId);
gridComponent->SetConfiguration(gridConfig);
m_gridEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_gridEntity->Init();
m_gridEntity->Activate();
m_groundEntity->CreateComponent(AZ::Render::MeshComponentTypeId);
m_groundEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
m_groundEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_groundEntity->Activate();
Reinit();
}
@@ -147,7 +138,7 @@ namespace EMStudio
// Destroy all the entity we created.
m_entityContext->DestroyEntity(m_iblEntity);
m_entityContext->DestroyEntity(m_postProcessEntity);
m_entityContext->DestroyEntity(m_gridEntity);
m_entityContext->DestroyEntity(m_groundEntity);
for (AZ::Entity* entity : m_actorEntities)
{
m_entityContext->DestroyEntity(entity);
@@ -220,6 +211,11 @@ namespace EMStudio
}
}
AZStd::shared_ptr<AzFramework::Scene> AnimViewportRenderer::GetFrameworkScene() const
{
return m_frameworkScene;
}
void AnimViewportRenderer::ResetEnvironment()
{
// Reset environment
@@ -229,6 +225,15 @@ namespace EMStudio
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity();
auto skyBoxFeatureProcessorInterface = m_scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix);
// Reset ground entity
AZ::Transform groundTransform = AZ::Transform::CreateIdentity();
AZ::TransformBus::Event(m_groundEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, groundTransform);
auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
"objects/groudplane/groundplane_512x512m.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert);
AZ::Render::MeshComponentRequestBus::Event(
m_groundEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset);
}
void AnimViewportRenderer::ReinitActorEntities()
@@ -56,6 +56,8 @@ namespace EMStudio
void UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags);
AZStd::shared_ptr<AzFramework::Scene> GetFrameworkScene() const;
private:
// This function resets the light, camera and other environment settings.
@@ -83,7 +85,7 @@ namespace EMStudio
AZ::Entity* m_postProcessEntity = nullptr;
AZ::Entity* m_iblEntity = nullptr;
AZ::Entity* m_gridEntity = nullptr;
AZ::Entity* m_groundEntity = nullptr;
AZStd::vector<AZ::Entity*> m_actorEntities;
const RenderOptions* m_renderOptions;
@@ -48,6 +48,12 @@ namespace EMStudio
CreateViewOptionEntry(contextMenu, "Joint Orientations", EMotionFX::ActorRenderFlag::RENDER_NODEORIENTATION);
CreateViewOptionEntry(contextMenu, "Actor Bind Pose", EMotionFX::ActorRenderFlag::RENDER_ACTORBINDPOSE);
contextMenu->addSeparator();
CreateViewOptionEntry(contextMenu, "Hit Detection Colliders", EMotionFX::ActorRenderFlag::RENDER_HITDETECTION_COLLIDERS);
CreateViewOptionEntry(contextMenu, "Ragdoll Colliders", EMotionFX::ActorRenderFlag::RENDER_RAGDOLL_COLLIDERS);
CreateViewOptionEntry(contextMenu, "Ragdoll Joint Limits", EMotionFX::ActorRenderFlag::RENDER_RAGDOLL_JOINTLIMITS);
CreateViewOptionEntry(contextMenu, "Cloth Colliders", EMotionFX::ActorRenderFlag::RENDER_CLOTH_COLLIDERS);
CreateViewOptionEntry(contextMenu, "Simulated Object Colliders", EMotionFX::ActorRenderFlag::RENDER_SIMULATEDOBJECT_COLLIDERS);
CreateViewOptionEntry(contextMenu, "Simulated Joints", EMotionFX::ActorRenderFlag::RENDER_SIMULATEJOINTS);
}
// Add the camera button
@@ -35,6 +35,7 @@ namespace EMStudio
setStyleSheet(QString::fromUtf8(""));
m_renderer = AZStd::make_unique<AnimViewportRenderer>(GetViewportContext(), m_plugin->GetRenderOptions());
SetScene(m_renderer->GetFrameworkScene(), false);
LoadRenderFlags();
SetupCameras();
@@ -42,11 +43,13 @@ namespace EMStudio
Reinit();
AnimViewportRequestBus::Handler::BusConnect();
ViewportPluginRequestBus::Handler::BusConnect();
}
AnimViewportWidget::~AnimViewportWidget()
{
SaveRenderFlags();
ViewportPluginRequestBus::Handler::BusDisconnect();
AnimViewportRequestBus::Handler::BusDisconnect();
}
@@ -173,6 +176,7 @@ namespace EMStudio
{
RenderViewportWidget::OnTick(deltaTime, time);
CalculateCameraProjection();
RenderCustomPluginData();
}
void AnimViewportWidget::CalculateCameraProjection()
@@ -191,6 +195,16 @@ namespace EMStudio
viewportContext->GetDefaultView()->SetViewToClipMatrix(viewToClipMatrix);
}
void AnimViewportWidget::RenderCustomPluginData()
{
const size_t numPlugins = GetPluginManager()->GetNumActivePlugins();
for (size_t i = 0; i < numPlugins; ++i)
{
EMStudioPlugin* plugin = GetPluginManager()->GetActivePlugin(i);
plugin->Render(m_renderFlags);
}
}
void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag)
{
m_renderFlags[flag] = !m_renderFlags[flag];
@@ -224,4 +238,9 @@ namespace EMStudio
settings.setValue(name, (bool)m_renderFlags[i]);
}
}
AZ::s32 AnimViewportWidget::GetViewportId() const
{
return GetViewportContext()->GetId();
}
} // namespace EMStudio
@@ -10,6 +10,8 @@
#include <QSettings>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzFramework/Viewport/CameraInput.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h>
#include <EMStudio/AnimViewportRequestBus.h>
#include <Integration/Rendering/RenderFlag.h>
@@ -21,6 +23,7 @@ namespace EMStudio
class AnimViewportWidget
: public AtomToolsFramework::RenderViewportWidget
, private AnimViewportRequestBus::Handler
, private ViewportPluginRequestBus::Handler
{
public:
AnimViewportWidget(AtomRenderPlugin* parentPlugin);
@@ -34,6 +37,8 @@ namespace EMStudio
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
void CalculateCameraProjection();
void RenderCustomPluginData();
void SetupCameras();
void SetupCameraController();
@@ -45,6 +50,9 @@ namespace EMStudio
void SetCameraViewMode(CameraViewMode mode);
void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag);
// ViewportPluginRequestBus::Handler overrides
AZ::s32 GetViewportId() const;
static constexpr float CameraDistance = 2.0f;
AtomRenderPlugin* m_plugin;
@@ -15,6 +15,7 @@
#include <MCore/Source/MemoryFile.h>
#include <EMotionFX/Rendering/Common/RenderUtil.h>
#include <EMotionFX/Rendering/Common/Camera.h>
#include <Integration/Rendering/RenderFlag.h>
#include "EMStudioConfig.h"
#include <QString>
#include <QObject>
@@ -92,7 +93,15 @@ namespace EMStudio
uint32 m_screenHeight;
};
virtual void Render(RenderPlugin* renderPlugin, RenderInfo* renderInfo) { MCORE_UNUSED(renderPlugin); MCORE_UNUSED(renderInfo); }
//! Deprecated: LegacyRender will call EMotionFX::DebugDraw that tied to OpenGL render.
//! It will be removed after OpenGLPlugin and GLWidget is gone.
virtual void LegacyRender(RenderPlugin* renderPlugin, RenderInfo* renderInfo) { MCORE_UNUSED(renderPlugin); MCORE_UNUSED(renderInfo); }
//! Render function will call atom auxGeom internally to render. This is the replacement for LegacyRender function.
virtual void Render(EMotionFX::ActorRenderFlagBitset renderFlags)
{
AZ_UNUSED(renderFlags);
};
virtual PluginOptions* GetOptions() { return nullptr; }
@@ -1072,6 +1072,16 @@ namespace EMStudio
settings.m_staticAABBColor = m_staticAABBColor;
settings.m_skeletonColor = m_skeletonColor;
settings.m_lineSkeletonColor = m_lineSkeletonColor;
settings.m_hitDetectionColliderColor = m_hitDetectionColliderColor;
settings.m_selectedHitDetectionColliderColor = m_selectedHitDetectionColliderColor;
settings.m_ragdollColliderColor = m_ragdollColliderColor;
settings.m_selectedRagdollColliderColor = m_selectedRagdollColliderColor;
settings.m_violatedJointLimitColor = m_violatedJointLimitColor;
settings.m_clothColliderColor = m_clothColliderColor;
settings.m_selectedClothColliderColor = m_selectedClothColliderColor;
settings.m_simulatedObjectColliderColor = m_simulatedObjectColliderColor;
settings.m_selectedSimulatedObjectColliderColor = m_selectedSimulatedObjectColliderColor;
}
void RenderOptions::OnGridUnitSizeChangedCallback() const
@@ -1054,7 +1054,7 @@ namespace EMStudio
EMStudioPlugin* plugin = GetPluginManager()->GetActivePlugin(i);
EMStudioPlugin::RenderInfo renderInfo(renderUtil, m_camera, m_width, m_height);
plugin->Render(m_plugin, &renderInfo);
plugin->LegacyRender(m_plugin, &renderInfo);
}
RenderDebugDraw();
@@ -0,0 +1,23 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace EMStudio
{
class ViewportPluginRequests
: public AZ::EBusTraits
{
public:
virtual AZ::s32 GetViewportId() const = 0;
};
using ViewportPluginRequestBus = AZ::EBus<ViewportPluginRequests>;
}
@@ -667,7 +667,7 @@ namespace EMStudio
}
void MotionWindowPlugin::Render(RenderPlugin* renderPlugin, EMStudioPlugin::RenderInfo* renderInfo)
void MotionWindowPlugin::LegacyRender(RenderPlugin* renderPlugin, EMStudioPlugin::RenderInfo* renderInfo)
{
MCommon::RenderUtil* renderUtil = renderInfo->m_renderUtil;
@@ -61,7 +61,7 @@ namespace EMStudio
bool Init() override;
EMStudioPlugin* Clone() override;
void Render(RenderPlugin* renderPlugin, EMStudioPlugin::RenderInfo* renderInfo) override;
void LegacyRender(RenderPlugin* renderPlugin, EMStudioPlugin::RenderInfo* renderInfo) override;
void ReInit();
@@ -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)
@@ -152,18 +152,32 @@ namespace EMotionFX
* @param[in] renderInfo Needed to access the render util.
* @param[in] colliderColor The collider color.
*/
static void RenderColliders(const AzPhysics::ShapeColliderPairList& colliders,
//! Deprecated: remove after openglrenderwidget is gone.
static void LegacyRenderColliders(const AzPhysics::ShapeColliderPairList& colliders,
const ActorInstance* actorInstance,
const Node* node,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& colliderColor);
static void RenderColliders(PhysicsSetup::ColliderConfigType colliderConfigType,
//! Deprecated: remove after openglrenderwidget is gone.
static void LegacyRenderColliders(
PhysicsSetup::ColliderConfigType colliderConfigType,
const MCore::RGBAColor& defaultColor,
const MCore::RGBAColor& selectedColor,
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:
@@ -18,6 +18,7 @@
#include <Editor/SkeletonModel.h>
#include <Editor/Plugins/Cloth/ClothJointInspectorPlugin.h>
#include <Editor/Plugins/Cloth/ClothJointWidget.h>
#include <Integration/Rendering/RenderActorSettings.h>
#include <QScrollArea>
@@ -172,7 +173,7 @@ namespace EMotionFX
ColliderHelpers::ClearColliders(selectedRowIndices, PhysicsSetup::Cloth);
}
void ClothJointInspectorPlugin::Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
void ClothJointInspectorPlugin::LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
{
EMStudio::RenderViewWidget* activeViewWidget = renderPlugin->GetActiveViewWidget();
if (!activeViewWidget)
@@ -188,10 +189,22 @@ namespace EMotionFX
const EMStudio::RenderOptions* renderOptions = renderPlugin->GetRenderOptions();
ColliderContainerWidget::RenderColliders(PhysicsSetup::Cloth,
ColliderContainerWidget::LegacyRenderColliders(PhysicsSetup::Cloth,
renderOptions->GetClothColliderColor(),
renderOptions->GetSelectedClothColliderColor(),
renderPlugin,
renderInfo);
}
void ClothJointInspectorPlugin::Render(EMotionFX::ActorRenderFlagBitset renderFlags)
{
const bool renderColliders = renderFlags[RENDER_CLOTH_COLLIDERS];
if (!renderColliders)
{
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
ColliderContainerWidget::RenderColliders(PhysicsSetup::Cloth, settings.m_clothColliderColor, settings.m_selectedClothColliderColor);
}
} // namespace EMotionFX
@@ -47,7 +47,8 @@ namespace EMotionFX
// SkeletonOutlinerNotificationBus overrides
void OnContextMenu(QMenu* menu, const QModelIndexList& selectedRowIndices) override;
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void Render(EMotionFX::ActorRenderFlagBitset renderFlags) override;
static bool IsJointInCloth(const QModelIndex& index);
public slots:
@@ -15,6 +15,7 @@
#include <Editor/SkeletonModel.h>
#include <Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h>
#include <Editor/Plugins/HitDetection/HitDetectionJointWidget.h>
#include <Integration/Rendering/RenderActorSettings.h>
#include <QScrollArea>
#include <MCore/Source/AzCoreConversions.h>
@@ -157,7 +158,7 @@ namespace EMotionFX
ColliderHelpers::ClearColliders(selectedRowIndices, PhysicsSetup::HitDetection);
}
void HitDetectionJointInspectorPlugin::Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
void HitDetectionJointInspectorPlugin::LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
{
EMStudio::RenderViewWidget* activeViewWidget = renderPlugin->GetActiveViewWidget();
if (!activeViewWidget)
@@ -173,10 +174,25 @@ namespace EMotionFX
const EMStudio::RenderOptions* renderOptions = renderPlugin->GetRenderOptions();
ColliderContainerWidget::RenderColliders(PhysicsSetup::HitDetection,
ColliderContainerWidget::LegacyRenderColliders(PhysicsSetup::HitDetection,
renderOptions->GetHitDetectionColliderColor(),
renderOptions->GetSelectedHitDetectionColliderColor(),
renderPlugin,
renderInfo);
}
void HitDetectionJointInspectorPlugin::Render(EMotionFX::ActorRenderFlagBitset renderFlags)
{
const bool renderColliders = renderFlags[EMotionFX::ActorRenderFlag::RENDER_HITDETECTION_COLLIDERS];
if (!renderColliders)
{
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
ColliderContainerWidget::RenderColliders(
PhysicsSetup::HitDetection, settings.m_hitDetectionColliderColor,
settings.m_selectedHitDetectionColliderColor);
}
} // namespace EMotionFX
@@ -43,7 +43,8 @@ namespace EMotionFX
// SkeletonOutlinerNotificationBus overrides
void OnContextMenu(QMenu* menu, const QModelIndexList& selectedRowIndices) override;
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void Render(EMotionFX::ActorRenderFlagBitset renderFlags) override;
public slots:
void OnAddCollider();
@@ -7,6 +7,7 @@
*/
#include <AzFramework/Physics/SystemBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMotionFX/Source/RagdollInstance.h>
#include <EMotionFX/Source/TransformData.h>
@@ -17,12 +18,14 @@
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.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/SkeletonModel.h>
#include <Editor/Plugins/Ragdoll/RagdollJointLimitWidget.h>
#include <Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h>
#include <Editor/Plugins/Ragdoll/RagdollNodeWidget.h>
#include <Integration/Rendering/RenderActorSettings.h>
#include <QScrollArea>
#include <MCore/Source/AzCoreConversions.h>
@@ -412,7 +415,7 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
void RagdollNodeInspectorPlugin::LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
{
EMStudio::RenderViewWidget* activeViewWidget = renderPlugin->GetActiveViewWidget();
if (!activeViewWidget)
@@ -435,14 +438,19 @@ namespace EMotionFX
for (size_t i = 0; i < actorInstanceCount; ++i)
{
ActorInstance* actorInstance = GetActorManager().GetActorInstance(i);
RenderRagdoll(actorInstance, renderColliders, renderJointLimits, renderPlugin, renderInfo);
LegacyRenderRagdoll(actorInstance, renderColliders, renderJointLimits, renderPlugin, renderInfo);
}
renderUtil->RenderLines();
renderUtil->EnableLighting(oldLightingEnabled);
}
void RagdollNodeInspectorPlugin::RenderRagdoll(ActorInstance* actorInstance, bool renderColliders, bool renderJointLimits, EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
void RagdollNodeInspectorPlugin::LegacyRenderRagdoll(
ActorInstance* actorInstance,
bool renderColliders,
bool renderJointLimits,
EMStudio::RenderPlugin* renderPlugin,
RenderInfo* renderInfo)
{
const Actor* actor = actorInstance->GetActor();
const Skeleton* skeleton = actor->GetSkeleton();
@@ -495,11 +503,12 @@ namespace EMotionFX
if (renderColliders)
{
const Physics::CharacterColliderNodeConfiguration* colliderNodeConfig = colliderConfig.FindNodeConfigByName(joint->GetNameString());
const Physics::CharacterColliderNodeConfiguration* colliderNodeConfig =
colliderConfig.FindNodeConfigByName(joint->GetNameString());
if (colliderNodeConfig)
{
const AzPhysics::ShapeColliderPairList& colliders = colliderNodeConfig->m_shapes;
ColliderContainerWidget::RenderColliders(colliders, actorInstance, joint, renderInfo, finalColor);
ColliderContainerWidget::LegacyRenderColliders(colliders, actorInstance, joint, renderInfo, finalColor);
}
}
@@ -511,15 +520,15 @@ namespace EMotionFX
const Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
if (ragdollParentNode)
{
RenderJointLimit(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderPlugin, renderInfo, finalColor);
RenderJointFrame(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderInfo, finalColor);
LegacyRenderJointLimit(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderPlugin, renderInfo, finalColor);
LegacyRenderJointFrame(*jointLimitConfig, actorInstance, joint, ragdollParentNode, renderInfo, finalColor);
}
}
}
}
}
void RagdollNodeInspectorPlugin::RenderJointLimit(
void RagdollNodeInspectorPlugin::LegacyRenderJointLimit(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
@@ -567,7 +576,7 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::RenderJointFrame(
void RagdollNodeInspectorPlugin::LegacyRenderJointFrame(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
@@ -585,4 +594,192 @@ namespace EMotionFX
renderInfo->m_renderUtil->RenderArrow(0.1f, jointChildWorldSpaceTransformNoScale.m_position, MCore::GetRight(jointChildWorldSpaceTransformNoScale.ToAZTransform()), color);
}
void RagdollNodeInspectorPlugin::Render(EMotionFX::ActorRenderFlagBitset renderFlags)
{
const bool renderColliders = renderFlags[RENDER_RAGDOLL_COLLIDERS];
const bool renderJointLimits = renderFlags[RENDER_RAGDOLL_JOINTLIMITS];
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
@@ -54,9 +54,10 @@ namespace EMotionFX
static void AddCollider(const QModelIndexList& modelIndices, const AZ::TypeId& colliderType);
static void CopyColliders(const QModelIndexList& modelIndices, PhysicsSetup::ColliderConfigType copyFrom);
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void RenderRagdoll(ActorInstance* actorInstance, bool renderColliders, bool renderJointLimits, EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo);
void RenderJointLimit(
//! 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,
@@ -64,7 +65,7 @@ namespace EMotionFX
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
void RenderJointFrame(
void LegacyRenderJointFrame(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
@@ -72,6 +73,26 @@ namespace EMotionFX
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
//! Those function replaces legacyRender function and calls atom auxGeom render internally.
void Render(EMotionFX::ActorRenderFlagBitset 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();
@@ -8,6 +8,7 @@
#include <AzCore/std/algorithm.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands.h>
#include <EMotionFX/Source/Actor.h>
#include <EMotionFX/Source/ActorInstance.h>
@@ -18,6 +19,7 @@
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h>
#include <Editor/ColliderContainerWidget.h>
#include <Editor/ColliderHelpers.h>
#include <Editor/Plugins/SimulatedObject/SimulatedJointWidget.h>
@@ -25,6 +27,7 @@
#include <Editor/ReselectingTreeView.h>
#include <Editor/SimulatedObjectHelpers.h>
#include <Editor/SkeletonModel.h>
#include <Integration/Rendering/RenderActorSettings.h>
#include <MCore/Source/AzCoreConversions.h>
#include <QLabel>
#include <QPushButton>
@@ -330,6 +333,11 @@ namespace EMotionFX
const Actor* actor = selectedRowIndices[0].data(SkeletonModel::ROLE_ACTOR_POINTER).value<Actor*>();
const SimulatedObjectSetup* simulatedObjectSetup = actor->GetSimulatedObjectSetup().get();
if (!simulatedObjectSetup)
{
AZ_Assert(false, "Expected a simulated object setup on the actor.");
return;
}
AZStd::unordered_set<const SimulatedObject*> addToCandidates;
for (const QModelIndex& index : selectedRowIndices)
@@ -477,7 +485,7 @@ namespace EMotionFX
// -------------------------------------------------- Rendering -------------------------------------------------------------
void SimulatedObjectWidget::Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
void SimulatedObjectWidget::LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo)
{
if (!m_actor || !m_actorInstance)
{
@@ -501,7 +509,92 @@ namespace EMotionFX
ActorInstance* actorInstance = GetActorManager().GetActorInstance(actorInstanceIndex);
const Actor* actor = actorInstance->GetActor();
const SimulatedObjectSetup* setup = actor->GetSimulatedObjectSetup().get();
AZ_Assert(setup, "Expected a simulated object setup on the actor instance.");
if (!setup)
{
AZ_Assert(false, "Expected a simulated object setup on the actor instance.");
return;
}
const size_t objectCount = setup->GetNumSimulatedObjects();
for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex)
{
const SimulatedObject* object = setup->GetSimulatedObject(objectIndex);
const size_t simulatedJointCount = object->GetNumSimulatedJoints();
for (size_t simulatedJointIndex = 0; simulatedJointIndex < simulatedJointCount; ++simulatedJointIndex)
{
const SimulatedJoint* simulatedJoint = object->GetSimulatedJoint(simulatedJointIndex);
const size_t skeletonJointIndex = simulatedJoint->GetSkeletonJointIndex();
if (selectedJointIndices.find(skeletonJointIndex) != selectedJointIndices.end())
{
LegacyRenderJointRadius(simulatedJoint, actorInstance, AZ::Color(1.0f, 0.0f, 1.0f, 1.0f));
}
}
}
}
}
const bool renderColliders = activeViewWidget->GetRenderFlag(EMStudio::RenderViewWidget::RENDER_SIMULATEDOBJECT_COLLIDERS);
if (renderColliders)
{
const EMStudio::RenderOptions* renderOptions = renderPlugin->GetRenderOptions();
ColliderContainerWidget::LegacyRenderColliders(PhysicsSetup::SimulatedObjectCollider,
renderOptions->GetSimulatedObjectColliderColor(),
renderOptions->GetSelectedSimulatedObjectColliderColor(),
renderPlugin,
renderInfo);
}
}
void SimulatedObjectWidget::LegacyRenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color)
{
#ifndef EMFX_SCALE_DISABLED
const float scale = actorInstance->GetWorldSpaceTransform().m_scale.GetX();
#else
const float scale = 1.0f;
#endif
const float radius = joint->GetCollisionRadius() * scale;
if (radius <= AZ::Constants::FloatEpsilon)
{
return;
}
AZ_Assert(joint->GetSkeletonJointIndex() != InvalidIndex, "Expected skeletal joint index to be valid.");
const EMotionFX::Transform jointTransform =
actorInstance->GetTransformData()->GetCurrentPose()->GetWorldSpaceTransform(joint->GetSkeletonJointIndex());
DebugDraw& debugDraw = GetDebugDraw();
DebugDraw::ActorInstanceData* drawData = debugDraw.GetActorInstanceData(actorInstance);
drawData->Lock();
drawData->DrawWireframeSphere(jointTransform.m_position, radius, color, jointTransform.m_rotation, 12, 12);
drawData->Unlock();
}
void SimulatedObjectWidget::Render(EMotionFX::ActorRenderFlagBitset renderFlags)
{
if (!m_actor || !m_actorInstance)
{
return;
}
const AZ::Render::RenderActorSettings& settings = EMotionFX::GetRenderActorSettings();
const bool renderSimulatedJoints = renderFlags[RENDER_SIMULATEJOINTS];
const AZStd::unordered_set<size_t>& selectedJointIndices = EMStudio::GetManager()->GetSelectedJointIndices();
if (renderSimulatedJoints && !selectedJointIndices.empty())
{
// Render the joint radius.
const size_t actorInstanceCount = GetActorManager().GetNumActorInstances();
for (size_t actorInstanceIndex = 0; actorInstanceIndex < actorInstanceCount; ++actorInstanceIndex)
{
ActorInstance* actorInstance = GetActorManager().GetActorInstance(actorInstanceIndex);
const Actor* actor = actorInstance->GetActor();
const SimulatedObjectSetup* setup = actor->GetSimulatedObjectSetup().get();
if (!setup)
{
AZ_Assert(false, "Expected a simulated object setup on the actor instance.");
return;
}
const size_t objectCount = setup->GetNumSimulatedObjects();
for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex)
{
@@ -520,25 +613,21 @@ namespace EMotionFX
}
}
const bool renderColliders = activeViewWidget->GetRenderFlag(EMStudio::RenderViewWidget::RENDER_SIMULATEDOBJECT_COLLIDERS);
const bool renderColliders = renderFlags[RENDER_SIMULATEDOBJECT_COLLIDERS];
if (renderColliders)
{
const EMStudio::RenderOptions* renderOptions = renderPlugin->GetRenderOptions();
ColliderContainerWidget::RenderColliders(PhysicsSetup::SimulatedObjectCollider,
renderOptions->GetSimulatedObjectColliderColor(),
renderOptions->GetSelectedSimulatedObjectColliderColor(),
renderPlugin,
renderInfo);
settings.m_simulatedObjectColliderColor, settings.m_selectedSimulatedObjectColliderColor);
}
}
void SimulatedObjectWidget::RenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color)
void SimulatedObjectWidget::RenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color)
{
#ifndef EMFX_SCALE_DISABLED
const float scale = actorInstance->GetWorldSpaceTransform().m_scale.GetX();
#else
const float scale = 1.0f;
#endif
#ifndef EMFX_SCALE_DISABLED
const float scale = actorInstance->GetWorldSpaceTransform().m_scale.GetX();
#else
const float scale = 1.0f;
#endif
const float radius = joint->GetCollisionRadius() * scale;
if (radius <= AZ::Constants::FloatEpsilon)
@@ -547,12 +636,21 @@ namespace EMotionFX
}
AZ_Assert(joint->GetSkeletonJointIndex() != InvalidIndex, "Expected skeletal joint index to be valid.");
const EMotionFX::Transform jointTransform = actorInstance->GetTransformData()->GetCurrentPose()->GetWorldSpaceTransform(joint->GetSkeletonJointIndex());
const EMotionFX::Transform jointTransform =
actorInstance->GetTransformData()->GetCurrentPose()->GetWorldSpaceTransform(joint->GetSkeletonJointIndex());
DebugDraw& debugDraw = GetDebugDraw();
DebugDraw::ActorInstanceData* drawData = debugDraw.GetActorInstanceData(actorInstance);
drawData->Lock();
drawData->DrawWireframeSphere(jointTransform.m_position, radius, color, jointTransform.m_rotation, 12, 12);
drawData->Unlock();
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->DrawWireSphere(jointTransform.m_position, radius);
}
} // namespace EMotionFX
@@ -59,8 +59,9 @@ namespace EMotionFX
bool Init() override;
void Reinit();
// Render
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void LegacyRender(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void LegacyRenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color);
void Render(EMotionFX::ActorRenderFlagBitset renderFlags) override;
void RenderJointRadius(const SimulatedJoint* joint, ActorInstance* actorInstance, const AZ::Color& color);
SimulatedObjectModel* GetSimulatedObjectModel() const;
@@ -27,6 +27,16 @@ namespace AZ::Render
float m_tangentsScale = 1.0f;
float m_wireframeScale = 1.0f;
AZ::Color m_hitDetectionColliderColor{0.44f, 0.44f, 0.44f, 1.0f};
AZ::Color m_selectedHitDetectionColliderColor{ 0.3f, 0.56f, 0.88f, 1.0f };
AZ::Color m_ragdollColliderColor{ 0.44f, 0.44f, 0.44f, 1.0f };
AZ::Color m_selectedRagdollColliderColor{ 0.96f, 0.65f, 0.14f, 1.0f };
AZ::Color m_violatedJointLimitColor{ 1.0f, 0.0f, 0.0f, 1.0f };
AZ::Color m_clothColliderColor{ 0.44f, 0.44f, 0.44f, 1.0f };
AZ::Color m_selectedClothColliderColor{ 0.6f, 0.46f, 1.0f, 1.0f };
AZ::Color m_simulatedObjectColliderColor{ 0.44f, 0.44f, 0.44f, 1.0f };
AZ::Color m_selectedSimulatedObjectColliderColor{ 1.0, 0.34f, 0.87f, 1.0f };
AZ::Color m_vertexNormalsColor{ 0.0f, 1.0f, 0.0f, 1.0f };
AZ::Color m_faceNormalsColor{ 0.5f, 0.5f, 1.0f, 1.0f };
AZ::Color m_tangentsColor{ 1.0f, 0.0f, 0.0f, 1.0f };