diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h index 8030c3ae05..a4d76809ba 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h @@ -24,7 +24,7 @@ namespace AZ { public: //! Get a list of custom feature processors to register with thumbnail renderer - virtual const AZStd::vector& GetCustomFeatureProcessors() const = 0; + virtual void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; }; using ThumbnailFeatureProcessorProviderBus = AZ::EBus; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 896e88f4e2..8be947ae26 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -82,12 +82,11 @@ namespace AZ void EditorCommonFeaturesSystemComponent::Activate() { - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique (); m_skinnedMeshDebugDisplay = AZStd::make_unique(); AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect(); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } @@ -95,6 +94,7 @@ namespace AZ { AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); @@ -191,6 +191,14 @@ namespace AZ } } + void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); + }); + } + const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory( const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index 2560bf7e11..d26886c4ae 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -28,6 +28,7 @@ namespace AZ , public AzToolsFramework::EditorLevelNotificationBus::Handler , public AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , public AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler + , public AzFramework::AssetCatalogEventBus::Handler , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: @@ -56,6 +57,9 @@ namespace AZ void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override; + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + // AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides... const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp index 9c69fdd995..d12d9df892 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp @@ -6,15 +6,42 @@ * */ +#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 namespace AZ { @@ -23,23 +50,310 @@ namespace AZ namespace Thumbnails { CommonThumbnailRenderer::CommonThumbnailRenderer() - : m_data(new ThumbnailRendererData) { // CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType // since MaterialOrModelThumbnail dispatches event on materialAssetType address too AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); - SystemTickBus::Handler::BusConnect(); ThumbnailFeatureProcessorProviderBus::Handler::BusConnect(); + SystemTickBus::Handler::BusConnect(); - m_steps[Step::Initialize] = AZStd::make_shared(this); - m_steps[Step::FindThumbnailToRender] = AZStd::make_shared(this); - m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared(this); - m_steps[Step::Capture] = AZStd::make_shared(this); - m_steps[Step::ReleaseResources] = AZStd::make_shared(this); + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); - m_minimalFeatureProcessors = + // Create and register a scene with all required feature processors + AZStd::unordered_set featureProcessors; + ThumbnailFeatureProcessorProviderBus::Broadcast( + &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors, featureProcessors); + + RPI::SceneDescriptor sceneDesc; + sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); + m_scene = RPI::Scene::CreateScene(sceneDesc); + + // Bind m_frameworkScene to the entity context's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); + + Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); + AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); + + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_scene); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = m_pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + + // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue + // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(m_renderPipeline); + m_scene->Activate(); + RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + m_passHierarchy.push_back(m_pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // Connect camera to pipeline's default view after camera entity activated + Matrix4x4 viewToClipMatrix; + MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view = RPI::View::CreateView(Name("MainCamera"), RPI::View::UsageCamera); + m_view->SetViewToClipMatrix(viewToClipMatrix); + m_renderPipeline->SetDefaultView(m_view); + + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::CreateEntity, + "ThumbnailPreviewModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultModelAsset.Create(DefaultModelAssetId, true); + + m_steps[CommonThumbnailRenderer::Step::FindThumbnailToRender] = AZStd::make_shared(this); + m_steps[CommonThumbnailRenderer::Step::WaitForAssetsToLoad] = AZStd::make_shared(this); + m_steps[CommonThumbnailRenderer::Step::Capture] = AZStd::make_shared(this); + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + } + + CommonThumbnailRenderer::~CommonThumbnailRenderer() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); + ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); + + SetStep(CommonThumbnailRenderer::Step::None); + + if (m_modelEntity) { + AzFramework::EntityContextRequestBus::Event( + m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + + m_scene->Deactivate(); + m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); + RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_frameworkScene->UnsetSubsystem(m_scene); + m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + } + + void CommonThumbnailRenderer::SetStep(Step step) + { + auto stepItr = m_steps.find(m_currentStep); + if (stepItr != m_steps.end()) + { + stepItr->second->Stop(); + } + + m_currentStep = step; + + stepItr = m_steps.find(m_currentStep); + if (stepItr != m_steps.end()) + { + stepItr->second->Start(); + } + } + + CommonThumbnailRenderer::Step CommonThumbnailRenderer::GetStep() const + { + return m_currentStep; + } + + void CommonThumbnailRenderer::SelectThumbnail() + { + if (!m_thumbnailInfoQueue.empty()) + { + // pop the next thumbnailkey to be rendered from the queue + m_currentThubnailInfo = m_thumbnailInfoQueue.front(); + m_thumbnailInfoQueue.pop(); + + SetStep(CommonThumbnailRenderer::Step::WaitForAssetsToLoad); + } + } + + void CommonThumbnailRenderer::CancelThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + } + + void CommonThumbnailRenderer::CompleteThumbnail() + { + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + } + + void CommonThumbnailRenderer::LoadAssets() + { + // Determine if thumbnailkey contains a material asset or set a default material + const Data::AssetId materialAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::MaterialAsset::RTTI_Type()); + m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, true); + + // Determine if thumbnailkey contains a model asset or set a default model + const Data::AssetId modelAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::ModelAsset::RTTI_Type()); + m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, true); + + // Determine if thumbnailkey contains a lighting preset asset or set a default lighting preset + const Data::AssetId lightingPresetAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::AnyAsset::RTTI_Type()); + m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, true); + } + + void CommonThumbnailRenderer::UpdateLoadAssets() + { + if (m_materialAsset.IsReady() && m_modelAsset.IsReady() && m_lightingPresetAsset.IsReady()) + { + SetStep(CommonThumbnailRenderer::Step::Capture); + return; + } + + if (m_materialAsset.IsError() || m_modelAsset.IsError() || m_lightingPresetAsset.IsError()) + { + CancelLoadAssets(); + return; + } + } + + void CommonThumbnailRenderer::CancelLoadAssets() + { + AZ_Warning( + "CommonThumbnailRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "CommonThumbnailRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "CommonThumbnailRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", + m_lightingPresetAsset.ToString().c_str()); + CancelThumbnail(); + } + + void CommonThumbnailRenderer::UpdateScene() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void CommonThumbnailRenderer::UpdateModel() + { + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, + m_materialAsset.GetId()); + + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + } + + void CommonThumbnailRenderer::UpdateLighting() + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + + void CommonThumbnailRenderer::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + m_modelAsset->GetAabb().GetAsSphere(center, radius); + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + + RPI::AttachmentReadback::CallbackFunction CommonThumbnailRenderer::GetCaptureCallback() + { + return [this](const RPI::AttachmentReadback::ReadbackResult& result) + { + if (result.m_dataBuffer) + { + QImage image( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); + + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, + &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, QPixmap::fromImage(image)); + } + else + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, + &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + } + }; + } + + bool CommonThumbnailRenderer::StartCapture() + { + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(m_currentThubnailInfo.m_size, m_currentThubnailInfo.m_size); + } + + m_renderPipeline->AddToRenderTickOnce(); + + bool startedCapture = false; + Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), GetCaptureCallback(), RPI::PassAttachmentReadbackOption::Output); + return startedCapture; + } + + void CommonThumbnailRenderer::EndCapture() + { + m_renderPipeline->RemoveFromRenderTick(); + } + + bool CommonThumbnailRenderer::Installed() const + { + return true; + } + + void CommonThumbnailRenderer::OnSystemTick() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); + } + + void CommonThumbnailRenderer::GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const + { + featureProcessors.insert({ "AZ::Render::TransformServiceFeatureProcessor", "AZ::Render::MeshFeatureProcessor", "AZ::Render::SimplePointLightFeatureProcessor", @@ -56,64 +370,12 @@ namespace AZ "AZ::Render::DecalTextureArrayFeatureProcessor", "AZ::Render::ImageBasedLightFeatureProcessor", "AZ::Render::PostProcessFeatureProcessor", - "AZ::Render::SkyBoxFeatureProcessor" - }; - } - - CommonThumbnailRenderer::~CommonThumbnailRenderer() - { - if (m_currentStep != Step::None) - { - CommonThumbnailRenderer::SetStep(Step::ReleaseResources); - } - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); - SystemTickBus::Handler::BusDisconnect(); - ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); - } - - void CommonThumbnailRenderer::SetStep(Step step) - { - if (m_currentStep != Step::None) - { - m_steps[m_currentStep]->Stop(); - } - m_currentStep = step; - m_steps[m_currentStep]->Start(); - } - - Step CommonThumbnailRenderer::GetStep() const - { - return m_currentStep; - } - - bool CommonThumbnailRenderer::Installed() const - { - return true; - } - - void CommonThumbnailRenderer::OnSystemTick() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); - } - - const AZStd::vector& CommonThumbnailRenderer::GetCustomFeatureProcessors() const - { - return m_minimalFeatureProcessors; + "AZ::Render::SkyBoxFeatureProcessor" }); } - AZStd::shared_ptr CommonThumbnailRenderer::GetData() const - { - return m_data; - } - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_data->m_thumbnailSize = thumbnailSize; - m_data->m_thumbnailQueue.push(thumbnailKey); - if (m_currentStep == Step::None) - { - SetStep(Step::Initialize); - } + m_thumbnailInfoQueue.push({ thumbnailKey, thumbnailSize }); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h index 7c3b17e104..2b1ccbd4e6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h @@ -8,15 +8,24 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include -#include +namespace AzFramework +{ + class Scene; +} // Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class +// 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include @@ -32,10 +41,9 @@ namespace AZ //! Provides custom rendering of material and model thumbnails class CommonThumbnailRenderer - : public ThumbnailRendererContext - , private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , private SystemTickBus::Handler - , private ThumbnailFeatureProcessorProviderBus::Handler + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler + , public ThumbnailFeatureProcessorProviderBus::Handler { public: AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) @@ -43,10 +51,33 @@ namespace AZ CommonThumbnailRenderer(); ~CommonThumbnailRenderer(); - //! ThumbnailRendererContext overrides... - void SetStep(Step step) override; - Step GetStep() const override; - AZStd::shared_ptr GetData() const override; + enum class Step : AZ::s8 + { + None, + FindThumbnailToRender, + WaitForAssetsToLoad, + Capture + }; + + void SetStep(Step step); + Step GetStep() const; + + void SelectThumbnail(); + void CancelThumbnail(); + void CompleteThumbnail(); + + void LoadAssets(); + void UpdateLoadAssets(); + void CancelLoadAssets(); + + void UpdateScene(); + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + RPI::AttachmentReadback::CallbackFunction GetCaptureCallback(); + bool StartCapture(); + void EndCapture(); private: //! ThumbnailerRendererRequestsBus::Handler interface overrides... @@ -57,12 +88,53 @@ namespace AZ void OnSystemTick() override; //! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides... - const AZStd::vector& GetCustomFeatureProcessors() const override; + void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + AZStd::string m_sceneName = "Material Thumbnail Scene"; + AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; + AZStd::shared_ptr m_frameworkScene; + RPI::RenderPipelinePtr m_renderPipeline; + RPI::ViewPtr m_view; + AZStd::vector m_passHierarchy; + AZStd::unique_ptr m_entityContext; + + //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. + struct ThumbnailInfo + { + AzToolsFramework::Thumbnailer::SharedThumbnailKey m_key; + int m_size = 512; + }; + AZStd::queue m_thumbnailInfoQueue; + ThumbnailInfo m_currentThubnailInfo; AZStd::unordered_map> m_steps; - Step m_currentStep = Step::None; - AZStd::shared_ptr m_data; - AZStd::vector m_minimalFeatureProcessors; + Step m_currentStep = CommonThumbnailRenderer::Step::None; + + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + Data::Asset m_lightingPresetAsset; + + //! Model asset about to be rendered + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + Data::Asset m_modelAsset; + + //! Material asset about to be rendered + static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; + const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); + Data::Asset m_defaultMaterialAsset; + Data::Asset m_materialAsset; + + Entity* m_modelEntity = nullptr; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h deleted file mode 100644 index d3bb2be64a..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - struct ThumbnailRendererData; - - enum class Step - { - None, - Initialize, - FindThumbnailToRender, - WaitForAssetsToLoad, - Capture, - ReleaseResources - }; - - //! An interface for ThumbnailRendererSteps to communicate with thumbnail renderer - class ThumbnailRendererContext - { - public: - virtual void SetStep(Step step) = 0; - virtual Step GetStep() const = 0; - virtual AZStd::shared_ptr GetData() const = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h deleted file mode 100644 index c471cf90d7..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "Atom/RPI.Reflect/Model/ModelAsset.h" - -#include -#include -#include -#include -#include -#include - -namespace AzFramework -{ - class Scene; -} - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets - struct ThumbnailRendererData final - { - static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - - RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Material Thumbnail Scene"; - AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; - AZStd::shared_ptr m_frameworkScene; - RPI::RenderPipelinePtr m_renderPipeline; - AZStd::unique_ptr m_entityContext; - AZStd::vector m_passHierarchy; - - RPI::ViewPtr m_view = nullptr; - Entity* m_modelEntity = nullptr; - - int m_thumbnailSize = 512; - - //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_thumbnailQueue; - //! Current thumbnail key being rendered. - AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered; - - Data::Asset m_lightingPresetAsset; - - Data::Asset m_defaultModelAsset; - //! Model asset about to be rendered - Data::Asset m_modelAsset; - - Data::Asset m_defaultMaterialAsset; - //! Material asset about to be rendered - Data::Asset m_materialAsset; - - AZStd::unordered_set m_assetsToLoad; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp index f728d56bbc..0686ffb971 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp @@ -6,19 +6,8 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include namespace AZ { @@ -26,104 +15,42 @@ namespace AZ { namespace Thumbnails { - CaptureStep::CaptureStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + CaptureStep::CaptureStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } void CaptureStep::Start() { - if (!m_context->GetData()->m_materialAsset || - !m_context->GetData()->m_modelAsset) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - return; - } - Render::MaterialComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_context->GetData()->m_materialAsset.GetId()); - Render::MeshComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MeshComponentRequestBus::Events::SetModelAsset, - m_context->GetData()->m_modelAsset); - RepositionCamera(); - m_readyToCapture = true; m_ticksToCapture = 1; + m_renderer->UpdateScene(); TickBus::Handler::BusConnect(); } void CaptureStep::Stop() { - m_context->GetData()->m_renderPipeline->RemoveFromRenderTick(); + m_renderer->EndCapture(); TickBus::Handler::BusDisconnect(); Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); } - void CaptureStep::RepositionCamera() const - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - const Aabb& aabb = m_context->GetData()->m_modelAsset->GetAabb(); - Vector3 modelCenter; - float radius; - aabb.GetAsSphere(modelCenter, radius); - - float distance = StartingDistanceMultiplier * - GetMax(GetMax(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + - DepthNear; - const Quaternion cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), StartingRotationAngle); - Vector3 cameraPosition(modelCenter.GetX(), modelCenter.GetY() - distance, modelCenter.GetZ()); - cameraPosition = cameraRotation.TransformVector(cameraPosition); - auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_context->GetData()->m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); - } - void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - if (m_readyToCapture && m_ticksToCapture-- <= 0) + if (m_ticksToCapture-- <= 0) { - m_context->GetData()->m_renderPipeline->AddToRenderTickOnce(); - - RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result) - { - if (!result.m_dataBuffer) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - return; - } - uchar* data = result.m_dataBuffer.get()->data(); - QImage image( - data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); - QPixmap pixmap; - pixmap.convertFromImage(image); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - pixmap); - }; - - Render::FrameCaptureNotificationBus::Handler::BusConnect(); - bool startedCapture = false; - Render::FrameCaptureRequestBus::BroadcastResult( - startedCapture, - &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, - m_context->GetData()->m_passHierarchy, AZStd::string("Output"), readbackCallback, RPI::PassAttachmentReadbackOption::Output); // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (startedCapture) + if (m_renderer->StartCapture()) { - m_readyToCapture = false; + Render::FrameCaptureNotificationBus::Handler::BusConnect(); + TickBus::Handler::BusDisconnect(); } } } - void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + void CaptureStep::OnCaptureFinished( + [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) { - m_context->SetStep(Step::FindThumbnailToRender); + m_renderer->CompleteThumbnail(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h index e93828e3b8..46d642ce53 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h @@ -25,27 +25,18 @@ namespace AZ , private Render::FrameCaptureNotificationBus::Handler { public: - CaptureStep(ThumbnailRendererContext* context); + CaptureStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; private: - //! Places the camera so that the entire model is visible - void RepositionCamera() const; - //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; //! Render::FrameCaptureNotificationBus::Handler overrides... void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override; - - static constexpr float DepthNear = 0.01f; - static constexpr float StartingDistanceMultiplier = 1.75f; - static constexpr float StartingRotationAngle = Constants::QuarterPi / 2.0f; - //! This flag is needed to wait one frame after each frame capture to reset FrameCaptureSystemComponent - bool m_readyToCapture = true; //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials int m_ticksToCapture = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp index 826ec4ae0d..d9c978605a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp @@ -6,11 +6,7 @@ * */ -#include -#include -#include -#include -#include +#include #include namespace AZ @@ -19,8 +15,8 @@ namespace AZ { namespace Thumbnails { - FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + FindThumbnailToRenderStep::FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } @@ -36,43 +32,7 @@ namespace AZ void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - PickNextThumbnail(); - } - - void FindThumbnailToRenderStep::PickNextThumbnail() - { - if (!m_context->GetData()->m_thumbnailQueue.empty()) - { - // pop the next thumbnailkey to be rendered from the queue - m_context->GetData()->m_thumbnailKeyRendered = m_context->GetData()->m_thumbnailQueue.front(); - m_context->GetData()->m_thumbnailQueue.pop(); - - // Find whether thumbnailkey contains a material asset or set a default material - m_context->GetData()->m_materialAsset = m_context->GetData()->m_defaultMaterialAsset; - Data::AssetId materialAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::MaterialAsset::RTTI_Type()); - if (materialAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(materialAssetId).second) - { - m_context->GetData()->m_materialAsset.Create(materialAssetId); - m_context->GetData()->m_materialAsset.QueueLoad(); - } - } - - // Find whether thumbnailkey contains a model asset or set a default model - m_context->GetData()->m_modelAsset = m_context->GetData()->m_defaultModelAsset; - Data::AssetId modelAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::ModelAsset::RTTI_Type()); - if (modelAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(modelAssetId).second) - { - m_context->GetData()->m_modelAsset.Create(modelAssetId); - m_context->GetData()->m_modelAsset.QueueLoad(); - } - } - - m_context->SetStep(Step::WaitForAssetsToLoad); - } + m_renderer->SelectThumbnail(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h index e63bc5dce5..6ba9b974a1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h @@ -22,7 +22,7 @@ namespace AZ , private TickBus::Handler { public: - FindThumbnailToRenderStep(ThumbnailRendererContext* context); + FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; @@ -31,8 +31,6 @@ namespace AZ //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - void PickNextThumbnail(); }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp deleted file mode 100644 index 6f74627bee..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - InitializeStep::InitializeStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void InitializeStep::Start() - { - auto data = m_context->GetData(); - - data->m_entityContext = AZStd::make_unique(); - data->m_entityContext->InitContext(); - - // Create and register a scene with all required feature processors - RPI::SceneDescriptor sceneDesc; - - AZ::EBusAggregateResults> results; - ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors); - - AZStd::set featureProcessorNames; - for (auto& resultCollection : results.values) - { - for (auto& featureProcessorName : resultCollection) - { - if (featureProcessorNames.emplace(featureProcessorName).second) - { - sceneDesc.m_featureProcessorNames.push_back(featureProcessorName); - } - } - } - - data->m_scene = RPI::Scene::CreateScene(sceneDesc); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto* sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); - Outcome, AZStd::string> createSceneOutcome = - sceneSystem->CreateScene(data->m_sceneName); - AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); // This should never happen unless scene creation has changed. - data->m_frameworkScene = createSceneOutcome.TakeValue(); - data->m_frameworkScene->SetSubsystem(data->m_scene); - - data->m_frameworkScene->SetSubsystem(data->m_entityContext.get()); - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = data->m_pipelineName; - pipelineDesc.m_rootPassTemplate = "ThumbnailPipelineRenderToTexture"; - // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue - // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost - pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; - data->m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - data->m_scene->AddRenderPipeline(data->m_renderPipeline); - data->m_scene->Activate(); - RPI::RPISystemInterface::Get()->RegisterScene(data->m_scene); - data->m_passHierarchy.push_back(data->m_pipelineName); - data->m_passHierarchy.push_back("CopyToSwapChain"); - - // Connect camera to pipeline's default view after camera entity activated - Name viewName = Name("MainCamera"); - data->m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera); - - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, - Constants::QuarterPi, - AspectRatio, - NearDist, - FarDist, true); - data->m_view->SetViewToClipMatrix(viewToClipMatrix); - - data->m_renderPipeline->SetDefaultView(data->m_view); - - // Create lighting preset - data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(ThumbnailRendererData::LightingPresetPath); - if (data->m_lightingPresetAsset.IsReady()) - { - auto preset = data->m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = Constants::HalfPi; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, - skyboxFeatureProcessor, - exposureControlSettingInterface, - directionalLightFeatureProcessor, - cameraConfig, - lightHandles); - } - } - - // Create preview model - AzFramework::EntityContextRequestBus::EventResult(data->m_modelEntity, data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); - data->m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - data->m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - data->m_modelEntity->CreateComponent(azrtti_typeid()); - data->m_modelEntity->Init(); - data->m_modelEntity->Activate(); - - // preload default model - Data::AssetId defaultModelAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultModelAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultModelPath, - RPI::ModelAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultModelAssetId.IsValid(), "Default model asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultModelPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultModelAssetId).second) - { - data->m_defaultModelAsset.Create(defaultModelAssetId); - data->m_defaultModelAsset.QueueLoad(); - } - - // preload default material - Data::AssetId defaultMaterialAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultMaterialAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultMaterialPath, - RPI::MaterialAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultMaterialAssetId.IsValid(), "Default material asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultMaterialPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultMaterialAssetId).second) - { - data->m_defaultMaterialAsset.Create(defaultMaterialAssetId); - data->m_defaultMaterialAsset.QueueLoad(); - } - - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h deleted file mode 100644 index cdac492e80..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! InitializeStep sets up RPI system and scene and prepares it for rendering thumbnail entities - //! This step is only called once when CommonThumbnailRenderer begins rendering its first thumbnail - class InitializeStep - : public ThumbnailRendererStep - { - public: - InitializeStep(ThumbnailRendererContext* context); - - void Start() override; - - private: - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.1f; - static constexpr float FarDist = 100.0f; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp deleted file mode 100644 index a14f48e408..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - ReleaseResourcesStep::ReleaseResourcesStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void ReleaseResourcesStep::Start() - { - auto data = m_context->GetData(); - - data->m_defaultMaterialAsset.Release(); - data->m_defaultModelAsset.Release(); - data->m_materialAsset.Release(); - data->m_modelAsset.Release(); - data->m_lightingPresetAsset.Release(); - - if (data->m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity); - data->m_modelEntity = nullptr; - } - - data->m_scene->Deactivate(); - data->m_scene->RemoveRenderPipeline(data->m_renderPipeline->GetId()); - RPI::RPISystemInterface::Get()->UnregisterScene(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_entityContext.get()); - data->m_scene = nullptr; - data->m_frameworkScene = nullptr; - data->m_renderPipeline = nullptr; - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h deleted file mode 100644 index 4858b90b96..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ReleaseResourcesStep - : public ThumbnailRendererStep - { - public: - ReleaseResourcesStep(ThumbnailRendererContext* context); - - void Start() override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h index cc10f91525..0a629e7e25 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h @@ -14,13 +14,13 @@ namespace AZ { namespace Thumbnails { - class ThumbnailRendererContext; + class CommonThumbnailRenderer; //! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces class ThumbnailRendererStep { public: - explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {} + explicit ThumbnailRendererStep(CommonThumbnailRenderer* renderer) : m_renderer(renderer) {} virtual ~ThumbnailRendererStep() = default; //! Start is called when step begins execution @@ -29,7 +29,7 @@ namespace AZ virtual void Stop() {} protected: - ThumbnailRendererContext* m_context; + CommonThumbnailRenderer* m_renderer; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp index 4f32bc4b68..53a5b596d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp @@ -7,9 +7,7 @@ */ #include "Thumbnails/ThumbnailerBus.h" - -#include -#include +#include #include #include @@ -19,81 +17,33 @@ namespace AZ { namespace Thumbnails { - WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } void WaitForAssetsToLoadStep::Start() { - LoadNextAsset(); + m_renderer->LoadAssets(); + m_timeRemainingS = TimeOutS; + TickBus::Handler::BusConnect(); } void WaitForAssetsToLoadStep::Stop() { - Data::AssetBus::Handler::BusDisconnect(); TickBus::Handler::BusDisconnect(); - m_context->GetData()->m_assetsToLoad.clear(); - } - - void WaitForAssetsToLoadStep::LoadNextAsset() - { - if (m_context->GetData()->m_assetsToLoad.empty()) - { - // When all assets are loaded, render the thumbnail itself - m_context->SetStep(Step::Capture); - } - else - { - // Pick the the next asset and wait until its ready - const auto assetIdIt = m_context->GetData()->m_assetsToLoad.begin(); - m_context->GetData()->m_assetsToLoad.erase(assetIdIt); - m_assetId = *assetIdIt; - Data::AssetBus::Handler::BusConnect(m_assetId); - // If asset is already loaded, then AssetEvents will call OnAssetReady instantly and we don't need to wait this time - if (Data::AssetBus::Handler::BusIsConnected()) - { - TickBus::Handler::BusConnect(); - m_timeRemainingS = TimeOutS; - } - } - } - - void WaitForAssetsToLoadStep::OnAssetReady([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnAssetCanceled([[maybe_unused]] Data::AssetId assetId) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); } void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { m_timeRemainingS -= deltaTime; - if (m_timeRemainingS < 0) + if (m_timeRemainingS > 0.0f) { - auto assetIdStr = m_assetId.ToString(); - AZ_Warning("CommonThumbnailRenderer", false, "Timed out waiting for asset %s to load.", assetIdStr.c_str()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); + m_renderer->UpdateLoadAssets(); + } + else + { + m_renderer->CancelLoadAssets(); } } } // namespace Thumbnails diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h index 921d1511ca..0202ef1045 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h @@ -8,7 +8,6 @@ #pragma once -#include #include namespace AZ @@ -20,29 +19,20 @@ namespace AZ //! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded class WaitForAssetsToLoadStep : public ThumbnailRendererStep - , private Data::AssetBus::Handler , private TickBus::Handler { public: - WaitForAssetsToLoadStep(ThumbnailRendererContext* context); + WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; private: - void LoadNextAsset(); - - // AZ::Data::AssetBus::Handler - void OnAssetReady(Data::Asset asset) override; - void OnAssetError(Data::Asset asset) override; - void OnAssetCanceled(Data::AssetId assetId) override; - //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - static constexpr float TimeOutS = 3.0f; - Data::AssetId m_assetId; - float m_timeRemainingS = 0; + static constexpr float TimeOutS = 5.0f; + float m_timeRemainingS = TimeOutS; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 174eb30b31..ffc3f257b0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -104,19 +104,13 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewerFactory.h Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp Source/Thumbnails/Rendering/CommonThumbnailRenderer.h - Source/Thumbnails/Rendering/ThumbnailRendererData.h - Source/Thumbnails/Rendering/ThumbnailRendererContext.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp