Add ability to load actor from the ui
Signed-off-by: rhhong <rhhong@amazon.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user