EMotion FX: Apply motion extraction only in game-mode and for anim editor entities (#5401)
* Motion extraction should only be applied when in game mode or for entities that belong to the Animation Editor. We don't want our entities to move in editor mode. * Moved code into separate function that actually applies the trajectory delta to the entity/character controller. Signed-off-by: Benjamin Jillich <jillich@amazon.com>
This commit is contained in:
@@ -65,36 +65,38 @@
|
||||
|
||||
#if defined(EMOTIONFXANIMATION_EDITOR) // EMFX tools / editor includes
|
||||
// Qt
|
||||
# include <QtGui/QSurfaceFormat>
|
||||
#include <QtGui/QSurfaceFormat>
|
||||
// EMStudio tools and main window registration
|
||||
# include <LyViewPaneNames.h>
|
||||
# include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
# include <AzCore/std/string/wildcard.h>
|
||||
# include <QApplication>
|
||||
# include <EMotionStudio/EMStudioSDK/Source/MainWindow.h>
|
||||
# include <EMotionStudio/EMStudioSDK/Source/PluginManager.h>
|
||||
#include <LyViewPaneNames.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <QApplication>
|
||||
#include <EMotionStudio/EMStudioSDK/Source/MainWindow.h>
|
||||
#include <EMotionStudio/EMStudioSDK/Source/PluginManager.h>
|
||||
// EMStudio plugins
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/CommandBar/CommandBarPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/ActionHistory/ActionHistoryPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/MorphTargetsWindow/MorphTargetsWindowPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/TimeView/TimeViewPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/Attachments/AttachmentsPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/SceneManagerPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/MotionEvents/MotionEventsPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/MotionSetsWindow/MotionSetsWindowPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.h>
|
||||
# include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
|
||||
# include <EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.h>
|
||||
# include <Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h>
|
||||
# include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
|
||||
# include <Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h>
|
||||
# include <Editor/Plugins/Cloth/ClothJointInspectorPlugin.h>
|
||||
# include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
|
||||
# include <Source/Editor/PropertyWidgets/PropertyTypes.h>
|
||||
# include <EMotionFX_Traits_Platform.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/CommandBar/CommandBarPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/ActionHistory/ActionHistoryPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MorphTargetsWindow/MorphTargetsWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/TimeView/TimeViewPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/Attachments/AttachmentsPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/SceneManagerPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionEvents/MotionEventsPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionSetsWindow/MotionSetsWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
|
||||
#include <EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.h>
|
||||
#include <Editor/Plugins/HitDetection/HitDetectionJointInspectorPlugin.h>
|
||||
#include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
|
||||
#include <Editor/Plugins/Ragdoll/RagdollNodeInspectorPlugin.h>
|
||||
#include <Editor/Plugins/Cloth/ClothJointInspectorPlugin.h>
|
||||
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
|
||||
#include <Source/Editor/PropertyWidgets/PropertyTypes.h>
|
||||
#include <EMotionFX_Traits_Platform.h>
|
||||
|
||||
#include <IEditor.h>
|
||||
#endif // EMOTIONFXANIMATION_EDITOR
|
||||
|
||||
#include <IConsole.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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<AZStd::unique_ptr<AZ::Data::AssetHandler> > m_assetHandlers;
|
||||
AZStd::unique_ptr<EMotionFXEventHandler> m_eventHandler;
|
||||
AZStd::unique_ptr<RenderBackendManager> m_renderBackendManager;
|
||||
|
||||
Reference in New Issue
Block a user