diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 38af4232ba..755db41996 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -65,36 +65,38 @@ #if defined(EMOTIONFXANIMATION_EDITOR) // EMFX tools / editor includes // Qt -# include +#include // EMStudio tools and main window registration -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include // EMStudio plugins -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #endif // EMOTIONFXANIMATION_EDITOR #include @@ -589,14 +591,12 @@ namespace EMotionFX #endif REGISTER_CVAR2("emfx_updateEnabled", &CVars::emfx_updateEnabled, 1, VF_DEV_ONLY, "Enable main EMFX update"); - REGISTER_CVAR2("emfx_actorRenderEnabled", &CVars::emfx_actorRenderEnabled, 1, VF_DEV_ONLY, "Enable ActorRenderNode rendering"); } ////////////////////////////////////////////////////////////////////////// void SystemComponent::OnCrySystemShutdown(ISystem&) { gEnv->pConsole->UnregisterVariable("emfx_updateEnabled"); - gEnv->pConsole->UnregisterVariable("emfx_actorRenderEnabled"); #if !defined(AZ_MONOLITHIC_BUILD) gEnv = nullptr; @@ -620,75 +620,102 @@ namespace EMotionFX { // Main EMotionFX runtime update. GetEMotionFX().Update(delta); - } - const ActorManager* actorManager = GetEMotionFX().GetActorManager(); - const size_t numActorInstances = actorManager->GetNumActorInstances(); - for (size_t i = 0; i < numActorInstances; ++i) - { - const ActorInstance* actorInstance = actorManager->GetActorInstance(i); + bool inGameMode = true; +#if defined (EMOTIONFXANIMATION_EDITOR) + // Check if we are in game mode. + IEditor* editor = nullptr; + AzToolsFramework::EditorRequestBus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::GetEditor); + inGameMode = editor->IsInGameMode(); +#endif - if (actorInstance && actorInstance->GetIsEnabled() && actorInstance->GetIsOwnedByRuntime()) + // Apply the motion extraction deltas to the character controller / entity transform for all entities. + const ActorManager* actorManager = GetEMotionFX().GetActorManager(); + const size_t numActorInstances = actorManager->GetNumActorInstances(); + for (size_t i = 0; i < numActorInstances; ++i) { - AZ::Entity* entity = actorInstance->GetEntity(); - const Actor* actor = actorInstance->GetActor(); + ActorInstance* actorInstance = actorManager->GetActorInstance(i); - if (entity && actor && actor->GetMotionExtractionNode()) + // Apply motion extraction only in game mode or in case the actor instance belongs to the Animation Editor. + const bool applyMotionExtraction = inGameMode || !actorInstance->GetIsOwnedByRuntime(); + if (applyMotionExtraction) { - const AZ::EntityId entityId = entity->GetId(); - - // Check if we have any physics character controllers. - bool hasCustomMotionExtractionController = false; - bool hasPhysicsController = false; - - Physics::CharacterRequestBus::EventResult(hasPhysicsController, entityId, &Physics::CharacterRequests::IsPresent); - if (!hasPhysicsController) - { - hasCustomMotionExtractionController = MotionExtractionRequestBus::FindFirstHandler(entityId) != nullptr; - } - - // If we have a physics controller. - if (hasCustomMotionExtractionController || hasPhysicsController) - { - const float deltaTimeInv = (delta > 0.0f) ? (1.0f / delta) : 0.0f; - - AZ::Transform currentTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); - - const AZ::Vector3 actorInstancePosition = actorInstance->GetWorldSpaceTransform().m_position; - const AZ::Vector3 positionDelta = actorInstancePosition - currentTransform.GetTranslation(); - - if (hasPhysicsController) - { - Physics::CharacterRequestBus::Event( - entityId, &Physics::CharacterRequests::AddVelocity, positionDelta * deltaTimeInv); - } - else if (hasCustomMotionExtractionController) - { - MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, delta); - AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); - } - - // Update the entity rotation. - const AZ::Quaternion actorInstanceRotation = actorInstance->GetWorldSpaceTransform().m_rotation; - const AZ::Quaternion currentRotation = currentTransform.GetRotation(); - if (!currentRotation.IsClose(actorInstanceRotation, AZ::Constants::FloatEpsilon)) - { - AZ::Transform newTransform = currentTransform; - newTransform.SetRotation(actorInstanceRotation); - AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform); - } - } - else // There is no physics controller, just use EMotion FX's actor instance transform directly. - { - const AZ::Transform newTransform = actorInstance->GetWorldSpaceTransform().ToAZTransform(); - AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform); - } + actorInstance->SetMotionExtractionEnabled(true); + ApplyMotionExtraction(actorInstance, delta); + } + else + { + actorInstance->SetMotionExtractionEnabled(false); } } } } + void SystemComponent::ApplyMotionExtraction(const ActorInstance* actorInstance, float timeDelta) + { + AZ_Assert(actorInstance, "Cannot apply motion extraction. Actor instance is not valid."); + AZ_Assert(actorInstance->GetActor(), "Cannot apply motion extraction. Actor instance is not linked to a valid actor."); + + AZ::Entity* entity = actorInstance->GetEntity(); + const Actor* actor = actorInstance->GetActor(); + if (!actorInstance->GetIsEnabled() || + !entity || + !actor->GetMotionExtractionNode()) + { + return; + } + + const AZ::EntityId entityId = entity->GetId(); + + // Check if we have any physics character controllers. + bool hasCustomMotionExtractionController = false; + bool hasPhysicsController = false; + + Physics::CharacterRequestBus::EventResult(hasPhysicsController, entityId, &Physics::CharacterRequests::IsPresent); + if (!hasPhysicsController) + { + hasCustomMotionExtractionController = MotionExtractionRequestBus::FindFirstHandler(entityId) != nullptr; + } + + // If we have a physics controller. + if (hasCustomMotionExtractionController || hasPhysicsController) + { + const float deltaTimeInv = (timeDelta > 0.0f) ? (1.0f / timeDelta) : 0.0f; + + AZ::Transform currentTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); + + const AZ::Vector3 actorInstancePosition = actorInstance->GetWorldSpaceTransform().m_position; + const AZ::Vector3 positionDelta = actorInstancePosition - currentTransform.GetTranslation(); + + if (hasPhysicsController) + { + Physics::CharacterRequestBus::Event( + entityId, &Physics::CharacterRequests::AddVelocity, positionDelta * deltaTimeInv); + } + else if (hasCustomMotionExtractionController) + { + MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, timeDelta); + AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); + } + + // Update the entity rotation. + const AZ::Quaternion actorInstanceRotation = actorInstance->GetWorldSpaceTransform().m_rotation; + const AZ::Quaternion currentRotation = currentTransform.GetRotation(); + if (!currentRotation.IsClose(actorInstanceRotation, AZ::Constants::FloatEpsilon)) + { + AZ::Transform newTransform = currentTransform; + newTransform.SetRotation(actorInstanceRotation); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform); + } + } + else // There is no physics controller, just use EMotion FX's actor instance transform directly. + { + const AZ::Transform newTransform = actorInstance->GetWorldSpaceTransform().ToAZTransform(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform); + } + } + int SystemComponent::GetTickOrder() { return AZ::TICK_ANIMATION; diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h index 3ef626c947..5be9afbbaa 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h @@ -124,6 +124,13 @@ namespace EMotionFX AZ::u32 m_numThreads; private: + //! Synchronize the actor instance location with the entity or character controller. + //! In case no character controller component is available, the entity will be moved + //! to the actor instance position. The spatial difference between the entity and the + //! actor instance will be calculated in case a character controller is present, and the + //! velocity will be applied to it to move it towards the actor instance. + void ApplyMotionExtraction(const ActorInstance* actorInstance, float timeDelta); + AZStd::vector > m_assetHandlers; AZStd::unique_ptr m_eventHandler; AZStd::unique_ptr m_renderBackendManager;