diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 4db69cf8d9..f3294ddc09 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -9,8 +9,8 @@ #include #include -#include #include +#include #include #include #include @@ -32,12 +32,15 @@ #include #include +#include +#include #include -#pragma optimize("", off) + namespace EMStudio { static constexpr float DepthNear = 0.01f; + static constexpr const char* const s_actorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; AnimViewportRenderer::AnimViewportRenderer(AZStd::shared_ptr windowContext) : m_windowContext(windowContext) @@ -136,29 +139,6 @@ namespace EMStudio const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs(); SetLightingPreset(preset); - // Create a static model. - // TODO: Replace this with actor component. - AzFramework::EntityContextRequestBus::EventResult( - m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); - - m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Activate(); - - // Create an actor. - // TODO: Support multiple actors. - AzFramework::EntityContextRequestBus::EventResult( - m_actorEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_actorEntity != nullptr, "Failed to create model entity."); - - static constexpr const char* const ActorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; - m_actorEntity->CreateComponent(ActorComponentTypeId); - m_actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_actorEntity->CreateComponent(azrtti_typeid()); - m_actorEntity->Activate(); - // Create grid AzFramework::EntityContextRequestBus::EventResult( m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); @@ -175,24 +155,21 @@ namespace EMStudio m_gridEntity->CreateComponent(azrtti_typeid()); m_gridEntity->Activate(); - Reset(); + Reinit(); } AnimViewportRenderer::~AnimViewportRenderer() { - const AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId(); - // Destory all the entities we created. - auto DestoryEntity = [](AZ::Entity* entity, AzFramework::EntityContextId contextId) + // Destroy all the entity we created. + m_entityContext->DestroyEntity(m_iblEntity); + m_entityContext->DestroyEntity(m_postProcessEntity); + m_entityContext->DestroyEntity(m_cameraEntity); + m_entityContext->DestroyEntity(m_gridEntity); + for (AZ::Entity* entity : m_actorEntities) { - AzFramework::EntityContextRequestBus::Event(contextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, entity); - entity = nullptr; - }; - DestoryEntity(m_iblEntity, entityContextId); - DestoryEntity(m_postProcessEntity, entityContextId); - DestoryEntity(m_cameraEntity, entityContextId); - DestoryEntity(m_modelEntity, entityContextId); - DestoryEntity(m_actorEntity, entityContextId); - DestoryEntity(m_gridEntity, entityContextId); + m_entityContext->DestroyEntity(entity); + } + m_actorEntities.clear(); m_entityContext->DestroyContext(); for (AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle& handle : m_lightHandles) @@ -212,7 +189,13 @@ namespace EMStudio m_scene = nullptr; } - void AnimViewportRenderer::Reset() + void AnimViewportRenderer::Reinit() + { + ReinitActorEntities(); + ResetEnvironment(); + } + + void AnimViewportRenderer::ResetEnvironment() { // Reset environment AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); @@ -223,22 +206,6 @@ namespace EMStudio auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); - // Reset model - AZ::Transform modelTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::Event(m_modelEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); - - auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( - "objects/shaderball_simple.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert); - AZ::Render::MeshComponentRequestBus::Event( - m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset); - - // Reset the actor asset - AZ::TransformBus::Event(m_actorEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); - auto actorAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( - "objects/characters/jack/jack.actor", AZ::RPI::AssetUtils::TraceLevel::Assert); - EMotionFX::Integration::ActorComponentRequestBus::Event( - m_actorEntity->GetId(), &EMotionFX::Integration::ActorComponentRequestBus::Events::SetActorAsset, actorAsset); - Camera::Configuration cameraConfig; Camera::CameraRequestBus::EventResult( cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); @@ -247,7 +214,7 @@ namespace EMStudio static constexpr float StartingDistanceMultiplier = 2.0f; static constexpr float StartingRotationAngle = AZ::Constants::QuarterPi / 2.0f; - AZ::Vector3 targetPosition = modelTransform.GetTranslation(); + AZ::Vector3 targetPosition = iblTransform.GetTranslation(); const float distance = 1.0f * StartingDistanceMultiplier; const AZ::Quaternion cameraRotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), StartingRotationAngle); AZ::Vector3 cameraPosition(targetPosition.GetX(), targetPosition.GetY() - distance, targetPosition.GetZ()); @@ -260,6 +227,75 @@ namespace EMStudio m_cameraEntity->GetId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable, azrtti_typeid()); } + void AnimViewportRenderer::ReinitActorEntities() + { + // 1. Destroy all the entities that does not point to any actorAsset anymore. + AZStd::set assetLookup; + AzFramework::EntityContext* entityContext = m_entityContext.get(); + const size_t numActors = EMotionFX::GetActorManager().GetNumActors(); + for (size_t i = 0; i < numActors; ++i) + { + assetLookup.emplace(EMotionFX::GetActorManager().GetActorAsset(i).GetId()); + } + m_actorEntities.erase( + AZStd::remove_if( + m_actorEntities.begin(), m_actorEntities.end(), + [&assetLookup, entityContext](AZ::Entity* entity) + { + EMotionFX::Integration::ActorComponent* actorComponent = + entity->FindComponent(); + if (assetLookup.find(actorComponent->GetActorAsset().GetId()) == assetLookup.end()) + { + entityContext->DestroyEntity(entity); + return true; + } + return false; + }), + m_actorEntities.end()); + + // 2. Create an entity for every actorAsset stored in actor manager. + for (size_t i = 0; i < numActors; ++i) + { + AZ::Data::Asset actorAsset = EMotionFX::GetActorManager().GetActorAsset(i); + if (!actorAsset->IsReady()) + { + continue; + } + + AZ::Entity* entity = FindActorEntity(actorAsset); + if (!entity) + { + m_actorEntities.emplace_back(CreateActorEntity(actorAsset)); + } + } + } + + AZ::Entity* AnimViewportRenderer::FindActorEntity(AZ::Data::Asset actorAsset) const + { + const auto foundEntity = AZStd::find_if( + begin(m_actorEntities), end(m_actorEntities), + [match = actorAsset](const AZ::Entity* entity) + { + EMotionFX::Integration::ActorComponent* actorComponent = entity->FindComponent(); + return actorComponent->GetActorAsset() == match; + }); + return foundEntity != end(m_actorEntities) ? (*foundEntity) : nullptr; + } + + AZ::Entity* AnimViewportRenderer::CreateActorEntity(AZ::Data::Asset actorAsset) + { + AZ::Entity* actorEntity = m_entityContext->CreateEntity(actorAsset->GetActor()->GetName()); + actorEntity->CreateComponent(s_actorComponentTypeId); + actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + actorEntity->CreateComponent(azrtti_typeid()); + actorEntity->Activate(); + + EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent(); + actorComponent->SetActorAsset(actorAsset); + + return actorEntity; + } + void AnimViewportRenderer::SetLightingPreset(const AZ::Render::LightingPreset* preset) { if (!preset) @@ -272,7 +308,6 @@ namespace EMStudio m_scene->GetFeatureProcessor(); AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId()) ->GetOrCreateExposureControlSettingsInterface(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index eb590f8d71..c131605caa 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -46,9 +47,21 @@ namespace EMStudio AnimViewportRenderer(AZStd::shared_ptr windowContext); ~AnimViewportRenderer(); + void Reinit(); + private: - void Reset(); + // This function reset the light, camera and other environment settings. + void ResetEnvironment(); + + // This function create in-editor entities for all the actor asset stored in the actor manager, + // and delete all the actor entities that no longer has an actor asset in the actor manager. + // Those entities are used in atom render viewport to visualize actors in animation editor. + void ReinitActorEntities(); + + AZ::Entity* CreateActorEntity(AZ::Data::Asset actorAsset); + + AZ::Entity* FindActorEntity(AZ::Data::Asset actorAsset) const; void SetLightingPreset(const AZ::Render::LightingPreset* preset); AZStd::shared_ptr m_windowContext; @@ -66,9 +79,9 @@ namespace EMStudio AZ::Entity* m_cameraEntity = nullptr; AZ::Component* m_cameraComponent = nullptr; AZ::Entity* m_modelEntity = nullptr; - AZ::Entity* m_actorEntity = nullptr; AZ::Data::AssetId m_modelAssetId; AZ::Entity* m_gridEntity = nullptr; + AZStd::vector m_actorEntities; AZStd::vector m_lightHandles; }; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 26bb9838b3..9e074c1d2c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -9,6 +9,7 @@ #include + namespace EMStudio { class AnimViewportRenderer; @@ -18,6 +19,7 @@ namespace EMStudio { public: AnimViewportWidget(QWidget* parent = nullptr); + AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get();} private: AZStd::unique_ptr m_renderer; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index c7e2178366..735c90d762 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -7,6 +7,11 @@ */ #include +#include + +#include +#include +#include #include namespace EMStudio @@ -66,6 +71,11 @@ namespace EMStudio return EMStudioPlugin::PLUGINTYPE_RENDERING; } + void AtomRenderPlugin::ReinitRenderer() + { + m_animViewportWidget->GetAnimViewportRenderer()->Reinit(); + } + bool AtomRenderPlugin::Init() { m_innerWidget = new QWidget(); @@ -75,9 +85,40 @@ namespace EMStudio verticalLayout->setSizeConstraint(QLayout::SetNoConstraint); verticalLayout->setSpacing(1); verticalLayout->setMargin(0); - m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + // Register command callbacks. + m_createActorInstanceCallback = new CreateActorInstanceCallback(false); + EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("CreateActorInstance", m_createActorInstanceCallback); + return true; } + + // Command callbacks + bool ReinitAtomRenderPlugin() + { + EMStudioPlugin* plugin = EMStudio::GetPluginManager()->FindActivePlugin(static_cast(AtomRenderPlugin::CLASS_ID)); + if (!plugin) + { + AZ_Error("AtomRenderPlugin", false, "Cannot execute command callback. Atom render plugin does not exist."); + return false; + } + + AtomRenderPlugin* atomRenderPlugin = static_cast(plugin); + atomRenderPlugin->ReinitRenderer(); + + return true; + } + + bool AtomRenderPlugin::CreateActorInstanceCallback::Execute( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + bool AtomRenderPlugin::CreateActorInstanceCallback::Undo( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 0fb1443a96..9e5b3b6937 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -9,11 +9,18 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include + #include #include #endif +namespace AZ +{ + class Entity; +} + namespace EMStudio { class AtomRenderPlugin @@ -39,7 +46,12 @@ namespace EMStudio EMStudioPlugin* Clone(); EMStudioPlugin::EPluginType GetPluginType() const override; + void ReinitRenderer(); + private: + MCORE_DEFINECOMMANDCALLBACK(CreateActorInstanceCallback); + CreateActorInstanceCallback* m_createActorInstanceCallback; + QWidget* m_innerWidget; AnimViewportWidget* m_animViewportWidget; }; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index 0779e55f85..0593575623 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -429,6 +429,12 @@ namespace EMotionFX } + ActorManager::ActorAssetData ActorManager::GetActorAsset(size_t nr) const + { + return m_actorAssets[nr]; + } + + const AZStd::vector& ActorManager::GetActorInstanceArray() const { return m_actorInstances; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h index e4ce0d6c94..e8bbf40661 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h @@ -80,6 +80,7 @@ namespace EMotionFX * @result A reference to the actor object that contains the array of Actor objects. */ Actor* GetActor(size_t nr) const; + ActorAssetData GetActorAsset(size_t nr) const; /** * Find the given actor by name.