From c90e1da475db44d2cd9be82a5cef7d832dabdc6e Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 7 Oct 2021 21:05:10 -0500 Subject: [PATCH] =?UTF-8?q?=E2=80=A2=20Moved=20everything=20related=20to?= =?UTF-8?q?=20the=20subject=20being=20captured=20by=20the=20preview=20rend?= =?UTF-8?q?erer=20into=20a=20preview=20render=20content=20class=20which=20?= =?UTF-8?q?will=20become=20an=20interface=20in=20the=20next=20iteration=20?= =?UTF-8?q?=E2=80=A2=20Extracted=20all=20of=20the=20thumbnail=20specific?= =?UTF-8?q?=20code=20from=20the=20common=20preview=20render=20class=20as?= =?UTF-8?q?=20a=20step=20towards=20separating=20it=20from=20the=20thumbnai?= =?UTF-8?q?l=20system=20completely=20=E2=80=A2=20Created=20a=20capture=20r?= =?UTF-8?q?equest=20structure=20that=20stores=20all=20of=20the=20info=20re?= =?UTF-8?q?lated=20to=20the=20content=20being=20captured=20and=20callbacks?= =?UTF-8?q?=20for=20success=20and=20failure=20=E2=80=A2=20Request=20to=20c?= =?UTF-8?q?apture=20any=20kind=20of=20content=20can=20be=20added=20to=20th?= =?UTF-8?q?e=20renderer=20using=20this=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../PreviewerFeatureProcessorProviderBus.h | 4 +- .../Rendering/CommonPreviewContent.cpp | 170 ++++++++++++++ .../Rendering/CommonPreviewContent.h | 79 +++++++ .../Rendering/CommonPreviewRenderer.cpp | 221 +++++------------- .../Rendering/CommonPreviewRenderer.h | 67 ++---- .../CommonPreviewRendererCaptureState.cpp | 2 +- .../CommonPreviewRendererIdleState.cpp | 2 +- ...egration_commonfeatures_editor_files.cmake | 2 + 8 files changed, 340 insertions(+), 207 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h index ef0e586348..bae49db89d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h @@ -16,14 +16,14 @@ namespace AZ { namespace Thumbnails { - //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation //! Duplicates will be ignored //! You can check minimal feature processors that are already registered in CommonPreviewRenderer.cpp class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits { public: - //! Get a list of custom feature processors to register with thumbnail renderer + //! Get a list of custom feature processors to register with preview image renderer virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp new file mode 100644 index 0000000000..12caac1e90 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp @@ -0,0 +1,170 @@ +/* + * 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 + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + CommonPreviewContent::CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId) + : m_scene(scene) + , m_view(view) + , m_entityContextId(entityContextId) + { + // Connect camera to pipeline's default view after camera entity activated + Matrix4x4 viewToClipMatrix; + MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view->SetViewToClipMatrix(viewToClipMatrix); + + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContextId, &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_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + + m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, false); + m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, false); + m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); + } + + CommonPreviewContent::~CommonPreviewContent() + { + if (m_modelEntity) + { + AzFramework::EntityContextRequestBus::Event( + m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + } + + void CommonPreviewContent::Load() + { + m_modelAsset.QueueLoad(); + m_materialAsset.QueueLoad(); + m_lightingPresetAsset.QueueLoad(); + } + + bool CommonPreviewContent::IsReady() const + { + return m_modelAsset.IsReady() && m_materialAsset.IsReady() && m_lightingPresetAsset.IsReady(); + } + + bool CommonPreviewContent::IsError() const + { + return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); + } + + void CommonPreviewContent::ReportErrors() + { + AZ_Warning( + "CommonPreviewContent", m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", + m_lightingPresetAsset.ToString().c_str()); + } + + void CommonPreviewContent::UpdateScene() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void CommonPreviewContent::UpdateModel() + { + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, + m_materialAsset.GetId()); + } + + void CommonPreviewContent::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 CommonPreviewContent::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)); + } + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h new file mode 100644 index 0000000000..6c8f0c5565 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h @@ -0,0 +1,79 @@ +/* + * 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 +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! Provides custom rendering of material and model thumbnails + class CommonPreviewContent + { + public: + AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); + + CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId); + ~CommonPreviewContent(); + + void Load(); + bool IsReady() const; + bool IsError() const; + void ReportErrors(); + void UpdateScene(); + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + 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; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + 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; + }; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp index b24de64b42..37a9bab378 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp @@ -6,33 +6,17 @@ * */ -#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 @@ -51,8 +35,7 @@ namespace AZ { CommonPreviewRenderer::CommonPreviewRenderer() { - // CommonPreviewRenderer supports both models and materials, but we connect on materialAssetType - // since MaterialOrModelThumbnail dispatches event on materialAssetType address too + // CommonPreviewRenderer supports both models and materials AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); @@ -72,7 +55,7 @@ namespace AZ // 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."); + AZ_Assert(sceneSystem, "Failed to get scene system implementation."); Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); @@ -104,23 +87,9 @@ namespace AZ 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[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); - m_steps[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); - m_steps[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); SetState(CommonPreviewRenderer::State::IdleState); } @@ -131,13 +100,8 @@ namespace AZ PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); SetState(CommonPreviewRenderer::State::None); - - if (m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event( - m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); - m_modelEntity = nullptr; - } + m_currentCaptureRequest = {}; + m_captureRequestQueue = {}; m_scene->Deactivate(); m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); @@ -146,18 +110,23 @@ namespace AZ m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } + void CommonPreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + void CommonPreviewRenderer::SetState(State state) { - auto stepItr = m_steps.find(m_currentState); - if (stepItr != m_steps.end()) + auto stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) { stepItr->second->Stop(); } m_currentState = state; - stepItr = m_steps.find(m_currentState); - if (stepItr != m_steps.end()) + stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) { stepItr->second->Start(); } @@ -168,54 +137,43 @@ namespace AZ return m_currentState; } - void CommonPreviewRenderer::SelectThumbnail() + void CommonPreviewRenderer::SelectCaptureRequest() { - if (!m_thumbnailInfoQueue.empty()) + if (!m_captureRequestQueue.empty()) { - // pop the next thumbnailkey to be rendered from the queue - m_currentThubnailInfo = m_thumbnailInfoQueue.front(); - m_thumbnailInfoQueue.pop(); + // pop the next request to be rendered from the queue + m_currentCaptureRequest = m_captureRequestQueue.front(); + m_captureRequestQueue.pop(); SetState(CommonPreviewRenderer::State::LoadState); } } - void CommonPreviewRenderer::CancelThumbnail() + void CommonPreviewRenderer::CancelCaptureRequest() { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_currentThubnailInfo.m_key, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + m_currentCaptureRequest.m_captureFailedCallback(); SetState(CommonPreviewRenderer::State::IdleState); } - void CommonPreviewRenderer::CompleteThumbnail() + void CommonPreviewRenderer::CompleteCaptureRequest() { SetState(CommonPreviewRenderer::State::IdleState); } void CommonPreviewRenderer::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); + m_currentCaptureRequest.m_content->Load(); } void CommonPreviewRenderer::UpdateLoadAssets() { - if (m_materialAsset.IsReady() && m_modelAsset.IsReady() && m_lightingPresetAsset.IsReady()) + if (m_currentCaptureRequest.m_content->IsReady()) { SetState(CommonPreviewRenderer::State::CaptureState); return; } - if (m_materialAsset.IsError() || m_modelAsset.IsError() || m_lightingPresetAsset.IsError()) + if (m_currentCaptureRequest.m_content->IsError()) { CancelLoadAssets(); return; @@ -224,107 +182,35 @@ namespace AZ void CommonPreviewRenderer::CancelLoadAssets() { - AZ_Warning( - "CommonPreviewRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", - m_materialAsset.ToString().c_str()); - AZ_Warning( - "CommonPreviewRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", - m_modelAsset.ToString().c_str()); - AZ_Warning( - "CommonPreviewRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", - m_lightingPresetAsset.ToString().c_str()); - CancelThumbnail(); + m_currentCaptureRequest.m_content->ReportErrors(); + CancelCaptureRequest(); } void CommonPreviewRenderer::UpdateScene() { - UpdateModel(); - UpdateLighting(); - UpdateCamera(); - } - - void CommonPreviewRenderer::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 CommonPreviewRenderer::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 CommonPreviewRenderer::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)); + m_currentCaptureRequest.m_content->UpdateScene(); } - RPI::AttachmentReadback::CallbackFunction CommonPreviewRenderer::GetCaptureCallback() + bool CommonPreviewRenderer::StartCapture() { - return [this](const RPI::AttachmentReadback::ReadbackResult& result) + auto captureCallback = + [currentCaptureRequest = m_currentCaptureRequest](const RPI::AttachmentReadback::ReadbackResult& result) { if (result.m_dataBuffer) { - QImage image( + currentCaptureRequest.m_captureCompleteCallback(QImage( 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)); + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888)); } else { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_currentThubnailInfo.m_key, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + currentCaptureRequest.m_captureFailedCallback(); } }; - } - bool CommonPreviewRenderer::StartCapture() - { if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) { - renderToTexturePass->ResizeOutput(m_currentThubnailInfo.m_size, m_currentThubnailInfo.m_size); + renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); } m_renderPipeline->AddToRenderTickOnce(); @@ -332,7 +218,7 @@ namespace AZ bool startedCapture = false; Render::FrameCaptureRequestBus::BroadcastResult( startedCapture, &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, - AZStd::string("Output"), GetCaptureCallback(), RPI::PassAttachmentReadbackOption::Output); + AZStd::string("Output"), captureCallback, RPI::PassAttachmentReadbackOption::Output); return startedCapture; } @@ -341,11 +227,6 @@ namespace AZ m_renderPipeline->RemoveFromRenderTick(); } - bool CommonPreviewRenderer::Installed() const - { - return true; - } - void CommonPreviewRenderer::OnSystemTick() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); @@ -372,10 +253,32 @@ namespace AZ "AZ::Render::PostProcessFeatureProcessor", "AZ::Render::SkyBoxFeatureProcessor" }); } - + void CommonPreviewRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_thumbnailInfoQueue.push({ thumbnailKey, thumbnailSize }); + AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + m_scene, m_view, m_entityContext->GetContextId(), + GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type())), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QImage& image) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, + QPixmap::fromImage(image)); + } }); + } + + bool CommonPreviewRenderer::Installed() const + { + return true; } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h index 259063cfdf..124a6987cc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h @@ -10,13 +10,11 @@ #include #include -#include -#include -#include #include #include #include #include +#include #include namespace AzFramework @@ -46,11 +44,21 @@ namespace AZ , public PreviewerFeatureProcessorProviderBus::Handler { public: - AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0) + AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0); CommonPreviewRenderer(); ~CommonPreviewRenderer(); + struct CaptureRequest + { + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; + + void AddCaptureRequest(const CaptureRequest& captureRequest); + enum class State : AZ::s8 { None, @@ -62,39 +70,34 @@ namespace AZ void SetState(State state); State GetState() const; - void SelectThumbnail(); - void CancelThumbnail(); - void CompleteThumbnail(); + void SelectCaptureRequest(); + void CancelCaptureRequest(); + void CompleteCaptureRequest(); 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... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; //! Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() 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"; @@ -105,36 +108,12 @@ namespace AZ 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; + //! Incoming requests are appended to this queue and processed one at a time in OnTick function. + AZStd::queue m_captureRequestQueue; + CaptureRequest m_currentCaptureRequest; - AZStd::unordered_map> m_steps; + AZStd::unordered_map> m_states; State m_currentState = CommonPreviewRenderer::State::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/CommonPreviewRendererCaptureState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp index e77b9709ac..fc74e9f43b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp @@ -50,7 +50,7 @@ namespace AZ void CommonPreviewRendererCaptureState::OnCaptureFinished( [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) { - m_renderer->CompleteThumbnail(); + m_renderer->CompleteCaptureRequest(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp index b272faef30..12a38fc93f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp @@ -32,7 +32,7 @@ namespace AZ void CommonPreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - m_renderer->SelectThumbnail(); + m_renderer->SelectCaptureRequest(); } } // 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 e96f199f5e..f135bc1132 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -102,6 +102,8 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewer.ui Source/Thumbnails/Preview/CommonPreviewerFactory.cpp Source/Thumbnails/Preview/CommonPreviewerFactory.h + Source/Thumbnails/Rendering/CommonPreviewContent.cpp + Source/Thumbnails/Rendering/CommonPreviewContent.h Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp Source/Thumbnails/Rendering/CommonPreviewRenderer.h Source/Thumbnails/Rendering/CommonPreviewRendererState.h