Add ability to load actor from the ui

Signed-off-by: rhhong <rhhong@amazon.com>
This commit is contained in:
rhhong
2021-09-27 16:27:32 -07:00
parent c463721b52
commit 82bfbd5c98
7 changed files with 170 additions and 60 deletions
@@ -9,8 +9,8 @@
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <Integration/Assets/ActorAsset.h>
#include <Integration/ActorComponentBus.h>
#include <Integration/Components/ActorComponent.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
@@ -32,12 +32,15 @@
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConstants.h>
#include <EMotionFX/Source/EMotionFXManager.h>
#include <EMotionFX/Source/ActorManager.h>
#include <EMStudio/AnimViewportRenderer.h>
#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<AZ::RPI::WindowContext> windowContext)
: m_windowContext(windowContext)
@@ -136,29 +139,6 @@ namespace EMStudio
const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs<AZ::Render::LightingPreset>();
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<AzFramework::TransformComponent>());
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<AzFramework::TransformComponent>());
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<AzFramework::TransformComponent>());
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<AZ::Render::SkyBoxFeatureProcessorInterface>();
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<AZ::RPI::ModelAsset>(
"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<EMotionFX::Integration::ActorAsset>(
"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<AZ::Debug::NoClipControllerComponent>());
}
void AnimViewportRenderer::ReinitActorEntities()
{
// 1. Destroy all the entities that does not point to any actorAsset anymore.
AZStd::set<AZ::Data::AssetId> 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<EMotionFX::Integration::ActorComponent>();
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<EMotionFX::Integration::ActorAsset> 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<EMotionFX::Integration::ActorAsset> 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<EMotionFX::Integration::ActorComponent>();
return actorComponent->GetActorAsset() == match;
});
return foundEntity != end(m_actorEntities) ? (*foundEntity) : nullptr;
}
AZ::Entity* AnimViewportRenderer::CreateActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset)
{
AZ::Entity* actorEntity = m_entityContext->CreateEntity(actorAsset->GetActor()->GetName());
actorEntity->CreateComponent(s_actorComponentTypeId);
actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
actorEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
actorEntity->Activate();
EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent<EMotionFX::Integration::ActorComponent>();
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::ImageBasedLightFeatureProcessorInterface>();
AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor =
m_scene->GetFeatureProcessor<AZ::Render::PostProcessFeatureProcessorInterface>();
AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface =
postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())
->GetOrCreateExposureControlSettingsInterface();
@@ -12,6 +12,7 @@
#include <AzFramework/Windowing/NativeWindow.h>
#include <AzFramework/Scene/Scene.h>
#include <Integration/Assets/ActorAsset.h>
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/WindowContext.h>
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
@@ -46,9 +47,21 @@ namespace EMStudio
AnimViewportRenderer(AZStd::shared_ptr<AZ::RPI::WindowContext> 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<EMotionFX::Integration::ActorAsset> actorAsset);
AZ::Entity* FindActorEntity(AZ::Data::Asset<EMotionFX::Integration::ActorAsset> actorAsset) const;
void SetLightingPreset(const AZ::Render::LightingPreset* preset);
AZStd::shared_ptr<AZ::RPI::WindowContext> 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<AZ::Entity*> m_actorEntities;
AZStd::vector<AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle> m_lightHandles;
};
@@ -9,6 +9,7 @@
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
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<AnimViewportRenderer> m_renderer;
@@ -7,6 +7,11 @@
*/
#include <EMStudio/AtomRenderPlugin.h>
#include <EMStudio/AnimViewportRenderer.h>
#include <Integration/Components/ActorComponent.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <QHBoxLayout>
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<uint32>(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<AtomRenderPlugin*>(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();
}
}
@@ -9,11 +9,18 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <MCore/Source/Command.h>
#include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/DockWidgetPlugin.h>
#include <EMStudio/AnimViewportWidget.h>
#include <QWidget>
#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;
};
@@ -429,6 +429,12 @@ namespace EMotionFX
}
ActorManager::ActorAssetData ActorManager::GetActorAsset(size_t nr) const
{
return m_actorAssets[nr];
}
const AZStd::vector<ActorInstance*>& ActorManager::GetActorInstanceArray() const
{
return m_actorInstances;
@@ -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.