diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 9672abfd99..bed4778e8e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -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()) + { + m_viewportContext->SetRenderScene(*existingScene); + if (auto auxGeomFP = existingScene->get()->GetFeatureProcessor()) + { + m_auxGeom = auxGeomFP->GetOrCreateDrawQueueForView(m_defaultCamera.get()); + } + return; + } + AZ::RPI::ScenePtr atomScene; auto initializeScene = [&](AZ::Render::Bootstrap::Request* bootstrapRequests) { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 4c17eaf06a..a32af31d6d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -24,8 +24,6 @@ #include #include -#include -#include #include #include #include @@ -122,22 +120,15 @@ namespace EMStudio const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs(); 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()); - m_gridEntity->Init(); - m_gridEntity->Activate(); + m_groundEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_groundEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_groundEntity->CreateComponent(azrtti_typeid()); + 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 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(); 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( + "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() diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index df69856355..27e62bb130 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -56,6 +56,8 @@ namespace EMStudio void UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags); + AZStd::shared_ptr 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 m_actorEntities; const RenderOptions* m_renderOptions; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp index 50cd088f5d..3b53103537 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp @@ -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 diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index cf7341e9ab..cd362bdaf5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -35,6 +35,7 @@ namespace EMStudio setStyleSheet(QString::fromUtf8("")); m_renderer = AZStd::make_unique(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 diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 7a8ae2cf52..069aebb73e 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -10,6 +10,8 @@ #include #include #include + +#include #include #include @@ -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; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h index 0de4ab946c..8ae84b6e49 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "EMStudioConfig.h" #include #include @@ -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; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp index 496781d316..d1e3dc5ebc 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp @@ -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 diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp index 429a0bffae..4a02e75fbd 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp @@ -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(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h new file mode 100644 index 0000000000..27953fac4b --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/ViewportPluginBus.h @@ -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 + +namespace EMStudio +{ + class ViewportPluginRequests + : public AZ::EBusTraits + { + public: + virtual AZ::s32 GetViewportId() const = 0; + }; + + using ViewportPluginRequestBus = AZ::EBus; +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.cpp index 87c6a601aa..912947e302 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.cpp @@ -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; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h index 7f4ebc3e78..84c2ccee9b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h @@ -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(); diff --git a/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.cpp b/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.cpp index fea4f23c6a..13696298dc 100644 --- a/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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(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(static_cast(worldScale.GetX()), static_cast(worldScale.GetY()), static_cast(worldScale.GetZ())); renderUtil->RenderWireframeSphere(radius, emfxColliderGlobalTransformNoScale.ToAZTransform(), colliderColor); @@ -647,7 +648,7 @@ namespace EMotionFX { Physics::CapsuleShapeConfiguration* capsule = static_cast(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(static_cast(worldScale.GetX()), static_cast(worldScale.GetY())); const float height = capsule->m_height * static_cast(worldScale.GetZ()); @@ -657,7 +658,7 @@ namespace EMotionFX { Physics::BoxShapeConfiguration* box = static_cast(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* sphere = static_cast(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(static_cast(worldScale.GetX()), static_cast(worldScale.GetY()), + static_cast(worldScale.GetZ())); + + debugDisplay->DepthTestOff(); + debugDisplay->SetColor(colliderColor); + debugDisplay->DrawWireSphere(emfxColliderGlobalTransformNoScale.m_position, radius); + } + else if (colliderType == azrtti_typeid()) + { + Physics::CapsuleShapeConfiguration* capsule = static_cast(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(static_cast(worldScale.GetX()), static_cast(worldScale.GetY())); + const float height = capsule->m_height * static_cast(worldScale.GetZ()); + + debugDisplay->DepthTestOff(); + debugDisplay->SetColor(colliderColor); + debugDisplay->DrawWireCapsule( + emfxColliderGlobalTransformNoScale.m_position, emfxColliderGlobalTransformNoScale.ToAZTransform().GetBasisZ(), radius, height); + } + else if (colliderType == azrtti_typeid()) + { + Physics::BoxShapeConfiguration* box = static_cast(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& 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 = 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) diff --git a/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.h b/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.h index f4641e4ad6..82e6d151d5 100644 --- a/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.h +++ b/Gems/EMotionFX/Code/Source/Editor/ColliderContainerWidget.h @@ -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: diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.cpp b/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.cpp index e1a58f1f44..161cc2ac95 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -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 diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.h b/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.h index 6a920fa10d..c1b3e9ad13 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.h +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/Cloth/ClothJointInspectorPlugin.h @@ -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: diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.cpp b/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.cpp index b7cf3ea13d..0f0eb89bfc 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -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 diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h b/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h index 5454fc56f9..4dc61f9b9e 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h @@ -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(); diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.cpp b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.cpp index cb5c525cec..e76cf42c44 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -17,12 +18,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -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& physicsSetup = actor->GetPhysicsSetup(); + const Physics::RagdollConfiguration& ragdollConfig = physicsSetup->GetRagdollConfig(); + const AZStd::vector& 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& 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 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& 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::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 diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h index 36a33c1cd3..d3b27da5ce 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h @@ -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(); diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.cpp b/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.cpp index 48104707de..695603cecb 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -330,6 +333,11 @@ namespace EMotionFX const Actor* actor = selectedRowIndices[0].data(SkeletonModel::ROLE_ACTOR_POINTER).value(); const SimulatedObjectSetup* simulatedObjectSetup = actor->GetSimulatedObjectSetup().get(); + if (!simulatedObjectSetup) + { + AZ_Assert(false, "Expected a simulated object setup on the actor."); + return; + } AZStd::unordered_set 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& 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 diff --git a/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h b/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h index 955c97ce13..9662fbc150 100644 --- a/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h +++ b/Gems/EMotionFX/Code/Source/Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h @@ -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; diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h index 3e4f5ff5c9..c397690b16 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h @@ -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 };