Merge branch 'development' into animation/rhhong/RenderUtilOptions

Signed-off-by: rhhong <rhhong@amazon.com>
This commit is contained in:
rhhong
2021-10-25 01:40:58 -07:00
1689 changed files with 43726 additions and 664968 deletions
@@ -1,5 +1,5 @@
{
"Source" : "LyShineUI",
"Source" : "LyShineUI.azsl",
"DepthStencilState" : {
"Depth" : {
@@ -1,5 +1,5 @@
{
"Source" : "SimpleTextured",
"Source" : "SimpleTextured.azsl",
"DepthStencilState" : {
"Depth" : {
@@ -1353,8 +1353,9 @@ namespace AZ::AtomBridge
// if 2d draw need to project pos to screen first
AzFramework::TextDrawParameters params;
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
params.m_position = AZ::Vector3(x, y, 1.0f);
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
params.m_color = m_rendState.m_color;
params.m_scale = AZ::Vector2(size);
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment
@@ -84,10 +84,6 @@ namespace AtomImGuiTools
{
m_imguiGpuProfiler.Draw(m_showGpuProfiler, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
}
if (m_showCpuProfiler)
{
m_imguiCpuProfiler.Draw(m_showCpuProfiler);
}
if (m_showTransientAttachmentProfiler)
{
auto* transientStats = AZ::RHI::RHISystemInterface::Get()->GetTransientAttachmentStatistics();
@@ -108,12 +104,6 @@ namespace AtomImGuiTools
{
ImGui::MenuItem("Pass Viewer", "", &m_showPassTree);
ImGui::MenuItem("Gpu Profiler", "", &m_showGpuProfiler);
if (ImGui::MenuItem("Cpu Profiler", "", &m_showCpuProfiler))
{
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
AZ::RHI::FrameSchedulerStatisticsFlags::GatherCpuTimingStatistics, m_showCpuProfiler);
AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(m_showCpuProfiler);
}
if (ImGui::MenuItem("Transient Attachment Profiler", "", &m_showTransientAttachmentProfiler))
{
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
@@ -15,7 +15,6 @@
#if defined(IMGUI_ENABLED)
#include <ImGuiBus.h>
#include <imgui/imgui.h>
#include <Atom/Utils/ImGuiCpuProfiler.h>
#include <Atom/Utils/ImGuiGpuProfiler.h>
#include <Atom/Utils/ImGuiPassTree.h>
#include <Atom/Utils/ImGuiShaderMetrics.h>
@@ -63,9 +62,6 @@ namespace AtomImGuiTools
AZ::Render::ImGuiGpuProfiler m_imguiGpuProfiler;
bool m_showGpuProfiler = false;
AZ::Render::ImGuiCpuProfiler m_imguiCpuProfiler;
bool m_showCpuProfiler = false;
AZ::Render::ImGuiTransientAttachmentProfiler m_imguiTransientAttachmentProfiler;
bool m_showTransientAttachmentProfiler = false;
@@ -1,5 +1,5 @@
{
"Source" : "TexturedIcon",
"Source" : "TexturedIcon.azsl",
"DepthStencilState" : {
"Depth" : {
@@ -120,13 +120,6 @@ namespace AZ
//! Sets the filter method of shadows.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Gets the width of softening boundary between shadowed area and lit area in degrees.
virtual float GetSofteningBoundaryWidthAngle() const = 0;
//! Sets the width of softening boundary between shadowed area and lit area in degrees.
//! 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0;
//! Gets the sample count for filtering of the shadow boundary.
virtual uint32_t GetFilteringSampleCount() const = 0;
@@ -59,7 +59,6 @@ namespace AZ
float m_bias = 0.1f;
ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
float m_boundaryWidthInDegrees = 0.25f;
uint16_t m_filteringSampleCount = 12;
float m_esmExponent = 87.0f;
@@ -153,15 +153,6 @@ namespace AZ
//! @param method filter method.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! This gets the width of boundary between shadowed area and lit area.
//! @return Boundary width. The shadow is gradually changed the degree of shadowed.
virtual float GetSofteningBoundaryWidth() const = 0;
//! This specifies the width of boundary between shadowed area and lit area.
//! @param width Boundary width. The shadow is gradually changed the degree of shadowed.
//! If width == 0, softening edge is disabled. Units are in meters.
virtual void SetSofteningBoundaryWidth(float width) = 0;
//! This gets the sample count for filtering of the shadow boundary.
//! @return Sample Count for filtering (up to 64)
virtual uint32_t GetFilteringSampleCount() const = 0;
@@ -177,6 +168,22 @@ namespace AZ
//! Sets whether the directional shadowmap should use receiver plane bias.
//! @param enable flag specifying whether to enable the receiver plane bias feature
virtual void SetShadowReceiverPlaneBiasEnabled(bool enable) = 0;
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
//! @return Returns the amount of bias to apply.
virtual float GetShadowBias() const = 0;
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
//! @param Sets the amount of bias to apply.
virtual void SetShadowBias(float bias) = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @return Returns the amount of bias to apply.
virtual float GetNormalShadowBias() const = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
};
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
@@ -101,9 +101,8 @@ namespace AZ
//! Method of shadow's filtering.
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
//! Width of the boundary between shadowed area and lit one.
//! If this is 0, edge softening is disabled. Units are in meters.
float m_boundaryWidth = 0.03f; // 3cm
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
float m_normalShadowBias = 0.0f;
//! Sample Count for filtering (from 4 to 64)
//! It is used only when the pixel is predicted as on the boundary.
@@ -113,6 +112,9 @@ namespace AZ
//! This uses partial derivatives to reduce shadow acne when using large pcf kernels.
bool m_receiverPlaneBiasEnabled = true;
//! Reduces shadow acne by applying a small amount of offset along shadow-space z.
float m_shadowBias = 0.0f;
bool IsSplitManual() const;
bool IsSplitAutomatic() const;
bool IsCascadeCorrectionDisabled() const;
@@ -0,0 +1,34 @@
/*
* 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/Feature/Material/MaterialAssignmentId.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
class QPixmap;
namespace AZ
{
namespace Render
{
//! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like
//! being informed that material preview images are available
class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Notify that a material preview image is ready
virtual void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0;
};
using EditorMaterialSystemComponentNotificationBus = AZ::EBus<EditorMaterialSystemComponentNotifications>;
} // namespace Render
} // namespace AZ
@@ -5,20 +5,22 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/Feature/Material/MaterialAssignmentId.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
#include <QPixmap>
namespace AZ
{
namespace Render
{
//! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor
class EditorMaterialSystemComponentRequests
: public AZ::EBusTraits
//! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing
//! different operations like opening the material editor, the material instance inspector, and managing material preview images
class EditorMaterialSystemComponentRequests : public AZ::EBusTraits
{
public:
// Only a single handler is allowed
@@ -31,6 +33,14 @@ namespace AZ
//! Open material instance editor
virtual void OpenMaterialInspector(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
//! Generate a material preview image
virtual void RenderMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
//! Get recently rendered material preview image
virtual QPixmap GetRenderedMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0;
};
using EditorMaterialSystemComponentRequestBus = AZ::EBus<EditorMaterialSystemComponentRequests>;
} // namespace Render
@@ -43,6 +43,9 @@ namespace AZ
virtual void ClearInvalidMaterialOverrides() = 0;
//! Repair materials that reference missing assets by assigning the default asset
virtual void RepairInvalidMaterialOverrides() = 0;
//! Repair material property overrides that reference missing properties by auto-renaming them where possible
//! @return the number of properties that were updated
virtual uint32_t ApplyAutomaticPropertyUpdates() = 0;
//! Set default material override
virtual void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) = 0;
//! Get default material override
@@ -1,33 +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 <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
//! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation
//! Duplicates will be ignored
//! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp
class ThumbnailFeatureProcessorProviderRequests
: public AZ::EBusTraits
{
public:
//! Get a list of custom feature processors to register with thumbnail renderer
virtual const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const = 0;
};
using ThumbnailFeatureProcessorProviderBus = AZ::EBus<ThumbnailFeatureProcessorProviderRequests>;
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -36,7 +36,6 @@ namespace AZ
->Field("Shadow Bias", &AreaLightComponentConfig::m_bias)
->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize)
->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod)
->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees)
->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount)
->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent)
;
@@ -74,8 +74,6 @@ namespace AZ::Render
->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize)
->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &AreaLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::GetSofteningBoundaryWidthAngle)
->Event("SetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::SetSofteningBoundaryWidthAngle)
->Event("GetFilteringSampleCount", &AreaLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent)
@@ -95,7 +93,6 @@ namespace AZ::Render
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent");
;
@@ -307,7 +304,6 @@ namespace AZ::Render
m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias);
m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize);
m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees);
m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent);
}
@@ -506,20 +502,6 @@ namespace AZ::Render
}
}
float AreaLightComponentController::GetSofteningBoundaryWidthAngle() const
{
return m_configuration.m_boundaryWidthInDegrees;
}
void AreaLightComponentController::SetSofteningBoundaryWidthAngle(float width)
{
m_configuration.m_boundaryWidthInDegrees = width;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(width);
}
}
uint32_t AreaLightComponentController::GetFilteringSampleCount() const
{
return m_configuration.m_filteringSampleCount;
@@ -82,8 +82,6 @@ namespace AZ
void SetShadowmapMaxSize(ShadowmapSize size) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidthAngle() const override;
void SetSofteningBoundaryWidthAngle(float width) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
float GetEsmExponent() const override;
@@ -37,9 +37,10 @@ namespace AZ
->Field("IsCascadeCorrectionEnabled", &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled)
->Field("IsDebugColoringEnabled", &DirectionalLightComponentConfig::m_isDebugColoringEnabled)
->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod)
->Field("SofteningBoundaryWidth", &DirectionalLightComponentConfig::m_boundaryWidth)
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled);
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled)
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias)
->Field("Normal Shadow Bias", &DirectionalLightComponentConfig::m_normalShadowBias);
}
}
@@ -80,12 +80,14 @@ namespace AZ
->Event("SetDebugColoringEnabled", &DirectionalLightRequestBus::Events::SetDebugColoringEnabled)
->Event("GetShadowFilterMethod", &DirectionalLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &DirectionalLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::GetSofteningBoundaryWidth)
->Event("SetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::SetSofteningBoundaryWidth)
->Event("GetFilteringSampleCount", &DirectionalLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::GetShadowReceiverPlaneBiasEnabled)
->Event("SetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::SetShadowReceiverPlaneBiasEnabled)
->Event("GetShadowBias", &DirectionalLightRequestBus::Events::GetShadowBias)
->Event("SetShadowBias", &DirectionalLightRequestBus::Events::SetShadowBias)
->Event("GetNormalShadowBias", &DirectionalLightRequestBus::Events::GetNormalShadowBias)
->Event("SetNormalShadowBias", &DirectionalLightRequestBus::Events::SetNormalShadowBias)
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
@@ -99,9 +101,10 @@ namespace AZ
->VirtualProperty("ViewFrustumCorrectionEnabled", "GetViewFrustumCorrectionEnabled", "SetViewFrustumCorrectionEnabled")
->VirtualProperty("DebugColoringEnabled", "GetDebugColoringEnabled", "SetDebugColoringEnabled")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidth", "GetSofteningBoundaryWidth", "SetSofteningBoundaryWidth")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled");
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled")
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias");
;
}
}
@@ -404,26 +407,39 @@ namespace AZ
}
}
float DirectionalLightComponentController::GetSofteningBoundaryWidth() const
{
return m_configuration.m_boundaryWidth;
}
void DirectionalLightComponentController::SetSofteningBoundaryWidth(float width)
{
width = GetMin(Shadow::MaxSofteningBoundaryWidth, GetMax(0.f, width));
m_configuration.m_boundaryWidth = width;
if (m_featureProcessor)
{
m_featureProcessor->SetShadowBoundaryWidth(m_lightHandle, width);
}
}
uint32_t DirectionalLightComponentController::GetFilteringSampleCount() const
{
return aznumeric_cast<uint32_t>(m_configuration.m_filteringSampleCount);
}
void DirectionalLightComponentController::SetShadowBias(float bias)
{
m_configuration.m_shadowBias = bias;
if (m_featureProcessor)
{
m_featureProcessor->SetShadowBias(m_lightHandle, bias);
}
}
float DirectionalLightComponentController::GetShadowBias() const
{
return m_configuration.m_shadowBias;
}
void DirectionalLightComponentController::SetNormalShadowBias(float bias)
{
m_configuration.m_normalShadowBias = bias;
if (m_featureProcessor)
{
m_featureProcessor->SetNormalShadowBias(m_lightHandle, bias);
}
}
float DirectionalLightComponentController::GetNormalShadowBias() const
{
return m_configuration.m_normalShadowBias;
}
void DirectionalLightComponentController::SetFilteringSampleCount(uint32_t count)
{
const uint16_t count16 = GetMin(Shadow::MaxPcfSamplingCount, aznumeric_cast<uint16_t>(count));
@@ -517,7 +533,8 @@ namespace AZ
SetViewFrustumCorrectionEnabled(m_configuration.m_isCascadeCorrectionEnabled);
SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled);
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
SetSofteningBoundaryWidth(m_configuration.m_boundaryWidth);
SetShadowBias(m_configuration.m_shadowBias);
SetNormalShadowBias(m_configuration.m_normalShadowBias);
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled);
@@ -76,12 +76,14 @@ namespace AZ
void SetDebugColoringEnabled(bool enabled) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidth() const override;
void SetSofteningBoundaryWidth(float width) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
bool GetShadowReceiverPlaneBiasEnabled() const override;
void SetShadowReceiverPlaneBiasEnabled(bool enable) override;
float GetShadowBias() const override;
void SetShadowBias(float bias) override;
float GetNormalShadowBias() const override;
void SetNormalShadowBias(float bias) override;
private:
friend class EditorDirectionalLightComponent;
@@ -147,14 +147,6 @@ namespace AZ::Render
}
}
void DiskLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees));
}
}
void DiskLightDelegate::SetFilteringSampleCount(uint32_t count)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
@@ -44,7 +44,6 @@ namespace AZ
void SetShadowBias(float bias) override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;
void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float exponent) override;
@@ -136,7 +136,7 @@ namespace AZ
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 100.0f)
->Attribute(Edit::Attributes::SoftMin, 0.0f)
->Attribute(Edit::Attributes::SoftMax, 1.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
@@ -154,15 +154,6 @@ namespace AZ
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening boundary width",
"Width of the boundary between shadowed area and lit one. "
"Units are in degrees. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 1.f)
->Attribute(Edit::Attributes::Suffix, " deg")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count",
"This is only used when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
@@ -133,17 +133,8 @@ namespace AZ
->EnumAttribute(ShadowFilterMethod::Esm, "ESM")
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening boundary width",
"Width of the boundary between shadowed area and lit one. "
"Units are in meters. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 0.1f)
->Attribute(Edit::Attributes::Suffix, " m")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsEsmDisabled)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count",
"This is used only when the pixel is predicted as on the boundary. "
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count\n",
"This is used only when the pixel is predicted to be on the boundary.\n"
"Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 64)
@@ -151,10 +142,26 @@ namespace AZ
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::CheckBox, &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled,
"Shadow Receiver Plane Bias Enable",
"Shadow Receiver Plane Bias Enable\n",
"This reduces shadow acne when using large pcf kernels.")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled);
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_shadowBias,
"Shadow Bias\n",
"Reduces acne by applying a fixed bias along z in shadow-space.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 0.2)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n",
"Reduces acne by biasing the shadowmap lookup along the geometric normal.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
;
}
}
@@ -56,7 +56,6 @@ namespace AZ
void SetShadowBias([[maybe_unused]] float bias) override {};
void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {};
void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {};
void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {};
void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {};
void SetEsmExponent([[maybe_unused]] float esmExponent) override{};
@@ -75,8 +75,6 @@ namespace AZ
virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0;
//! Sets the filter method for the shadow
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Sets the width of boundary between shadowed area and lit area in degrees.
virtual void SetSofteningBoundaryWidthAngle(float widthInDegrees) = 0;
//! Sets the sample count for filtering of the shadow boundary, max 64.
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow.
@@ -92,14 +92,6 @@ namespace AZ::Render
}
}
void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees));
}
}
void SphereLightDelegate::SetFilteringSampleCount(uint32_t count)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
@@ -34,7 +34,6 @@ namespace AZ
void SetShadowBias(float bias) override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;
void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float esmExponent) override;
@@ -6,15 +6,17 @@
*
*/
#include <EditorCommonFeaturesSystemComponent.h>
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <EditorCommonFeaturesSystemComponent.h>
#include <SharedPreview/SharedThumbnail.h>
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
#include <IEditor.h>
@@ -68,7 +70,7 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
required.push_back(AZ_CRC_CE("ThumbnailerService"));
}
void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -82,24 +84,23 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::Activate()
{
m_renderer = AZStd::make_unique<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer>();
m_previewerFactory = AZStd::make_unique <LyIntegration::CommonPreviewerFactory>();
m_skinnedMeshDebugDisplay = AZStd::make_unique<SkinnedMeshDebugDisplay>();
AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect();
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect();
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
}
void EditorCommonFeaturesSystemComponent::Deactivate()
{
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect();
m_skinnedMeshDebugDisplay.reset();
m_previewerFactory.reset();
m_renderer.reset();
TeardownThumbnails();
}
void EditorCommonFeaturesSystemComponent::OnNewLevelCreated()
@@ -191,6 +192,13 @@ namespace AZ
}
}
void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
{
AZ::TickBus::QueueFunction([this](){
SetupThumbnails();
});
}
const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory(
const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
{
@@ -199,7 +207,39 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop()
{
m_renderer.reset();
TeardownThumbnails();
}
void EditorCommonFeaturesSystemComponent::SetupThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache), ThumbnailContext::DefaultContext);
if (!m_thumbnailRenderer)
{
m_thumbnailRenderer = AZStd::make_unique<AZ::LyIntegration::SharedThumbnailRenderer>();
}
if (!m_previewerFactory)
{
m_previewerFactory = AZStd::make_unique<LyIntegration::SharedPreviewerFactory>();
}
}
void EditorCommonFeaturesSystemComponent::TeardownThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName,
ThumbnailContext::DefaultContext);
m_thumbnailRenderer.reset();
m_previewerFactory.reset();
}
} // namespace Render
} // namespace AZ
@@ -11,10 +11,10 @@
#include <AzCore/Component/Component.h>
#include <AzFramework/Application/Application.h>
#include <AzToolsFramework/API/EditorLevelNotificationBus.h>
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
#include <AzToolsFramework/AssetBrowser/Previewer/PreviewerBus.h>
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
#include <Source/Thumbnails/Preview/CommonPreviewerFactory.h>
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
#include <SharedPreview/SharedPreviewerFactory.h>
#include <SharedPreview/SharedThumbnailRenderer.h>
namespace AZ
{
@@ -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:
@@ -53,15 +54,23 @@ namespace AZ
void OnNewLevelCreated() override;
// SliceEditorEntityOwnershipServiceBus overrides ...
void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override;
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;
const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(
const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override;
// AzFramework::ApplicationLifecycleEvents overrides...
void OnApplicationAboutToStop() override;
void SetupThumbnails();
void TeardownThumbnails();
private:
AZStd::unique_ptr<SkinnedMeshDebugDisplay> m_skinnedMeshDebugDisplay;
@@ -69,8 +78,8 @@ namespace AZ
AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" };
float m_envProbeHeight{ 200.0f };
AZStd::unique_ptr<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer> m_renderer;
AZStd::unique_ptr<LyIntegration::CommonPreviewerFactory> m_previewerFactory;
AZStd::unique_ptr<AZ::LyIntegration::SharedThumbnailRenderer> m_thumbnailRenderer;
AZStd::unique_ptr<LyIntegration::SharedPreviewerFactory> m_previewerFactory;
};
} // namespace Render
} // namespace AZ
@@ -175,6 +175,10 @@ namespace AZ
void GridComponentController::OnBeginPrepareRender()
{
auto* auxGeomFP = AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::RPI::AuxGeomFeatureProcessorInterface>(m_entityId);
if (!auxGeomFP)
{
return;
}
if (auto auxGeom = auxGeomFP->GetDrawQueue())
{
BuildGrid();
@@ -148,11 +148,13 @@ namespace AZ
BaseClass::Activate();
MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId());
MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId());
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
UpdateMaterialSlots();
}
void EditorMaterialComponent::Deactivate()
{
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
MaterialReceiverNotificationBus::Handler::BusDisconnect();
MaterialComponentNotificationBus::Handler::BusDisconnect();
BaseClass::Deactivate();
@@ -238,6 +240,19 @@ namespace AZ
UpdateMaterialSlots();
});
action->setToolTip("Repair materials that reference missing assets by assigning the default asset.");
action = menu->addAction("Apply Automatic Property Updates", [this]() {
AzToolsFramework::ScopedUndoBatch undoBatch("Applying automatic property updates.");
SetDirty();
uint32_t propertiesUpdated = 0;
MaterialComponentRequestBus::EventResult(propertiesUpdated, GetEntityId(), &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates);
AZ_Printf("EditorMaterialComponent", "Updated %u property(s).", propertiesUpdated);
UpdateMaterialSlots();
});
action->setToolTip("Repair material property overrides that reference missing properties by auto-renaming them where possible.");
}
void EditorMaterialComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
@@ -260,6 +275,18 @@ namespace AZ
}
}
void EditorMaterialComponent::OnRenderMaterialPreviewComplete(
[[maybe_unused]] const AZ::EntityId& entityId,
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
[[maybe_unused]] const QPixmap& pixmap)
{
if (entityId == GetEntityId())
{
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
}
}
AZ::u32 EditorMaterialComponent::OnConfigurationChanged()
{
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
@@ -9,6 +9,7 @@
#pragma once
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <Material/EditorMaterialComponentSlot.h>
@@ -21,8 +22,9 @@ namespace AZ
//! In-editor material component for displaying and editing material assignments.
class EditorMaterialComponent final
: public EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>
, private MaterialReceiverNotificationBus::Handler
, private MaterialComponentNotificationBus::Handler
, public MaterialReceiverNotificationBus::Handler
, public MaterialComponentNotificationBus::Handler
, public EditorMaterialSystemComponentNotificationBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>;
@@ -52,6 +54,10 @@ namespace AZ
//! MaterialComponentNotificationBus::Handler overrides...
void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override;
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
// Regenerates the editor component material slots based on the material and
// LOD mapping from the model or other consumer of materials.
// If any corresponding material assignments are found in the component
@@ -23,10 +23,6 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
@@ -49,29 +45,18 @@ namespace AZ
MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent)
: AtomToolsFramework::InspectorWidget(parent)
{
// Create the menu button
QToolButton* menuButton = new QToolButton(this);
menuButton->setAutoRaise(true);
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
menuButton->setVisible(true);
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
AddHeading(menuButton);
m_messageLabel = new QLabel(this);
m_messageLabel->setWordWrap(true);
m_messageLabel->setVisible(true);
m_messageLabel->setAlignment(Qt::AlignCenter);
m_messageLabel->setText(tr("Material not available"));
AddHeading(m_messageLabel);
CreateHeading();
AZ::TickBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
}
MaterialPropertyInspector::~MaterialPropertyInspector()
{
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
MaterialComponentNotificationBus::Handler::BusDisconnect();
}
@@ -140,7 +125,7 @@ namespace AZ
}
Populate();
m_messageLabel->setVisible(false);
LoadOverridesFromEntity();
return true;
}
@@ -152,8 +137,9 @@ namespace AZ
m_dirtyPropertyFlags.set();
m_editorFunctors = {};
m_internalEditNotification = {};
m_messageLabel->setVisible(true);
m_messageLabel->setText(tr("Material not available"));
m_updateUI = {};
m_updatePreview = {};
UpdateHeading();
}
bool MaterialPropertyInspector::IsLoaded() const
@@ -168,49 +154,63 @@ namespace AZ
m_dirtyPropertyFlags.set();
m_internalEditNotification = {};
AZ::TickBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset();
}
void MaterialPropertyInspector::AddDetailsGroup()
void MaterialPropertyInspector::CreateHeading()
{
const AZStd::string& groupName = "Details";
const AZStd::string& groupDisplayName = "Details";
const AZStd::string& groupDescription = "";
// Create the menu button
QToolButton* menuButton = new QToolButton(this);
menuButton->setAutoRaise(true);
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
menuButton->setVisible(true);
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
AddHeading(menuButton);
auto propertyGroupContainer = new QWidget(this);
propertyGroupContainer->setLayout(new QHBoxLayout());
m_overviewImage = new QLabel(this);
m_overviewImage->setFixedSize(QSize(120, 120));
m_overviewImage->setScaledContents(true);
m_overviewImage->setVisible(false);
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey =
MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId);
auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this);
thumbnailWidget->setFixedSize(QSize(120, 120));
thumbnailWidget->setVisible(true);
thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext);
propertyGroupContainer->layout()->addWidget(thumbnailWidget);
auto materialInfoWidget = new QLabel(this);
m_overviewText = new QLabel(this);
QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth());
materialInfoWidget->setSizePolicy(sizePolicy1);
materialInfoWidget->setMinimumSize(QSize(0, 0));
materialInfoWidget->setMaximumSize(QSize(16777215, 16777215));
materialInfoWidget->setTextFormat(Qt::AutoText);
materialInfoWidget->setScaledContents(false);
materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
materialInfoWidget->setWordWrap(true);
sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth());
m_overviewText->setSizePolicy(sizePolicy1);
m_overviewText->setMinimumSize(QSize(0, 0));
m_overviewText->setMaximumSize(QSize(16777215, 16777215));
m_overviewText->setTextFormat(Qt::AutoText);
m_overviewText->setScaledContents(false);
m_overviewText->setWordWrap(true);
m_overviewText->setVisible(true);
auto overviewContainer = new QWidget(this);
overviewContainer->setLayout(new QHBoxLayout());
overviewContainer->layout()->addWidget(m_overviewImage);
overviewContainer->layout()->addWidget(m_overviewText);
AddHeading(overviewContainer);
}
void MaterialPropertyInspector::UpdateHeading()
{
if (!IsLoaded())
{
m_overviewText->setText(tr("Material not available"));
m_overviewText->setAlignment(Qt::AlignCenter);
m_overviewImage->setVisible(false);
return;
}
QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str());
QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str());
QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str());
QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
QFileInfo materialParentSourceFileInfo(
AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(
entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
AZStd::string slotName;
MaterialComponentRequestBus::EventResult(
@@ -226,7 +226,8 @@ namespace AZ
}
if (!materialTypeSourceFileInfo.fileName().isEmpty())
{
materialInfo += tr("<tr><td><b>Material Type&emsp;</b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
materialInfo +=
tr("<tr><td><b>Material Type&emsp;</b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
}
if (!materialSourceFileInfo.fileName().isEmpty())
{
@@ -234,14 +235,21 @@ namespace AZ
}
if (!materialParentSourceFileInfo.fileName().isEmpty())
{
materialInfo += tr("<tr><td><b>Material Parent&emsp;</b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
materialInfo +=
tr("<tr><td><b>Material Parent&emsp;</b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
}
materialInfo += tr("</table>");
materialInfoWidget->setText(materialInfo);
propertyGroupContainer->layout()->addWidget(materialInfoWidget);
m_overviewText->setText(materialInfo);
m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer);
QPixmap pixmap;
EditorMaterialSystemComponentRequestBus::BroadcastResult(
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId,
m_materialAssignmentId);
m_overviewImage->setPixmap(pixmap);
m_overviewImage->setVisible(true);
m_updatePreview |= pixmap.isNull();
}
void MaterialPropertyInspector::AddUvNamesGroup()
@@ -282,13 +290,8 @@ namespace AZ
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
}
void MaterialPropertyInspector::Populate()
void MaterialPropertyInspector::AddPropertiesGroup()
{
AddGroupsBegin();
AddDetailsGroup();
AddUvNamesGroup();
// Copy all of the properties from the material asset to the source data that will be exported
for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder())
{
@@ -327,10 +330,14 @@ namespace AZ
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
}
}
void MaterialPropertyInspector::Populate()
{
AddGroupsBegin();
AddUvNamesGroup();
AddPropertiesGroup();
AddGroupsEnd();
LoadOverridesFromEntity();
}
void MaterialPropertyInspector::LoadOverridesFromEntity()
@@ -345,6 +352,25 @@ namespace AZ
m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides,
m_materialAssignmentId);
// Apply any automatic property renames so that the material inspector will be properly initialized with the right values
// for properties that have new names.
{
AZStd::vector<AZStd::pair<Name, Name>> renamedProperties;
for (auto& propertyOverridePair : m_editData.m_materialPropertyOverrideMap)
{
Name name = propertyOverridePair.first;
if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(name))
{
renamedProperties.emplace_back(propertyOverridePair.first, name);
}
}
for (const auto& [oldName, newName] : renamedProperties)
{
m_editData.m_materialPropertyOverrideMap[newName] = m_editData.m_materialPropertyOverrideMap[oldName];
m_editData.m_materialPropertyOverrideMap.erase(oldName);
}
}
for (auto& group : m_groups)
{
for (auto& property : group.second.m_properties)
@@ -375,6 +401,7 @@ namespace AZ
m_dirtyPropertyFlags.set();
RunEditorMaterialFunctors();
RebuildAll();
UpdateHeading();
}
void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges)
@@ -398,6 +425,9 @@ namespace AZ
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
m_internalEditNotification = false;
}
// m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs
// throttling
}
void MaterialPropertyInspector::RunEditorMaterialFunctors()
@@ -521,9 +551,9 @@ namespace AZ
{
if (IsInstanceNodePropertyModifed(node))
{
return ":/PropertyEditor/Resources/changed_data_item.png";
return ":/Icons/changed_property.svg";
}
return ":/PropertyEditor/Resources/blank.png";
return ":/Icons/blank.png";
}
bool MaterialPropertyInspector::SaveMaterial() const
@@ -607,7 +637,8 @@ namespace AZ
MaterialComponentRequestBus::Event(
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
MaterialPropertyOverrideMap());
QueueUpdateUI();
m_updateUI = true;
m_updatePreview = true;
});
action->setEnabled(IsLoaded());
@@ -702,10 +733,7 @@ namespace AZ
void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId)
{
if (m_entityId == entityId)
{
QueueUpdateUI();
}
m_updateUI |= (m_entityId == entityId);
}
void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId)
@@ -719,25 +747,39 @@ namespace AZ
void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
{
AZ_UNUSED(name);
if (m_entityId == entityId)
{
QueueUpdateUI();
}
m_updateUI |= (m_entityId == entityId);
}
void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time)
{
AZ_UNUSED(time);
AZ_UNUSED(deltaTime);
UpdateUI();
AZ::TickBus::Handler::BusDisconnect();
if (m_updateUI)
{
m_updateUI = false;
UpdateUI();
}
if (m_updatePreview)
{
m_updatePreview = false;
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId);
}
}
void MaterialPropertyInspector::OnMaterialsEdited()
{
if (!m_internalEditNotification)
m_updateUI |= !m_internalEditNotification;
m_updatePreview = true;
}
void MaterialPropertyInspector::OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)
{
if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId)
{
QueueUpdateUI();
m_overviewImage->setPixmap(pixmap);
}
}
@@ -761,16 +803,6 @@ namespace AZ
LoadMaterial(m_entityId, m_materialAssignmentId);
}
}
void MaterialPropertyInspector::QueueUpdateUI()
{
if (!AZ::TickBus::Handler::BusIsConnected())
{
AZ::TickBus::Handler::BusConnect();
}
}
} // namespace EditorMaterialComponentInspector
} // namespace Render
} // namespace AZ
//#include <AtomLyIntegration/CommonFeatures/moc_EditorMaterialComponentInspector.cpp>
@@ -9,6 +9,7 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
@@ -31,14 +32,13 @@ namespace AZ
{
namespace EditorMaterialComponentInspector
{
using PropertyChangedCallback = AZStd::function<void(const MaterialPropertyOverrideMap&)>;
class MaterialPropertyInspector
: public AtomToolsFramework::InspectorWidget
, public AzToolsFramework::IPropertyEditorNotify
, public AZ::EntitySystemBus::Handler
, public AZ::TickBus::Handler
, public MaterialComponentNotificationBus::Handler
, public EditorMaterialSystemComponentNotificationBus::Handler
{
Q_OBJECT
public:
@@ -89,11 +89,19 @@ namespace AZ
//! MaterialComponentNotificationBus::Handler overrides...
void OnMaterialsEdited() override;
void UpdateUI();
void QueueUpdateUI();
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId,
const AZ::Render::MaterialAssignmentId& materialAssignmentId,
const QPixmap& pixmap) override;
void UpdateUI();
void CreateHeading();
void UpdateHeading();
void AddDetailsGroup();
void AddUvNamesGroup();
void AddPropertiesGroup();
void LoadOverridesFromEntity();
void SaveOverridesToEntity(bool commitChanges);
@@ -115,7 +123,10 @@ namespace AZ
AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {};
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups = {};
bool m_internalEditNotification = {};
QLabel* m_messageLabel = {};
bool m_updateUI = {};
bool m_updatePreview = {};
QLabel* m_overviewText = {};
QLabel* m_overviewImage = {};
};
} // namespace EditorMaterialComponentInspector
} // namespace Render
@@ -6,23 +6,25 @@
*
*/
#include <Material/EditorMaterialComponentSlot.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <Material/EditorMaterialComponentInspector.h>
#include <Material/EditorMaterialModelUvNameMapInspector.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <Material/EditorMaterialComponentInspector.h>
#include <Material/EditorMaterialComponentSlot.h>
#include <Material/EditorMaterialModelUvNameMapInspector.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QMenu>
#include <QAction>
#include <QAction>
#include <QByteArray>
#include <QCursor>
#include <QDataStream>
#include <QMenu>
AZ_POP_DISABLE_WARNING
namespace AZ
@@ -100,6 +102,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData)
;
}
}
@@ -118,6 +121,33 @@ namespace AZ
}
};
AZStd::vector<char> EditorMaterialComponentSlot::GetPreviewPixmapData() const
{
if (!GetActiveAssetId().IsValid())
{
return {};
}
QPixmap pixmap;
EditorMaterialSystemComponentRequestBus::BroadcastResult(
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id);
if (pixmap.isNull())
{
if (m_updatePreview)
{
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
m_updatePreview = false;
}
return {};
}
QByteArray pixmapBytes;
QDataStream stream(&pixmapBytes, QIODevice::WriteOnly);
stream << pixmap;
return AZStd::vector<char>(pixmapBytes.begin(), pixmapBytes.end());
}
AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const
{
return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId();
@@ -169,14 +199,6 @@ namespace AZ
ClearOverrides();
}
void EditorMaterialComponentSlot::ClearToDefaultAsset()
{
m_materialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(GetDefaultAssetId(), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
MaterialComponentRequestBus::Event(
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
ClearOverrides();
}
void EditorMaterialComponentSlot::ClearOverrides()
{
MaterialComponentRequestBus::Event(
@@ -315,6 +337,10 @@ namespace AZ
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
m_updatePreview = false;
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
@@ -8,37 +8,52 @@
#pragma once
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/Feature/Material/MaterialAssignment.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <QPixmap>
namespace AZ
{
namespace Render
{
static const size_t DefaultMaterialSlotIndex = std::numeric_limits<size_t>::max();
//! Details for a single editable material assignment
struct EditorMaterialComponentSlot final
{
AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}");
AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0);
static void Reflect(ReflectContext* context);
static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
static void Reflect(ReflectContext* context);
//! Get cached preview image as a buffer to use as an RPE attribute
//! If a cached image isn't avalible then a request will be made to render one
AZStd::vector<char> GetPreviewPixmapData() const;
//! Returns the overridden asset id if it's valid, otherwise gets the default asseet id
AZ::Data::AssetId GetActiveAssetId() const;
//! Returns the default asseet id of the material provded by the model
AZ::Data::AssetId GetDefaultAssetId() const;
//! Returns the display name of the material slot
AZStd::string GetLabel() const;
//! Returns true if the active material asset has a source material
bool HasSourceData() const;
//! Assign a new material override asset
void SetAsset(const Data::AssetId& assetId);
//! Assign a new material override asset
void SetAsset(const Data::Asset<RPI::MaterialAsset>& asset);
//! Remove material and prperty overrides
void Clear();
void ClearToDefaultAsset();
//! Remove prperty overrides
void ClearOverrides();
void OpenMaterialExporter();
@@ -54,6 +69,7 @@ namespace AZ
void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
void OnMaterialChanged() const;
void OnDataChanged() const;
mutable bool m_updatePreview = true;
};
// Vector of slots for assignable or overridable material data.
@@ -62,8 +78,8 @@ namespace AZ
// Table containing all editable material data that is displayed in the edit context and inspector
// The vector represents all the LODs that can have material overrides.
// The container will be populated with every potential material slot on an associated model, using its default values.
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map
// as overrides that will be applied to material instances
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment
// map as overrides that will be applied to material instances
using EditorMaterialComponentSlotsByLodContainer = AZStd::vector<EditorMaterialComponentSlotContainer>;
} // namespace Render
} // namespace AZ
@@ -99,7 +99,6 @@ namespace AZ
{
// Construct the material source data object that will be exported
AZ::RPI::MaterialSourceData exportData;
exportData.m_propertyLayoutVersion = editData.m_materialTypeSourceData.m_propertyLayout.m_version;
// Converting absolute material paths to relative paths
bool result = false;
@@ -7,6 +7,11 @@
*/
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h>
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
@@ -16,11 +21,10 @@
#include <AzFramework/Application/Application.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ViewPaneOptions.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <Editor/LyViewPaneNames.h>
#include <Material/EditorMaterialComponentInspector.h>
#include <Material/EditorMaterialSystemComponent.h>
#include <Material/MaterialThumbnail.h>
#include <SharedPreview/SharedPreviewContent.h>
// Disables warning messages triggered by the Qt library
// 4251: class needs to have dll-interface to be used by clients of class
@@ -30,6 +34,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
#include <QApplication>
#include <QDockWidget>
#include <QObject>
#include <QPixmap>
#include <QImage>
#include <QProcessEnvironment>
AZ_POP_DISABLE_WARNING
@@ -55,7 +61,7 @@ namespace AZ
{
ec->Class<EditorMaterialSystemComponent>("EditorMaterialSystemComponent", "System component that manages launching and maintaining connections the material editor.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
@@ -64,17 +70,17 @@ namespace AZ
void EditorMaterialSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e));
provided.push_back(AZ_CRC_CE("EditorMaterialSystem"));
}
void EditorMaterialSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e));
incompatible.push_back(AZ_CRC_CE("EditorMaterialSystem"));
}
void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
required.push_back(AZ_CRC_CE("PreviewRendererSystem"));
}
void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -89,25 +95,25 @@ namespace AZ
void EditorMaterialSystemComponent::Activate()
{
AZ::EntitySystemBus::Handler::BusConnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
EditorMaterialSystemComponentRequestBus::Handler::BusConnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect();
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
SetupThumbnails();
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
}
void EditorMaterialSystemComponent::Deactivate()
{
AZ::EntitySystemBus::Handler::BusDisconnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
TeardownThumbnails();
m_materialBrowserInteractions.reset();
if (m_openMaterialEditorAction)
@@ -154,11 +160,84 @@ namespace AZ
}
}
void EditorMaterialSystemComponent::OnApplicationAboutToStop()
void EditorMaterialSystemComponent::RenderMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId)
{
TeardownThumbnails();
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
if (auto previewRenderer = AZ::Interface<AtomToolsFramework::PreviewRendererInterface>::Get())
{
AZ::Data::AssetId materialAssetId = {};
MaterialComponentRequestBus::EventResult(
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId);
if (!materialAssetId.IsValid())
{
MaterialComponentRequestBus::EventResult(
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId);
if (!materialAssetId.IsValid())
{
return;
}
}
AZ::Render::MaterialPropertyOverrideMap propertyOverrides;
AZ::Render::MaterialComponentRequestBus::EventResult(
propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides,
materialAssignmentId);
previewRenderer->AddCaptureRequest(
{ MaterialPreviewResolution,
AZStd::make_shared<AZ::LyIntegration::SharedPreviewContent>(
previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(),
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId,
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides),
[entityId, materialAssignmentId]()
{
AZ_UNUSED(entityId);
AZ_UNUSED(materialAssignmentId);
AZ_Warning(
"EditorMaterialSystemComponent", false, "RenderMaterialPreview capture failed for entity %s slot %s.",
entityId.ToString().c_str(), materialAssignmentId.ToString().c_str());
},
[entityId, materialAssignmentId](const QPixmap& pixmap)
{
AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast(
&AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId,
materialAssignmentId, pixmap);
} });
}
}
QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const
{
const auto& itr1 = m_materialPreviews.find(entityId);
if (itr1 != m_materialPreviews.end())
{
const auto& itr2 = itr1->second.find(materialAssignmentId);
if (itr2 != itr1->second.end())
{
return itr2->second;
}
}
return QPixmap();
}
void EditorMaterialSystemComponent::OnEntityDestroyed(const AZ::EntityId& entityId)
{
m_materialPreviews.erase(entityId);
}
void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete(
[[maybe_unused]] const AZ::EntityId& entityId,
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
[[maybe_unused]] const QPixmap& pixmap)
{
PurgePreviews();
m_materialPreviews[entityId][materialAssignmentId] = pixmap;
}
void EditorMaterialSystemComponent::OnPopulateToolMenuItems()
{
if (!m_openMaterialEditorAction)
@@ -201,26 +280,6 @@ namespace AZ
"Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions);
}
void EditorMaterialSystemComponent::SetupThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache),
ThumbnailContext::DefaultContext);
}
void EditorMaterialSystemComponent::TeardownThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName,
ThumbnailContext::DefaultContext);
}
AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails(
const char* fullSourceFileName)
{
@@ -232,5 +291,19 @@ namespace AZ
}
return AzToolsFramework::AssetBrowser::SourceFileDetails();
}
void EditorMaterialSystemComponent::PurgePreviews()
{
size_t materialPreviewCount = 0;
for (const auto& materialPreviewPair : m_materialPreviews)
{
materialPreviewCount += materialPreviewPair.second.size();
}
if (materialPreviewCount > MaterialPreviewLimit)
{
m_materialPreviews.clear();
}
}
} // namespace Render
} // namespace AZ
@@ -5,31 +5,32 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzFramework/Application/Application.h>
#include <AzCore/Component/EntityBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Viewport/ActionBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <Material/MaterialBrowserInteractions.h>
#include <QPixmap>
namespace AZ
{
namespace Render
{
//! System component that manages launching and maintaining connections with the material editor.
class EditorMaterialSystemComponent
class EditorMaterialSystemComponent final
: public AZ::Component
, private EditorMaterialSystemComponentRequestBus::Handler
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
, private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
, private AzToolsFramework::EditorMenuNotificationBus::Handler
, private AzToolsFramework::EditorEvents::Bus::Handler
, public AZ::EntitySystemBus::Handler
, public EditorMaterialSystemComponentNotificationBus::Handler
, public EditorMaterialSystemComponentRequestBus::Handler
, public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
, public AzToolsFramework::EditorMenuNotificationBus::Handler
, public AzToolsFramework::EditorEvents::Bus::Handler
{
public:
AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}");
@@ -51,9 +52,16 @@ namespace AZ
//! EditorMaterialSystemComponentRequestBus::Handler overrides...
void OpenMaterialEditor(const AZStd::string& sourcePath) override;
void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
QPixmap GetRenderedMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override;
// AzFramework::ApplicationLifecycleEvents overrides...
void OnApplicationAboutToStop() override;
// AZ::EntitySystemBus::Handler overrides...
void OnEntityDestroyed(const AZ::EntityId& entityId) override;
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
//! AssetBrowserInteractionNotificationBus::Handler overrides...
AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override;
@@ -65,12 +73,13 @@ namespace AZ
// AztoolsFramework::EditorEvents::Bus::Handler overrides...
void NotifyRegisterViews() override;
void SetupThumbnails();
void TeardownThumbnails();
void PurgePreviews();
QAction* m_openMaterialEditorAction = nullptr;
AZStd::unique_ptr<MaterialBrowserInteractions> m_materialBrowserInteractions;
AZStd::unordered_map<AZ::EntityId, AZStd::unordered_map<AZ::Render::MaterialAssignmentId, QPixmap>> m_materialPreviews;
static constexpr const size_t MaterialPreviewLimit = 100;
static constexpr const int MaterialPreviewResolution = 128;
};
} // namespace Render
} // namespace AZ
@@ -49,6 +49,7 @@ namespace AZ
->Event("ClearIncompatibleMaterialOverrides", &MaterialComponentRequestBus::Events::ClearIncompatibleMaterialOverrides)
->Event("ClearInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::ClearInvalidMaterialOverrides)
->Event("RepairInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::RepairInvalidMaterialOverrides)
->Event("ApplyAutomaticPropertyUpdates", &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates)
->Event("SetMaterialOverride", &MaterialComponentRequestBus::Events::SetMaterialOverride)
->Event("GetMaterialOverride", &MaterialComponentRequestBus::Events::GetMaterialOverride)
->Event("ClearMaterialOverride", &MaterialComponentRequestBus::Events::ClearMaterialOverride)
@@ -406,6 +407,37 @@ namespace AZ
}
LoadMaterials();
}
uint32_t MaterialComponentController::ApplyAutomaticPropertyUpdates()
{
uint32_t propertiesUpdated = 0;
for (auto& materialAssignmentPair : m_configuration.m_materials)
{
MaterialAssignment& materialAssignment = materialAssignmentPair.second;
AZStd::vector<AZStd::pair<Name, Name>> renamedProperties;
for (const auto& propertyPair : materialAssignment.m_propertyOverrides)
{
Name propertyId = propertyPair.first;
if (materialAssignment.m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(propertyId))
{
renamedProperties.emplace_back(propertyPair.first, propertyId);
++propertiesUpdated;
}
}
for (const auto& [oldName, newName] : renamedProperties)
{
materialAssignment.m_propertyOverrides[newName] = materialAssignment.m_propertyOverrides[oldName];
materialAssignment.m_propertyOverrides.erase(oldName);
}
}
return propertiesUpdated;
}
void MaterialComponentController::SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId)
{
@@ -58,6 +58,7 @@ namespace AZ
void ClearIncompatibleMaterialOverrides() override;
void ClearInvalidMaterialOverrides() override;
void RepairInvalidMaterialOverrides() override;
uint32_t ApplyAutomaticPropertyUpdates() override;
void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) override;
const AZ::Data::AssetId GetDefaultMaterialOverride() const override;
void ClearDefaultMaterialOverride() override;
@@ -1,112 +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 <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <QtConcurrent/QtConcurrent>
#include <Source/Material/MaterialThumbnail.h>
#include <Source/Thumbnails/ThumbnailUtils.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass
//////////////////////////////////////////////////////////////////////////
// MaterialThumbnail
//////////////////////////////////////////////////////////////////////////
MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
: Thumbnail(key)
{
m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type());
if (!m_assetId.IsValid())
{
AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
m_state = State::Failed;
return;
}
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
void MaterialThumbnail::LoadThread()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
RPI::MaterialAsset::RTTI_Type(),
&AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
m_key,
MaterialThumbnailSize);
// wait for response from thumbnail renderer
m_renderWait.acquire();
}
MaterialThumbnail::~MaterialThumbnail()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
void MaterialThumbnail::ThumbnailRendered(QPixmap& thumbnailImage)
{
m_pixmap = thumbnailImage;
m_renderWait.release();
}
void MaterialThumbnail::ThumbnailFailedToRender()
{
m_state = State::Failed;
m_renderWait.release();
}
void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
{
if (m_assetId == assetId &&
m_state == State::Ready)
{
m_state = State::Unloaded;
Load();
}
}
//////////////////////////////////////////////////////////////////////////
// MaterialThumbnailCache
//////////////////////////////////////////////////////////////////////////
MaterialThumbnailCache::MaterialThumbnailCache()
: ThumbnailCache<MaterialThumbnail>()
{
}
MaterialThumbnailCache::~MaterialThumbnailCache() = default;
int MaterialThumbnailCache::GetPriority() const
{
// Material thumbnails override default source thumbnails, so carry higher priority
return 1;
}
const char* MaterialThumbnailCache::GetProviderName() const
{
return ProviderName;
}
bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
{
return
GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() &&
// in case it's a source scene file, it will contain both material and model products
// model thumbnails are handled by MeshThumbnail
!GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid();
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
#include <Material/moc_MaterialThumbnail.cpp>
@@ -1,73 +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
#if !defined(Q_MOC_RUN)
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
#endif
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
/**
* Custom material or model thumbnail that detects when an asset changes and updates the thumbnail
*/
class MaterialThumbnail
: public AzToolsFramework::Thumbnailer::Thumbnail
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
{
Q_OBJECT
public:
MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
~MaterialThumbnail() override;
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
void ThumbnailRendered(QPixmap& thumbnailImage) override;
void ThumbnailFailedToRender() override;
protected:
void LoadThread() override;
private:
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
AZStd::binary_semaphore m_renderWait;
Data::AssetId m_assetId;
};
/**
* Cache configuration for large material thumbnails
*/
class MaterialThumbnailCache
: public AzToolsFramework::Thumbnailer::ThumbnailCache<MaterialThumbnail>
{
public:
MaterialThumbnailCache();
~MaterialThumbnailCache() override;
int GetPriority() const override;
const char* GetProviderName() const override;
static constexpr const char* ProviderName = "Material Thumbnails";
protected:
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -6,13 +6,10 @@
*
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Utils/Utils.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <Source/Mesh/EditorMeshSystemComponent.h>
#include <Source/Mesh/MeshThumbnail.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Mesh/EditorMeshSystemComponent.h>
namespace AZ
{
@@ -47,11 +44,6 @@ namespace AZ
incompatible.push_back(AZ_CRC_CE("EditorMeshSystem"));
}
void EditorMeshSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC_CE("ThumbnailerService"));
}
void EditorMeshSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
@@ -59,39 +51,10 @@ namespace AZ
void EditorMeshSystemComponent::Activate()
{
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
SetupThumbnails();
}
void EditorMeshSystemComponent::Deactivate()
{
TeardownThumbnails();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
}
void EditorMeshSystemComponent::OnApplicationAboutToStop()
{
TeardownThumbnails();
}
void EditorMeshSystemComponent::SetupThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider,
MAKE_TCACHE(Thumbnails::MeshThumbnailCache),
ThumbnailContext::DefaultContext);
}
void EditorMeshSystemComponent::TeardownThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider,
Thumbnails::MeshThumbnailCache::ProviderName,
ThumbnailContext::DefaultContext);
}
} // namespace Render
} // namespace AZ
@@ -8,7 +8,6 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzFramework/Application/Application.h>
namespace AZ
{
@@ -17,7 +16,6 @@ namespace AZ
//! System component that sets up necessary logic related to EditorMeshComponent.
class EditorMeshSystemComponent
: public AZ::Component
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
{
public:
AZ_COMPONENT(EditorMeshSystemComponent, "{4D332E3D-C4FC-410B-A915-8E234CBDD4EC}");
@@ -26,20 +24,12 @@ namespace AZ
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
protected:
// AZ::Component interface overrides...
void Activate() override;
void Deactivate() override;
private:
// AzFramework::ApplicationLifecycleEvents overrides...
void OnApplicationAboutToStop() override;
void SetupThumbnails();
void TeardownThumbnails();
};
} // namespace Render
} // namespace AZ
@@ -1,109 +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 <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <QtConcurrent/QtConcurrent>
#include <Source/Mesh/MeshThumbnail.h>
#include <Source/Thumbnails/ThumbnailUtils.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
static constexpr const int MeshThumbnailSize = 512; // 512 is the default size in render to texture pass
//////////////////////////////////////////////////////////////////////////
// MeshThumbnail
//////////////////////////////////////////////////////////////////////////
MeshThumbnail::MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
: Thumbnail(key)
{
m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type());
if (!m_assetId.IsValid())
{
AZ_Error("MeshThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
m_state = State::Failed;
return;
}
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
void MeshThumbnail::LoadThread()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
RPI::ModelAsset::RTTI_Type(),
&AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
m_key,
MeshThumbnailSize);
// wait for response from thumbnail renderer
m_renderWait.acquire();
}
MeshThumbnail::~MeshThumbnail()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
void MeshThumbnail::ThumbnailRendered(QPixmap& thumbnailImage)
{
m_pixmap = thumbnailImage;
m_renderWait.release();
}
void MeshThumbnail::ThumbnailFailedToRender()
{
m_state = State::Failed;
m_renderWait.release();
}
void MeshThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
{
if (m_assetId == assetId &&
m_state == State::Ready)
{
m_state = State::Unloaded;
Load();
}
}
//////////////////////////////////////////////////////////////////////////
// MeshThumbnailCache
//////////////////////////////////////////////////////////////////////////
MeshThumbnailCache::MeshThumbnailCache()
: ThumbnailCache<MeshThumbnail>()
{
}
MeshThumbnailCache::~MeshThumbnailCache() = default;
int MeshThumbnailCache::GetPriority() const
{
// Material thumbnails override default source thumbnails, so carry higher priority
return 1;
}
const char* MeshThumbnailCache::GetProviderName() const
{
return ProviderName;
}
bool MeshThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
{
return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid();
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
#include <Mesh/moc_MeshThumbnail.cpp>
@@ -1,72 +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
#if !defined(Q_MOC_RUN)
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#endif
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
/**
* Custom material or model thumbnail that detects when an asset changes and updates the thumbnail
*/
class MeshThumbnail
: public AzToolsFramework::Thumbnailer::Thumbnail
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
{
Q_OBJECT
public:
MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
~MeshThumbnail() override;
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
void ThumbnailRendered(QPixmap& thumbnailImage) override;
void ThumbnailFailedToRender() override;
protected:
void LoadThread() override;
private:
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
AZStd::binary_semaphore m_renderWait;
Data::AssetId m_assetId;
};
/**
* Cache configuration for large material thumbnails
*/
class MeshThumbnailCache
: public AzToolsFramework::Thumbnailer::ThumbnailCache<MeshThumbnail>
{
public:
MeshThumbnailCache();
~MeshThumbnailCache() override;
int GetPriority() const override;
const char* GetProviderName() const override;
static constexpr const char* ProviderName = "Mesh Thumbnails";
protected:
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -7,6 +7,10 @@
*/
#include <PostProcess/ColorGrading/EditorHDRColorGradingComponent.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzCore/StringFunc/StringFunc.h>
namespace AZ
{
@@ -18,7 +22,10 @@ namespace AZ
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()->Version(1);
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()
->Version(2)
->Field("generatedLut", &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
@@ -31,6 +38,20 @@ namespace AZ
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO ATOM-2672][PostFX] need to create page for PostProcessing.
->ClassElement(AZ::Edit::ClassElements::Group, "LUT Generation")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->UIElement(AZ::Edit::UIHandlers::Button, "Generate LUT", "Generates a LUT from the scene's enabled color grading blend.")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Generate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::GenerateLut)
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath, "Generated LUT Path", "Generated LUT Path")
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
->UIElement(AZ::Edit::UIHandlers::Button, "Activate LUT", "Use the generated LUT asset in a Look Modification component")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Activate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::ActivateLut)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
;
editContext->Class<HDRColorGradingComponentController>(
@@ -47,6 +68,9 @@ namespace AZ
"Enable HDR color grading.")
->ClassElement(AZ::Edit::ClassElements::Group, "Color Adjustment")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorAdjustmentWeight, "Weight", "Weight of color adjustments")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingExposure, "Exposure", "Exposure Value")
->Attribute(Edit::Attributes::Min, AZStd::numeric_limits<float>::lowest())
->Attribute(Edit::Attributes::Max, AZStd::numeric_limits<float>::max())
@@ -66,27 +90,34 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingFilterMultiply, "Filter Multiply", "Filter Multiply Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_colorFilterSwatch, "Color Filter Swatch", "Color Filter Swatch Value")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_colorFilterSwatch, "Filter Swatch", "Color Filter Swatch Value")
->ClassElement(AZ::Edit::ClassElements::Group, "White Balance")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceWeight, "Weight", "Weight of white balance")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceKelvin, "Temperature", "Temperature in Kelvin")
->Attribute(Edit::Attributes::Min, 1000.0f)
->Attribute(Edit::Attributes::Max, 40000.0f)
->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.165f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceTint, "Tint", "Tint Value")
->Attribute(Edit::Attributes::Min, -100.0f)
->Attribute(Edit::Attributes::Max, 100.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceLuminancePreservation, "Luminance Preservation", "Modulate the preservation of luminance")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->ClassElement(AZ::Edit::ClassElements::Group, "Split Toning")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneWeight, "Split Tone Weight", "Modulates the split toning effect.")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneWeight, "Weight", "Modulates the split toning effect.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneBalance, "Split Tone Balance", "Split Tone Balance Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneBalance, "Balance", "Split Tone Balance Value")
->Attribute(Edit::Attributes::Min, -1.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneShadowsColor, "Split Tone Shadows Color", "Split Tone Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneHighlightsColor, "Split Tone Highlights Color", "Split Tone Highlights Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneShadowsColor, "Shadows Color", "Split Tone Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneHighlightsColor, "Highlights Color", "Split Tone Highlights Color")
->ClassElement(AZ::Edit::ClassElements::Group, "Channel Mixing")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
@@ -99,33 +130,56 @@ namespace AZ
->ClassElement(AZ::Edit::ClassElements::Group, "Shadow Midtones Highlights")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhWeight, "SMH Weight", "Modulates the SMH effect.")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhWeight, "Weight", "Modulates the SMH effect.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsStart, "SMH Shadows Start", "SMH Shadows Start Value")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsStart, "Shadows Start", "SMH Shadows Start Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsEnd, "SMH Shadows End", "SMH Shadows End Value")
->Attribute(Edit::Attributes::Max, 16.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsEnd, "Shadows End", "SMH Shadows End Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsStart, "SMH Highlights Start", "SMH Highlights Start Value")
->Attribute(Edit::Attributes::Max, 16.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsStart, "Highlights Start", "SMH Highlights Start Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsEnd, "SMH Highlights End", "SMH Highlights End Value")
->Attribute(Edit::Attributes::Max, 16.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsEnd, "Highlights End", "SMH Highlights End Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhShadowsColor, "SMH Shadows Color", "SMH Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhMidtonesColor, "SMH Midtones Color", "SMH Midtones Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhHighlightsColor, "SMH Highlights Color", "SMH Highlights Color")
->Attribute(Edit::Attributes::Max, 16.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhShadowsColor, "Shadows Color", "SMH Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhMidtonesColor, "Midtones Color", "SMH Midtones Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhHighlightsColor, "Highlights Color", "SMH Highlights Color")
->ClassElement(AZ::Edit::ClassElements::Group, "Final Adjustment")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_finalAdjustmentWeight, "Weight", "Weight of final adjustments")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingHueShift, "Hue Shift", "Hue Shift Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingPostSaturation, "Post Saturation", "Post Saturation Value")
->Attribute(Edit::Attributes::Min, -100.0f)
->Attribute(Edit::Attributes::Max, 100.0f)
->ClassElement(AZ::Edit::ClassElements::Group, "LUT Generation")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &HDRColorGradingComponentConfig::m_lutResolution, "LUT Resolution", "Resolution of generated LUT")
->EnumAttribute(LutResolution::Lut16x16x16, "16x16x16")
->EnumAttribute(LutResolution::Lut32x32x32, "32x32x32")
->EnumAttribute(LutResolution::Lut64x64x64, "64x64x64")
->DataElement(Edit::UIHandlers::ComboBox, &HDRColorGradingComponentConfig::m_shaperPresetType,
"Shaper Type", "Shaper Type.")
->EnumAttribute(ShaperPresetType::None, "None")
->EnumAttribute(ShaperPresetType::LinearCustomRange, "Linear Custom Range")
->EnumAttribute(ShaperPresetType::Log2_48Nits, "Log2 48 nits")
->EnumAttribute(ShaperPresetType::Log2_1000Nits, "Log2 1000 nits")
->EnumAttribute(ShaperPresetType::Log2_2000Nits, "Log2 2000 nits")
->EnumAttribute(ShaperPresetType::Log2_4000Nits, "Log2 4000 nits")
->EnumAttribute(ShaperPresetType::Log2CustomRange, "Log2 Custom Range")
->EnumAttribute(ShaperPresetType::PqSmpteSt2084, "PQ (SMPTE ST 2084)")
;
}
}
@@ -136,6 +190,120 @@ namespace AZ
{
}
void EditorHDRColorGradingComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
if (m_waitOneFrame)
{
m_waitOneFrame = false;
return;
}
const char* LutAttachment = "LutOutput";
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{ "LutGenerationPass" };
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZStd::string lutGenerationCacheFolder;
AzFramework::StringFunc::Path::GetFolderPath(resolvedOutputFilePath, lutGenerationCacheFolder);
AZ::IO::SystemFile::CreateDir(lutGenerationCacheFolder.c_str());
bool startedCapture = false;
AZ::Render::FrameCaptureRequestBus::BroadcastResult(
startedCapture,
&AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachment,
LutGenerationPassHierarchy,
AZStd::string(LutAttachment),
m_currentTiffFilePath,
AZ::RPI::PassAttachmentReadbackOption::Output);
if (startedCapture)
{
AZ::TickBus::Handler::BusDisconnect();
AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect();
}
}
void EditorHDRColorGradingComponent::OnCaptureFinished([[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]]const AZStd::string& info)
{
char resolvedInputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedInputFilePath, AZ_MAX_PATH_LEN);
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentLutFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZStd::string lutGenerationFolder;
AzFramework::StringFunc::Path::GetFolderPath(resolvedOutputFilePath, lutGenerationFolder);
AZ::IO::SystemFile::CreateDir(lutGenerationFolder.c_str());
AZStd::vector<AZStd::string_view> pythonArgs
{
"--i", resolvedInputFilePath,
"--o", resolvedOutputFilePath
};
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
TiffToAzassetPythonScriptPath,
pythonArgs);
m_controller.m_configuration.m_generateLut = false;
m_controller.OnConfigChanged();
m_generatedLutAbsolutePath = resolvedOutputFilePath + AZStd::string(".azasset");
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(
&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh,
AzToolsFramework::PropertyModificationRefreshLevel::Refresh_EntireTree);
AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
}
void EditorHDRColorGradingComponent::GenerateLut()
{
// turn on lut generation pass
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
m_currentTiffFilePath = AZStd::string::format(TempTiffFilePath, uuidString.c_str());
m_currentLutFilePath = "@projectroot@/" + AZStd::string::format(GeneratedLutRelativePath, uuidString.c_str());
m_controller.SetGenerateLut(true);
m_controller.OnConfigChanged();
m_waitOneFrame = true;
AZ::TickBus::Handler::BusConnect();
}
AZ::u32 EditorHDRColorGradingComponent::ActivateLut()
{
using namespace AzFramework::StringFunc::Path;
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, GetEntityId());
AZStd::string filename;
GetFileName(m_generatedLutAbsolutePath.c_str(), filename);
AZStd::string assetRelativePath = "LutGeneration/" + filename + ".azasset";
AZStd::vector<AZStd::string_view> pythonArgs
{
"--entityName", entityName,
"--assetRelativePath", assetRelativePath
};
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
ActivateLutAssetPythonScriptPath,
pythonArgs);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
bool EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings()
{
return !m_generatedLutAbsolutePath.empty();
}
u32 EditorHDRColorGradingComponent::OnConfigurationChanged()
{
m_controller.OnConfigChanged();
@@ -8,16 +8,25 @@
#pragma once
#include <AzCore/Component/TickBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentAdapter.h>
#include <Atom/Feature/Utils/FrameCaptureBus.h>
#include <PostProcess/ColorGrading/HDRColorGradingComponent.h>
namespace AZ
{
namespace Render
{
static constexpr const char* const TempTiffFilePath{ "@usercache@/LutGeneration/SavedLut_%s.tiff" };
static constexpr const char* const GeneratedLutRelativePath = { "LutGeneration/SavedLut_%s" };
static constexpr const char* const TiffToAzassetPythonScriptPath{ "@engroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py" };
static constexpr const char* const ActivateLutAssetPythonScriptPath{ "@engroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py" };
class EditorHDRColorGradingComponent final
: public AzToolsFramework::Components::
EditorComponentAdapter<HDRColorGradingComponentController, HDRColorGradingComponent, HDRColorGradingComponentConfig>
, private TickBus::Handler
, private FrameCaptureNotificationBus::Handler
{
public:
using BaseClass = AzToolsFramework::Components::EditorComponentAdapter<HDRColorGradingComponentController, HDRColorGradingComponent, HDRColorGradingComponentConfig>;
@@ -30,6 +39,23 @@ namespace AZ
//! EditorRenderComponentAdapter overrides...
AZ::u32 OnConfigurationChanged() override;
private:
// AZ::TickBus overrides ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// FrameCaptureNotificationBus overrides ...
void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override;
void GenerateLut();
AZ::u32 ActivateLut();
bool GetGeneratedLutVisibilitySettings();
bool m_waitOneFrame = false;
AZStd::string m_currentTiffFilePath;
AZStd::string m_currentLutFilePath;
AZStd::string m_generatedLutAbsolutePath;
};
} // namespace Render
} // namespace AZ
@@ -52,6 +52,7 @@ namespace AZ
void HDRColorGradingComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("HDRColorGradingService"));
incompatible.push_back(AZ_CRC_CE("LookModificationService"));
}
void HDRColorGradingComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
@@ -49,12 +49,12 @@ namespace AZ
void LookModificationComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("LookModificationService", 0x207b7539));
provided.push_back(AZ_CRC_CE("LookModificationService"));
}
void LookModificationComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("LookModificationService", 0x207b7539));
incompatible.push_back(AZ_CRC("LookModificationService"));
}
void LookModificationComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
@@ -0,0 +1,173 @@
/*
* 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 <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
#include <Atom/Feature/Utils/LightingPreset.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/MatrixUtils.h>
#include <AzCore/Math/Transform.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <SharedPreview/SharedPreviewContent.h>
namespace AZ
{
namespace LyIntegration
{
SharedPreviewContent::SharedPreviewContent(
RPI::ScenePtr scene,
RPI::ViewPtr view,
AZ::Uuid entityContextId,
const Data::AssetId& modelAssetId,
const Data::AssetId& materialAssetId,
const Data::AssetId& lightingPresetAssetId,
const Render::MaterialPropertyOverrideMap& materialPropertyOverrides)
: m_scene(scene)
, m_view(view)
, m_entityContextId(entityContextId)
, m_materialPropertyOverrides(materialPropertyOverrides)
{
// Create preview model
AzFramework::EntityContextRequestBus::EventResult(
m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "SharedPreviewContentModel");
m_modelEntity->CreateComponent(Render::MeshComponentTypeId);
m_modelEntity->CreateComponent(Render::MaterialComponentTypeId);
m_modelEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
m_modelEntity->Init();
m_modelEntity->Activate();
m_modelAsset.Create(modelAssetId);
m_materialAsset.Create(materialAssetId);
m_lightingPresetAsset.Create(lightingPresetAssetId);
}
SharedPreviewContent::~SharedPreviewContent()
{
if (m_modelEntity)
{
m_modelEntity->Deactivate();
AzFramework::EntityContextRequestBus::Event(
m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity);
m_modelEntity = nullptr;
}
}
void SharedPreviewContent::Load()
{
m_modelAsset.QueueLoad();
m_materialAsset.QueueLoad();
m_lightingPresetAsset.QueueLoad();
}
bool SharedPreviewContent::IsReady() const
{
return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) &&
(!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) &&
(!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady());
}
bool SharedPreviewContent::IsError() const
{
return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError();
}
void SharedPreviewContent::ReportErrors()
{
AZ_Warning(
"SharedPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s",
m_modelAsset.ToString<AZStd::string>().c_str());
AZ_Warning(
"SharedPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s",
m_materialAsset.ToString<AZStd::string>().c_str());
AZ_Warning(
"SharedPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(),
"Asset failed to load in time: %s", m_lightingPresetAsset.ToString<AZStd::string>().c_str());
}
void SharedPreviewContent::Update()
{
UpdateModel();
UpdateLighting();
UpdateCamera();
}
void SharedPreviewContent::UpdateModel()
{
Render::MeshComponentRequestBus::Event(
m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset);
Render::MaterialComponentRequestBus::Event(
m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetMaterialOverride,
Render::DefaultMaterialAssignmentId, m_materialAsset.GetId());
Render::MaterialComponentRequestBus::Event(
m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetPropertyOverrides,
Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides);
}
void SharedPreviewContent::UpdateLighting()
{
if (m_lightingPresetAsset.IsReady())
{
auto preset = m_lightingPresetAsset->GetDataAs<Render::LightingPreset>();
if (preset)
{
auto iblFeatureProcessor = m_scene->GetFeatureProcessor<Render::ImageBasedLightFeatureProcessorInterface>();
auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId());
auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface();
auto directionalLightFeatureProcessor =
m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor<Render::SkyBoxFeatureProcessorInterface>();
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<Render::DirectionalLightFeatureProcessorInterface::LightHandle> lightHandles;
preset->ApplyLightingPreset(
iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor,
cameraConfig, lightHandles);
}
}
}
void SharedPreviewContent::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 = {};
if (m_modelAsset.IsReady())
{
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::CreateLookAt(cameraPosition, center);
m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform));
}
} // namespace LyIntegration
} // namespace AZ
@@ -0,0 +1,67 @@
/*
* 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/Feature/Material/MaterialAssignment.h>
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <AtomToolsFramework/PreviewRenderer/PreviewContent.h>
namespace AZ
{
namespace LyIntegration
{
//! Creates a simple scene used for most previews and thumbnails
class SharedPreviewContent final : public AtomToolsFramework::PreviewContent
{
public:
AZ_CLASS_ALLOCATOR(SharedPreviewContent, AZ::SystemAllocator, 0);
SharedPreviewContent(
RPI::ScenePtr scene,
RPI::ViewPtr view,
AZ::Uuid entityContextId,
const Data::AssetId& modelAssetId,
const Data::AssetId& materialAssetId,
const Data::AssetId& lightingPresetAssetId,
const Render::MaterialPropertyOverrideMap& materialPropertyOverrides);
~SharedPreviewContent() override;
void Load() override;
bool IsReady() const override;
bool IsError() const override;
void ReportErrors() override;
void Update() override;
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;
Data::Asset<RPI::ModelAsset> m_modelAsset;
Data::Asset<RPI::MaterialAsset> m_materialAsset;
Data::Asset<RPI::AnyAsset> m_lightingPresetAsset;
Render::MaterialPropertyOverrideMap m_materialPropertyOverrides;
};
} // namespace LyIntegration
} // namespace AZ
@@ -11,37 +11,42 @@
#include <AssetBrowser/Thumbnails/SourceThumbnail.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Thumbnails/ThumbnailUtils.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <SharedPreview/SharedPreviewUtils.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
namespace SharedPreviewUtils
{
Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType)
Data::AssetId GetAssetId(
AzToolsFramework::Thumbnailer::SharedThumbnailKey key,
const Data::AssetType& assetType,
const Data::AssetId& defaultAssetId)
{
static const Data::AssetId invalidAssetId;
// if it's a source thumbnail key, find first product with a matching asset type
auto sourceKey = azrtti_cast<const AzToolsFramework::AssetBrowser::SourceThumbnailKey*>(key.data());
if (sourceKey)
{
bool foundIt = false;
AZStd::vector<Data::AssetInfo> productsAssetInfo;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo);
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID,
sourceKey->GetSourceUuid(), productsAssetInfo);
if (!foundIt)
{
return invalidAssetId;
return defaultAssetId;
}
auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(),
auto assetInfoIt = AZStd::find_if(
productsAssetInfo.begin(), productsAssetInfo.end(),
[&assetType](const Data::AssetInfo& assetInfo)
{
return assetInfo.m_assetType == assetType;
});
if (assetInfoIt == productsAssetInfo.end())
{
return invalidAssetId;
return defaultAssetId;
}
return assetInfoIt->m_assetId;
@@ -53,10 +58,9 @@ namespace AZ
{
return productKey->GetAssetId();
}
return invalidAssetId;
return defaultAssetId;
}
QString WordWrap(const QString& string, int maxLength)
{
QString result;
@@ -81,6 +85,32 @@ namespace AZ
}
return result;
}
} // namespace Thumbnails
AZStd::unordered_set<AZ::Uuid> GetSupportedAssetTypes()
{
return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() };
}
bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
{
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
{
const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId);
if (assetId.IsValid())
{
if (typeId == RPI::AnyAsset::RTTI_Type())
{
AZ::Data::AssetInfo assetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId);
return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset");
}
return true;
}
}
return false;
}
} // namespace SharedPreviewUtils
} // namespace LyIntegration
} // namespace AZ
@@ -18,13 +18,23 @@ namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
namespace SharedPreviewUtils
{
//! Get assetId by assetType that belongs to either source or product thumbnail key
Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType);
Data::AssetId GetAssetId(
AzToolsFramework::Thumbnailer::SharedThumbnailKey key,
const Data::AssetType& assetType,
const Data::AssetId& defaultAssetId = {});
//! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed
//! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word
//! wrap needed
QString WordWrap(const QString& string, int maxLength);
} // namespace Thumbnails
//! Get the set of all asset types supported by the shared preview
AZStd::unordered_set<AZ::Uuid> GetSupportedAssetTypes();
//! Determine if a thumbnail key has an asset supported by the shared preview
bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
} // namespace SharedPreviewUtils
} // namespace LyIntegration
} // namespace AZ
@@ -7,23 +7,21 @@
*/
#include <AzCore/IO/FileIO.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <Source/Thumbnails/Preview/CommonPreviewer.h>
#include <Source/Thumbnails/ThumbnailUtils.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <SharedPreview/SharedPreviewUtils.h>
#include <SharedPreview/SharedPreviewer.h>
// 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 <Source/Thumbnails/Preview/ui_CommonPreviewer.h>
#include <QString>
#include <QResizeEvent>
#include <QString>
#include <SharedPreview/ui_SharedPreviewer.h>
AZ_POP_DISABLE_WARNING
namespace AZ
@@ -32,18 +30,22 @@ namespace AZ
{
static constexpr int CharWidth = 6;
CommonPreviewer::CommonPreviewer(QWidget* parent)
SharedPreviewer::SharedPreviewer(QWidget* parent)
: Previewer(parent)
, m_ui(new Ui::CommonPreviewerClass())
, m_ui(new Ui::SharedPreviewerClass())
{
m_ui->setupUi(this);
}
CommonPreviewer::~CommonPreviewer()
SharedPreviewer::~SharedPreviewer()
{
}
void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
void SharedPreviewer::Clear() const
{
}
void SharedPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
using namespace AzToolsFramework::AssetBrowser;
using namespace AzToolsFramework::Thumbnailer;
@@ -54,23 +56,23 @@ namespace AZ
UpdateFileInfo();
}
const QString& CommonPreviewer::GetName() const
const QString& SharedPreviewer::GetName() const
{
return m_name;
}
void CommonPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event)
void SharedPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event)
{
m_ui->m_previewWidget->setMaximumHeight(m_ui->m_previewWidget->width());
UpdateFileInfo();
}
void CommonPreviewer::UpdateFileInfo() const
void SharedPreviewer::UpdateFileInfo() const
{
m_ui->m_fileInfoLabel->setText(Thumbnails::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth));
m_ui->m_fileInfoLabel->setText(SharedPreviewUtils::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth));
}
} // namespace LyIntegration
} // namespace AZ
#include <Source/Thumbnails/Preview/moc_CommonPreviewer.cpp>
#include <SharedPreview/moc_SharedPreviewer.cpp>
@@ -5,22 +5,23 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/AssetBrowser/Previewer/Previewer.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QWidget>
#include <QScopedPointer>
#include <QWidget>
AZ_POP_DISABLE_WARNING
#endif
namespace Ui
{
class CommonPreviewerClass;
class SharedPreviewerClass;
}
namespace AzToolsFramework
@@ -30,8 +31,8 @@ namespace AzToolsFramework
class ProductAssetBrowserEntry;
class SourceAssetBrowserEntry;
class AssetBrowserEntry;
}
}
} // namespace AssetBrowser
} // namespace AzToolsFramework
class QResizeEvent;
@@ -39,18 +40,17 @@ namespace AZ
{
namespace LyIntegration
{
class CommonPreviewer final
: public AzToolsFramework::AssetBrowser::Previewer
class SharedPreviewer final : public AzToolsFramework::AssetBrowser::Previewer
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(CommonPreviewer, AZ::SystemAllocator, 0);
AZ_CLASS_ALLOCATOR(SharedPreviewer, AZ::SystemAllocator, 0);
explicit CommonPreviewer(QWidget* parent = nullptr);
~CommonPreviewer();
explicit SharedPreviewer(QWidget* parent = nullptr);
~SharedPreviewer();
// AzToolsFramework::AssetBrowser::Previewer overrides...
void Clear() const override {}
void Clear() const override;
void Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) override;
const QString& GetName() const override;
@@ -60,9 +60,9 @@ namespace AZ
private:
void UpdateFileInfo() const;
QScopedPointer<Ui::CommonPreviewerClass> m_ui;
QScopedPointer<Ui::SharedPreviewerClass> m_ui;
QString m_fileInfo;
QString m_name = "CommonPreviewer";
QString m_name = "SharedPreviewer";
};
} // namespace LyIntegration
} // namespace AZ
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CommonPreviewerClass</class>
<widget class="QWidget" name="CommonPreviewerClass">
<class>SharedPreviewerClass</class>
<widget class="QWidget" name="SharedPreviewerClass">
<property name="geometry">
<rect>
<x>0</x>
@@ -0,0 +1,33 @@
/*
* 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 <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <SharedPreview/SharedPreviewUtils.h>
#include <SharedPreview/SharedPreviewer.h>
#include <SharedPreview/SharedPreviewerFactory.h>
namespace AZ
{
namespace LyIntegration
{
AzToolsFramework::AssetBrowser::Previewer* SharedPreviewerFactory::CreatePreviewer(QWidget* parent) const
{
return new SharedPreviewer(parent);
}
bool SharedPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
{
return SharedPreviewUtils::IsSupportedAssetType(entry->GetThumbnailKey());
}
const QString& SharedPreviewerFactory::GetName() const
{
return m_name;
}
} // namespace LyIntegration
} // namespace AZ
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/SystemAllocator.h>
@@ -18,14 +19,13 @@ namespace AZ
{
namespace LyIntegration
{
class CommonPreviewerFactory final
: public AzToolsFramework::AssetBrowser::PreviewerFactory
class SharedPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory
{
public:
AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0);
AZ_CLASS_ALLOCATOR(SharedPreviewerFactory, AZ::SystemAllocator, 0);
CommonPreviewerFactory() = default;
~CommonPreviewerFactory() = default;
SharedPreviewerFactory() = default;
~SharedPreviewerFactory() = default;
// AzToolsFramework::AssetBrowser::PreviewerFactory overrides...
AzToolsFramework::AssetBrowser::Previewer* CreatePreviewer(QWidget* parent = nullptr) const override;
@@ -33,7 +33,7 @@ namespace AZ
const QString& GetName() const override;
private:
QString m_name = "CommonPreviewer";
QString m_name = "SharedPreviewer";
};
} // namespace LyIntegration
} // namespace AZ
@@ -0,0 +1,106 @@
/*
* 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 <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <QtConcurrent/QtConcurrent>
#include <SharedPreview/SharedPreviewUtils.h>
#include <SharedPreview/SharedThumbnail.h>
namespace AZ
{
namespace LyIntegration
{
static constexpr const int SharedThumbnailSize = 256;
//////////////////////////////////////////////////////////////////////////
// SharedThumbnail
//////////////////////////////////////////////////////////////////////////
SharedThumbnail::SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
: Thumbnail(key)
{
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
{
const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId);
if (assetId.IsValid())
{
m_assetId = assetId;
m_typeId = typeId;
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
return;
}
}
AZ_Error("SharedThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
m_state = State::Failed;
}
void SharedThumbnail::LoadThread()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, SharedThumbnailSize);
// wait for response from thumbnail renderer
m_renderWait.acquire();
}
SharedThumbnail::~SharedThumbnail()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
void SharedThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage)
{
m_pixmap = thumbnailImage;
m_renderWait.release();
}
void SharedThumbnail::ThumbnailFailedToRender()
{
m_state = State::Failed;
m_renderWait.release();
}
void SharedThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
{
if (m_assetId == assetId && m_state == State::Ready)
{
m_state = State::Unloaded;
Load();
}
}
//////////////////////////////////////////////////////////////////////////
// SharedThumbnailCache
//////////////////////////////////////////////////////////////////////////
SharedThumbnailCache::SharedThumbnailCache()
: ThumbnailCache<SharedThumbnail>()
{
}
SharedThumbnailCache::~SharedThumbnailCache() = default;
int SharedThumbnailCache::GetPriority() const
{
// Custom thumbnails have a higher priority to override default source thumbnails
return 1;
}
const char* SharedThumbnailCache::GetProviderName() const
{
return ProviderName;
}
bool SharedThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
{
return SharedPreviewUtils::IsSupportedAssetType(key);
}
} // namespace LyIntegration
} // namespace AZ
#include <SharedPreview/moc_SharedThumbnail.cpp>
@@ -0,0 +1,66 @@
/*
* 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
#if !defined(Q_MOC_RUN)
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#endif
namespace AZ
{
namespace LyIntegration
{
//! Custom thumbnail for most common Atom assets
//! Detects asset changes and updates the thumbnail
class SharedThumbnail final
: public AzToolsFramework::Thumbnailer::Thumbnail
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
{
Q_OBJECT
public:
SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
~SharedThumbnail() override;
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
void ThumbnailRendered(const QPixmap& thumbnailImage) override;
void ThumbnailFailedToRender() override;
protected:
void LoadThread() override;
private:
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
AZStd::binary_semaphore m_renderWait;
Data::AssetId m_assetId;
AZ::Uuid m_typeId;
};
//! Cache configuration for shared thumbnails
class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache<SharedThumbnail>
{
public:
SharedThumbnailCache();
~SharedThumbnailCache() override;
int GetPriority() const override;
const char* GetProviderName() const override;
static constexpr const char* ProviderName = "Common Feature Shared Thumbnail Provider";
protected:
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
};
} // namespace LyIntegration
} // namespace AZ
@@ -0,0 +1,75 @@
/*
* 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 <AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h>
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <SharedPreview/SharedPreviewContent.h>
#include <SharedPreview/SharedPreviewUtils.h>
#include <SharedPreview/SharedThumbnailRenderer.h>
namespace AZ
{
namespace LyIntegration
{
SharedThumbnailRenderer::SharedThumbnailRenderer()
{
m_defaultModelAsset.Create(DefaultModelAssetId, true);
m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true);
m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true);
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId);
}
SystemTickBus::Handler::BusConnect();
}
SharedThumbnailRenderer::~SharedThumbnailRenderer()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect();
SystemTickBus::Handler::BusDisconnect();
}
void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize)
{
if (auto previewRenderer = AZ::Interface<AtomToolsFramework::PreviewRendererInterface>::Get())
{
previewRenderer->AddCaptureRequest(
{ thumbnailSize,
AZStd::make_shared<SharedPreviewContent>(
previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(),
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId),
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId),
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId),
Render::MaterialPropertyOverrideMap()),
[thumbnailKey]()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
},
[thumbnailKey](const QPixmap& pixmap)
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap);
} });
}
}
bool SharedThumbnailRenderer::Installed() const
{
return true;
}
void SharedThumbnailRenderer::OnSystemTick()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents();
}
} // namespace LyIntegration
} // namespace AZ
@@ -0,0 +1,57 @@
/*
* 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/Asset/AssetUtils.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <AzCore/Component/TickBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <Thumbnails/Thumbnail.h>
namespace AZ
{
namespace LyIntegration
{
//! Provides custom thumbnail rendering of supported asset types
class SharedThumbnailRenderer final
: public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
, public SystemTickBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(SharedThumbnailRenderer, AZ::SystemAllocator, 0);
SharedThumbnailRenderer();
~SharedThumbnailRenderer();
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;
// Default assets to be kept loaded and used for rendering if not overridden
static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath);
Data::Asset<RPI::AnyAsset> m_defaultLightingPresetAsset;
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath);
Data::Asset<RPI::ModelAsset> m_defaultModelAsset;
static constexpr const char* DefaultMaterialPath = "";
const Data::AssetId DefaultMaterialAssetId;
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
};
} // namespace LyIntegration
} // namespace AZ
@@ -65,7 +65,7 @@ namespace AZ
m_featureProcessorInterface = RPI::Scene::GetFeatureProcessorForEntity<SkyBoxFeatureProcessorInterface>(entityId);
// only activate if there is no other skybox activate
if (!m_featureProcessorInterface->IsEnabled())
if (m_featureProcessorInterface && !m_featureProcessorInterface->IsEnabled())
{
m_featureProcessorInterface->SetSkyboxMode(SkyBoxMode::Cubemap);
m_featureProcessorInterface->Enable(true);
@@ -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
*
*/
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Source/Thumbnails/Preview/CommonPreviewer.h>
#include <Source/Thumbnails/Preview/CommonPreviewerFactory.h>
#include <Source/Thumbnails/ThumbnailUtils.h>
namespace AZ
{
namespace LyIntegration
{
AzToolsFramework::AssetBrowser::Previewer* CommonPreviewerFactory::CreatePreviewer(QWidget* parent) const
{
return new CommonPreviewer(parent);
}
bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
{
return
Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()).IsValid() ||
Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()).IsValid();
}
const QString& CommonPreviewerFactory::GetName() const
{
return m_name;
}
} // namespace LyIntegration
} // namespace AZ
@@ -1,120 +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 <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h>
namespace AZ
{
namespace LyIntegration
{
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();
m_steps[Step::Initialize] = AZStd::make_shared<InitializeStep>(this);
m_steps[Step::FindThumbnailToRender] = AZStd::make_shared<FindThumbnailToRenderStep>(this);
m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared<WaitForAssetsToLoadStep>(this);
m_steps[Step::Capture] = AZStd::make_shared<CaptureStep>(this);
m_steps[Step::ReleaseResources] = AZStd::make_shared<ReleaseResourcesStep>(this);
m_minimalFeatureProcessors =
{
"AZ::Render::TransformServiceFeatureProcessor",
"AZ::Render::MeshFeatureProcessor",
"AZ::Render::SimplePointLightFeatureProcessor",
"AZ::Render::SimpleSpotLightFeatureProcessor",
"AZ::Render::PointLightFeatureProcessor",
// There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
// flickering [ATOM-13568]
// as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
// Possibly re-enable with [GFX TODO][ATOM-13639]
// "AZ::Render::DirectionalLightFeatureProcessor",
"AZ::Render::DiskLightFeatureProcessor",
"AZ::Render::CapsuleLightFeatureProcessor",
"AZ::Render::QuadLightFeatureProcessor",
"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<AZStd::string>& CommonThumbnailRenderer::GetCustomFeatureProcessors() const
{
return m_minimalFeatureProcessors;
}
AZStd::shared_ptr<ThumbnailRendererData> 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);
}
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,69 +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 <AzToolsFramework/Thumbnails/Thumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
// Disables warning messages triggered by the Qt library
// 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 <QPixmap>
AZ_POP_DISABLE_WARNING
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
class ThumbnailRendererStep;
//! Provides custom rendering of material and model thumbnails
class CommonThumbnailRenderer
: public ThumbnailRendererContext
, private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
, private SystemTickBus::Handler
, private ThumbnailFeatureProcessorProviderBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0)
CommonThumbnailRenderer();
~CommonThumbnailRenderer();
//! ThumbnailRendererContext overrides...
void SetStep(Step step) override;
Step GetStep() const override;
AZStd::shared_ptr<ThumbnailRendererData> GetData() const override;
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::ThumbnailFeatureProcessorProviderBus::Handler interface overrides...
const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const override;
AZStd::unordered_map<Step, AZStd::shared_ptr<ThumbnailRendererStep>> m_steps;
Step m_currentStep = Step::None;
AZStd::shared_ptr<ThumbnailRendererData> m_data;
AZStd::vector<AZStd::string> m_minimalFeatureProcessors;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -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 <AzCore/std/smart_ptr/shared_ptr.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
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<ThumbnailRendererData> GetData() const = 0;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -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 <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Math/Transform.h>
#include <AzFramework/Entity/GameEntityContextComponent.h>
#include <Thumbnails/Thumbnail.h>
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<AzFramework::Scene> m_frameworkScene;
RPI::RenderPipelinePtr m_renderPipeline;
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
AZStd::vector<AZStd::string> 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<AzToolsFramework::Thumbnailer::SharedThumbnailKey> m_thumbnailQueue;
//! Current thumbnail key being rendered.
AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered;
Data::Asset<RPI::AnyAsset> m_lightingPresetAsset;
Data::Asset<RPI::ModelAsset> m_defaultModelAsset;
//! Model asset about to be rendered
Data::Asset<RPI::ModelAsset> m_modelAsset;
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
//! Material asset about to be rendered
Data::Asset<RPI::MaterialAsset> m_materialAsset;
AZStd::unordered_set<Data::AssetId> m_assetsToLoad;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,130 +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 <Atom/Feature/Utils/FrameCaptureBus.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/View.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
#include <AzCore/Math/MatrixUtils.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
CaptureStep::CaptureStep(ThumbnailRendererContext* context)
: ThumbnailRendererStep(context)
{
}
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;
TickBus::Handler::BusConnect();
}
void CaptureStep::Stop()
{
m_context->GetData()->m_renderPipeline->RemoveFromRenderTick();
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)
{
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)
{
m_readyToCapture = false;
}
}
}
void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info)
{
m_context->SetStep(Step::FindThumbnailToRender);
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,55 +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/Feature/Utils/FrameCaptureBus.h>
#include <AzCore/Component/TickBus.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
//! CaptureStep renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished
class CaptureStep
: public ThumbnailRendererStep
, private TickBus::Handler
, private Render::FrameCaptureNotificationBus::Handler
{
public:
CaptureStep(ThumbnailRendererContext* context);
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;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,79 +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 <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Thumbnails/ThumbnailUtils.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context)
: ThumbnailRendererStep(context)
{
}
void FindThumbnailToRenderStep::Start()
{
TickBus::Handler::BusConnect();
}
void FindThumbnailToRenderStep::Stop()
{
TickBus::Handler::BusDisconnect();
}
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);
}
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,40 +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 <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
//! FindThumbnailToRenderStep checks whether there are any new thumbnails that need to be rendered every tick
class FindThumbnailToRenderStep
: public ThumbnailRendererStep
, private TickBus::Handler
{
public:
FindThumbnailToRenderStep(ThumbnailRendererContext* context);
void Start() override;
void Stop() override;
private:
//! AZ::TickBus::Handler interface overrides...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
void PickNextThumbnail();
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -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 <AzCore/Math/MatrixUtils.h>
#include <AzCore/EBus/Results.h>
#include <AzFramework/Components/TransformComponent.h>
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
#include <Atom/Feature/Utils/LightingPreset.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
#include <Atom/RPI.Reflect/System/SceneDescriptor.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h>
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<AzFramework::EntityContext>();
data->m_entityContext->InitContext();
// Create and register a scene with all required feature processors
RPI::SceneDescriptor sceneDesc;
AZ::EBusAggregateResults<AZStd::vector<AZStd::string>> results;
ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors);
AZStd::set<AZStd::string> 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::shared_ptr<AzFramework::Scene>, 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<AZ::RPI::AnyAsset>(ThumbnailRendererData::LightingPresetPath);
if (data->m_lightingPresetAsset.IsReady())
{
auto preset = data->m_lightingPresetAsset->GetDataAs<Render::LightingPreset>();
if (preset)
{
auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::ImageBasedLightFeatureProcessorInterface>();
auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface();
auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::SkyBoxFeatureProcessorInterface>();
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<Render::DirectionalLightFeatureProcessorInterface::LightHandle> 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<AzFramework::TransformComponent>());
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
@@ -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 <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
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
@@ -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 <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/Scene.h>
#include <AzFramework/Scene/Scene.h>
#include <AzFramework/Scene/SceneSystemInterface.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h>
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
@@ -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 <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
class ReleaseResourcesStep
: public ThumbnailRendererStep
{
public:
ReleaseResourcesStep(ThumbnailRendererContext* context);
void Start() override;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -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
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
class ThumbnailRendererContext;
//! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces
class ThumbnailRendererStep
{
public:
explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {}
virtual ~ThumbnailRendererStep() = default;
//! Start is called when step begins execution
virtual void Start() {}
//! Stop is called when step ends execution
virtual void Stop() {}
protected:
ThumbnailRendererContext* m_context;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,101 +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 "Thumbnails/ThumbnailerBus.h"
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context)
: ThumbnailRendererStep(context)
{
}
void WaitForAssetsToLoadStep::Start()
{
LoadNextAsset();
}
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<Data::AssetData> asset)
{
Data::AssetBus::Handler::BusDisconnect();
LoadNextAsset();
}
void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset<Data::AssetData> 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)
{
auto assetIdStr = m_assetId.ToString<AZStd::string>();
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);
}
}
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -1,50 +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 <AzCore/Asset/AssetCommon.h>
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
//! 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);
void Start() override;
void Stop() override;
private:
void LoadNextAsset();
// AZ::Data::AssetBus::Handler
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
void OnAssetError(Data::Asset<Data::AssetData> 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;
};
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -7,9 +7,9 @@
#
set(FILES
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h
Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h
Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h
Source/Module.cpp
Source/Animation/EditorAttachmentComponent.h
Source/Animation/EditorAttachmentComponent.cpp
@@ -45,8 +45,6 @@ set(FILES
Source/Material/EditorMaterialSystemComponent.h
Source/Material/MaterialBrowserInteractions.h
Source/Material/MaterialBrowserInteractions.cpp
Source/Material/MaterialThumbnail.cpp
Source/Material/MaterialThumbnail.h
Source/Mesh/EditorMeshComponent.h
Source/Mesh/EditorMeshComponent.cpp
Source/Mesh/EditorMeshStats.h
@@ -55,8 +53,6 @@ set(FILES
Source/Mesh/EditorMeshSystemComponent.h
Source/Mesh/EditorMeshStatsSerializer.cpp
Source/Mesh/EditorMeshStatsSerializer.h
Source/Mesh/MeshThumbnail.h
Source/Mesh/MeshThumbnail.cpp
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp
Source/PostProcess/EditorPostFxLayerComponent.cpp
@@ -95,28 +91,19 @@ set(FILES
Source/SkyBox/EditorHDRiSkyboxComponent.h
Source/SkyBox/EditorPhysicalSkyComponent.cpp
Source/SkyBox/EditorPhysicalSkyComponent.h
Source/Thumbnails/ThumbnailUtils.h
Source/Thumbnails/ThumbnailUtils.cpp
Source/Thumbnails/Preview/CommonPreviewer.cpp
Source/Thumbnails/Preview/CommonPreviewer.h
Source/Thumbnails/Preview/CommonPreviewer.ui
Source/Thumbnails/Preview/CommonPreviewerFactory.cpp
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/SharedPreview/SharedPreviewer.cpp
Source/SharedPreview/SharedPreviewer.h
Source/SharedPreview/SharedPreviewer.ui
Source/SharedPreview/SharedPreviewerFactory.cpp
Source/SharedPreview/SharedPreviewerFactory.h
Source/SharedPreview/SharedPreviewContent.cpp
Source/SharedPreview/SharedPreviewContent.h
Source/SharedPreview/SharedPreviewUtils.cpp
Source/SharedPreview/SharedPreviewUtils.h
Source/SharedPreview/SharedThumbnail.cpp
Source/SharedPreview/SharedThumbnail.h
Source/SharedPreview/SharedThumbnailRenderer.cpp
Source/SharedPreview/SharedThumbnailRenderer.h
Source/Scripting/EditorEntityReferenceComponent.cpp
Source/Scripting/EditorEntityReferenceComponent.h
Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp
@@ -1,6 +1,6 @@
{
"Source" : "ImGuiAtom",
"Source" : "ImGuiAtom.azsl",
"RasterState" : { "CullMode" : "None" },
@@ -4,18 +4,18 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
# -- This line is 75 characters -------------------------------------------
# -------------------------------------------------------------------------
# Sets up the project environment for python scripting using the
export DYNACONF_COMPANY=Amazon
# if a lumberyard project isn't set use this gem
export DYNACONF_LY_PROJECT=DccScriptingInterface
export DYNACONF_LY_PROJECT_PATH=`pwd`
export DYNACONF_LY_DEV=${LY_PROJECT_PATH}\..\..\..\..
# if a O3DE project isn't set use this gem
export DYNACONF_O3DE_PROJECT=DccScriptingInterface
export DYNACONF_O3DE_PROJECT_PATH=`pwd`
export DYNACONF_O3DE_DEV=${O3DE_PROJECT_PATH}\..\..\..\..
# LY build folder
export DYNACONF_LY_BUILD_PATH=${LY_DEV}\build
export DYNACONF_LY_BIN_PATH=${LY_BUILD_PATH}\bin\profile
export DYNACONF_O3DE_BUILD_PATH=${O3DE_DEV}\build
export DYNACONF_O3DE_BIN_PATH=${O3DE_BUILD_PATH}\bin\profile
# default IDE and debug settings
#export DYNACONF_DCCSI_GDEBUG=false
@@ -24,9 +24,9 @@ export DYNACONF_DCCSI_GDEBUGGER=WING
export DYNACONF_DCCSI_LOGLEVEL=20
# defaults for DccScriptingInterface (DCCsi)
export DYNACONF_DCCSIG_PATH=${LY_DEV}\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface
export DYNACONF_DCCSIG_PATH=${O3DE_DEV}\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface
# set up default python interpreter (Lumberyard)
# set up default python interpreter (O3DE)
# we may want to entirely remove these and rely on config.py to dynamically set up
# however VScode can be configured with a .env so might be valueable to keep
export DYNACONF_DCCSI_PY_VERSION_MAJOR=3
@@ -40,13 +40,13 @@ export DYNACONF_DCCSI_PYTHON_PATH=${DCCSIG_PATH}\3rdParty\Python
export DYNACONF_DCCSI_PYTHON_LIB_PATH=${DCCSI_PYTHON_PATH}\Lib\${DCCSI_PY_VERSION_MAJOR}.x\${DCCSI_PY_VERSION_MAJOR}.${DCCSI_PY_VERSION_MINOR}.x\site-packages
# TO DO: figure out how to best deal with OS folder (i.e. 'windows')
export DYNACONF_DCCSI_PYTHON_INSTALL=${LY_DEV}\python
export DYNACONF_DDCCSI_PY_BASE=${DCCSI_PYTHON_INSTALL}\python.cmd
export DYNACONF_O3DE_PYTHON_INSTALL=${O3DE_DEV}\python
export DYNACONF_DCCSI_PY_BASE=${O3DE_PYTHON_INSTALL}\python.cmd
# set up Qt / PySide2
# TO DO: These should NOT be set in the global env as they will cause conflicts
# with other Qt apps (like DCC tools), only set in local.env, or modify config.py
# for utils/tools/apps that need them ( see config.init_ly_pyside() )
#export DYNACONF_QTFORPYTHON_PATH=${LY_DEV}\Gems\QtForPython\3rdParty\pyside2\windows\release
#export DYNACONF_QT_PLUGIN_PATH=${LY_BUILD_PATH}\bin\profile\EditorPlugins
#export DYNACONF_QT_QPA_PLATFORM_PLUGIN_PATH=${LY_BUILD_PATH}\bin\profile\EditorPlugins\platforms
#export DYNACONF_QTFORPYTHON_PATH=${O3DE_DEV}\Gems\QtForPython\3rdParty\pyside2\windows\release
#export DYNACONF_QT_PLUGIN_PATH=${O3DE_BUILD_PATH}\bin\profile\EditorPlugins
#export DYNACONF_QT_QPA_PLATFORM_PLUGIN_PATH=${O3DE_BUILD_PATH}\bin\profile\EditorPlugins\platforms
@@ -8,4 +8,6 @@ workspace.xml
# Ignore dynaconf secret files
.secrets.*
settings.local.json
azpy/_sample_package_/*
azpy/_sample_package_/*
.env
settings_export.json.tmp
@@ -19,3 +19,4 @@ __WIP__/*
!.gitignore
.secrets.*
settings.local.json
.env
@@ -0,0 +1,36 @@
DccScriptingInterface (DCCsi)
This location can be extended with additional 3rdParty Python Utils, Tools, Packages, etc.
These are not installed or distributed with O3DE
However, there is some stubbed scaffolding in place.
This is a bootstrapped sandbox for installing python libs (version bootstrapped procedurally):
C:\Depot\o3de-engine\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python\Lib\2.x\2.7.x\site-packages
C:\Depot\o3de-engine\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python\Lib\3.x\3.7.x\site-packages
Any libs installed to this location will be accessible (use at your own risk)
For instance, if you want to add py2.7 compatible libs, for apps like Maya2020:
"C:\Depot\o3de-engine\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Tools\DCC\Maya\readme.txt"
These pyside2-tools can be useful, and they are not pip installed, nor distributed.
C:\Depot\o3de-engine\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python\pyside2-tools
pyside2-tools instructions:
1. clone the repo in this location: C:\Depot\o3de-engine\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python
>git clone https://github.com/pyside/pyside2-tools
2. to use as a python package ...
find this and copy:
"< local DCCsi >\3rdParty\Python\pyside2-tools\pyside2uic\__init__.py.in"
and rename to this:
"< local DCCsi >\3rdParty\Python\pyside2-tools\pyside2uic\__init__.py"
3. add to PYTHONPATH: < local DCCsi >\3rdParty\Python
in .py something like: site.addsitedir(DCCSI_PYSIDE2_TOOLS)
See: "< local DCCsi >\config.py"
@@ -7,9 +7,9 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
# -- This line is 75 characters -------------------------------------------
# -------------------------------------------------------------------------
"""This module is for use in boostrapping the DccScriptingInterface Gem
with Lumberyard. Note: this boostrap is only designed fo be py3 compatible.
with O3DE. Note: this boostrap is only designed fo be py3 compatible.
If you need DCCsi access in py27 (Autodesk Maya for instance) you may need
to implement your own boostrapper module. Currently this is boostrapped
from add_dccsi.py, as a temporty measure related to this Jira:
@@ -24,40 +24,64 @@ import logging as _logging
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
_O3DE_RUNNING=None
try:
import azlmbr
_O3DE_RUNNING=True
except:
_O3DE_RUNNING=False
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# we don't use dynaconf setting here as we might not yet have access
# to that site-dir.
_MODULE = 'DCCsi.bootstrap'
_MODULENAME = __name__
if _MODULENAME is '__main__':
_MODULENAME = 'O3DE.DCCsi.bootstrap'
# set up module logging
for handler in _logging.root.handlers[:]:
_logging.root.removeHandler(handler)
_LOGGER = _logging.getLogger(_MODULENAME)
# we need to set up basic access to the DCCsi
_MODULE_PATH = os.path.realpath(__file__) # To Do: what if frozen?
_DCCSIG_PATH = os.path.normpath(os.path.join(_MODULE_PATH, '../../..'))
_DCCSIG_PATH = os.getenv('DCCSIG_PATH', _DCCSIG_PATH)
site.addsitedir(_DCCSIG_PATH)
_DCCSI_PATH = os.path.normpath(os.path.join(_MODULE_PATH, '../../..'))
_DCCSI_PATH = os.getenv('DCCSI_PATH', _DCCSI_PATH)
site.addsitedir(_DCCSI_PATH)
# we can get basic access to the DCCsi.azpy api now
import azpy
# now we have azpy api access
from azpy.env_bool import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
from azpy.constants import ENVAR_DCCSI_LOGLEVEL
from azpy.constants import FRMT_LOG_LONG
# early attach WingIDE debugger (can refactor to include other IDEs later)
while 0: # flag on to attemp to connect wingIDE debugger
from azpy.env_bool import env_bool
if not env_bool('DCCSI_DEBUGGER_ATTACHED', False):
# if not already attached lets do it here
from azpy.test.entry_test import connect_wing
foo = connect_wing()
# set up global space, logging etc.
# set these true if you want them set globally for debugging
_DCCSI_GDEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
_DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, False)
_DCCSI_LOGLEVEL = int(env_bool(ENVAR_DCCSI_LOGLEVEL, int(20)))
if _DCCSI_GDEBUG:
_DCCSI_LOGLEVEL = int(10)
_logging.basicConfig(format=FRMT_LOG_LONG, level=_DCCSI_LOGLEVEL)
_LOGGER.debug('Initializing: {0}.'.format({_MODULENAME}))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# settings.setenv() # doing this will add the additional DYNACONF_ envars
def get_dccsi_config(DCCSIG_PATH=_DCCSIG_PATH):
# _settings.setenv() # doing this will add the additional DYNACONF_ envars
def get_dccsi_config(DCCSI_PATH=_DCCSI_PATH):
"""Convenience method to set and retreive settings directly from module."""
# we can go ahead and just make sure the the DCCsi env is set
# config is SO generic this ensures we are importing a specific one
_spec_dccsi_config = importlib.util.spec_from_file_location("dccsi.config",
Path(DCCSIG_PATH,
# _config is SO generic this ensures we are importing a specific one
_spec_dccsi_config = importlib.util.spec_from_file_location("dccsi._config",
Path(DCCSI_PATH,
"config.py"))
_dccsi_config = importlib.util.module_from_spec(_spec_dccsi_config)
_spec_dccsi_config.loader.exec_module(_dccsi_config)
@@ -65,9 +89,12 @@ def get_dccsi_config(DCCSIG_PATH=_DCCSIG_PATH):
return _dccsi_config
# -------------------------------------------------------------------------
# set and retreive the base settings on import
config = get_dccsi_config()
settings = config.get_config_settings()
# set and retreive the base env context/_settings on import
_config = get_dccsi_config()
_settings = _config.get_config_settings()
if _DCCSI_DEV_MODE:
_config.attach_debugger() # attempts to start debugger
# done with basic setup
# --- END -----------------------------------------------------------------
@@ -77,50 +104,99 @@ settings = config.get_config_settings()
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
# -------------------------------------------------------------------------
_O3DE_RUNNING=None
try:
import azlmbr
_O3DE_RUNNING=True
except:
_O3DE_RUNNING=False
# -------------------------------------------------------------------------
_G_DEBUG = False
_G_TEST_PYSIDE = False
_MODULENAME = __name__
if _MODULENAME is '__main__':
_MODULENAME = 'O3DE.DCCsi.bootstrap'
from azpy.constants import STR_CROSSBAR
# module internal debugging flags
while 0: # temp internal debug flag
_DCCSI_GDEBUG = True
break
# overide logger for standalone to be more verbose and log to file
import azpy
_LOGGER = azpy.initialize_logger(_MODULENAME,
log_to_file=_DCCSI_GDEBUG,
default_log_level=_DCCSI_LOGLEVEL)
# happy print
_LOGGER.info(STR_CROSSBAR)
_LOGGER.info('~ constants.py ... Running script as __main__')
_LOGGER.info(STR_CROSSBAR)
# parse the command line args
import argparse
parser = argparse.ArgumentParser(
description='O3DE DCCsi Boostrap (Test)',
epilog="Will externally test the DCCsi boostrap")
_config = get_dccsi_config()
_settings = config.get_config_settings()
_log_level = int(_settings.DCCSI_LOGLEVEL)
if _G_DEBUG:
_log_level = int(10) # force debug level
_LOGGER = azpy.initialize_logger(_MODULE,
log_to_file=True,
default_log_level=_log_level)
_settings = _config.get_config_settings(enable_o3de_python=True,
enable_o3de_pyside2=True)
parser.add_argument('-gd', '--global-debug',
type=bool,
required=False,
help='Enables global debug flag.')
parser.add_argument('-dm', '--developer-mode',
type=bool,
required=False,
help='Enables dev mode for early auto attaching debugger.')
parser.add_argument('-tp', '--test-pyside2',
type=bool,
required=False,
help='Runs Qt/PySide2 tests and reports.')
args = parser.parse_args()
# we can now grab values from the DCCsi.config.py dynamic env settings
# the rest of this block is basic debug testing the dynamic settings at boot
_LOGGER.info(f'Running module: {_MODULE}')
_LOGGER.info(f'DCCSIG_PATH: {_settings.DCCSIG_PATH}')
_LOGGER.info(f'DCCSI_G_DEBUG: {_settings.DCCSI_GDEBUG}')
_LOGGER.info(f'DCCSI_DEV_MODE: {_settings.DCCSI_DEV_MODE}')
_LOGGER.info(f'OS_FOLDER: {_settings.OS_FOLDER}')
_LOGGER.info(f'LY_PROJECT: {_settings.LY_PROJECT}')
_LOGGER.info(f'LY_PROJECT_PATH: {_settings.LY_PROJECT_PATH}')
_LOGGER.info(f'LY_DEV: {_settings.LY_DEV}')
_LOGGER.info(f'LY_BUILD_PATH: {_settings.LY_BUILD_PATH}')
_LOGGER.info(f'LY_BIN_PATH: {_settings.LY_BIN_PATH}')
# easy overrides
if args.global_debug:
_DCCSI_GDEBUG = True
if args.developer_mode:
_DCCSI_DEV_MODE = True
_config.attach_debugger() # attempts to start debugger
_LOGGER.info(f'DCCSIG_PATH: {_settings.DCCSIG_PATH}')
_LOGGER.info(f'DCCSI_PYTHON_LIB_PATH: {_settings.DCCSI_PYTHON_LIB_PATH}')
_LOGGER.info(f'DDCCSI_PY_BASE: {_settings.DDCCSI_PY_BASE}')
if _DCCSI_GDEBUG:
_LOGGER.info(f'DCCSI_PATH: {_settings.DCCSI_PATH}')
_LOGGER.info(f'DCCSI_G_DEBUG: {_settings.DCCSI_GDEBUG}')
_LOGGER.info(f'DCCSI_DEV_MODE: {_settings.DCCSI_DEV_MODE}')
_LOGGER.info(f'DCCSI_OS_FOLDER: {_settings.DCCSI_OS_FOLDER}')
_LOGGER.info(f'O3DE_PROJECT: {_settings.O3DE_PROJECT}')
_LOGGER.info(f'O3DE_PROJECT_PATH: {_settings.O3DE_PROJECT_PATH}')
_LOGGER.info(f'O3DE_DEV: {_settings.O3DE_DEV}')
_LOGGER.info(f'O3DE_BUILD_PATH: {_settings.O3DE_BUILD_PATH}')
_LOGGER.info(f'O3DE_BIN_PATH: {_settings.O3DE_BIN_PATH}')
_LOGGER.info(f'DCCSI_PATH: {_settings.DCCSI_PATH}')
_LOGGER.info(f'DCCSI_PYTHON_LIB_PATH: {_settings.DCCSI_PYTHON_LIB_PATH}')
_LOGGER.info(f'DCCSI_PY_BASE: {_settings.DCCSI_PY_BASE}')
if _G_TEST_PYSIDE:
if _DCCSI_GDEBUG or args.test_pyside2:
try:
import PySide2
except:
# set up Qt/PySide2 access and test
_settings = _config.get_config_settings(setup_ly_pyside=True)
_settings = _config.get_config_settings(enable_o3de_pyside2=True)
import PySide2
_LOGGER.info(f'PySide2: {PySide2}')
_LOGGER.info(f'LY_BIN_PATH: {_settings.LY_BIN_PATH}')
_LOGGER.info(f'O3DE_BIN_PATH: {_settings.O3DE_BIN_PATH}')
_LOGGER.info(f'QT_PLUGIN_PATH: {_settings.QT_PLUGIN_PATH}')
_LOGGER.info(f'QT_QPA_PLATFORM_PLUGIN_PATH: {_settings.QT_QPA_PLATFORM_PLUGIN_PATH}')
_config.test_pyside2()
if not _O3DE_RUNNING:
# return
sys.exit()
# --- END -----------------------------------------------------------------
@@ -0,0 +1,87 @@
"""
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
"""
# -------------------------------------------------------------------------
This folder contains the DccScriptingInterface (DCCsi) for O3DE
Notice: The old \\SDK folder is being replaced with \\Tools
The scripts in \\SDK may be out of data (and not run)
When scripts are finished being updated and refactored into \\Tools the \\SDK will be removed
What is the DCCsi?
- A shared development environment for technical art oriented to working with Python across a number of DCC tools.
- Leverage the existing python ecosystem for technical art.
- Integrate a DCC app like Substance (or Substance SAT api) from the Python driven VFX and Games ecosystem.
- Extend O3DE and unlock its potential for content creators, and the Technical Artists that service them.
Tenets:
(1) Interoperability: Design DCC-agnostic modules and DCC-bespoke modules
to work together efficiently and intuitively.
(2) Encapsulation: Define a module in terms of its essential features and interface to other components,
to facilitate logical layered design and easy maintenance.
(3) Extensibility: Design the tool set to be easily extensible with new functionality and new tools.
Individual pieces should have a generic communication mechanism to allow newly written tools to slot cleanly and transparently into the tool chain.
What is provided (High Level):
- DCC-Agnostic Python Framework (as a modular Gem) related to multiple integrations for:
O3DE Editor (python scripting, utils and PySide2 tools)
DCC applications and their Python APIs/SDKs
Custom standalone tools and utils (python based)
external from cmd line
external standalone
integrated to run within O3DE Editor
What is provided (by folder):
\3rdParty: Allows third party libs/packages to be integrated outside of O3DE
Example: O3DE is py3, Maya 2020 (and earlier) is py27
O3DE provides a patterns for Gems to provide a requirements.txt
See:
DccScriptingInterface\reqiurements.txt
^ These packages will be fetched and installed into O3DE python at build time
This means for some applications like Maya we need another way to add the same packages
See:
DccScriptingInterface\SDK\Maya\readme.txt
DccScriptingInterface\SDK\Maya\requirements.txt
DccScriptingInterface\3rdParty\Python\Lib\2.x\2.7.x\site-packages\*
Packages that reside in 3rdParty are never commited to the repo (only fetched+installed)
\Assets: All O3DE Gems can maintain an asset folder
If a Gem contains an \Asset folder, these assets are folded into the projects asset data
These assets are processed by the Asset Processor for use in the Editor and Runtime
In the DCCsi the \Assets folder primarily contains TestData
\azpy Core (shared) API, A pure python Package and Modules
\Code Contains the bare bones C++ scaffold to build and integrate the Gem with O3DE
Notes: portions of the DCCsi can be utilized outside of O3DE
thus this Gem doens't have to be enabled and built for some use cases
\Editor This folder provides an entry point pattern for extending O3DE Editor with python
When a Gem is enabled ...
If the following if found, it will be executed when the Editor boots:
"Editor\Scripts\bootstrap.py"
This can be used to initialize code access, extend the editor (PySide2), etc.
\Tools This is where the following is maintained:
\Tools\DCC Integration for DCC tools:
configuration of tool (managed env, etc.)
bootstrapping, such as providing the tool access to azpy api code
extensibility, such as adding new functionality or tool to the app
\Tools\DCC\Maya An example of adding a integration for Autodesk Maya
\Tools\Env\Windows This provides a .bat file managed env to configure and bootsrap windows apps
\Tools\Launchers\windows Provides .bat files based tool launchers for windows (accesses env)
@@ -1,132 +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
"""
# -------------------------------------------------------------------------
import pymel.core as pmc
import sys
import types
def syspath():
print 'sys.path:'
for p in sys.path:
print ' ' + p
def info(obj):
"""Prints information about the object."""
lines = ['Info for %s' % obj.name(),
'Attributes:']
# Get the name of all attributes
for a in obj.listAttr():
lines.append(' ' + a.name())
lines.append('MEL type: %s' % obj.type())
lines.append('MRO:')
lines.extend([' ' + t.__name__ for t in type(obj).__mro__])
result = '\n'.join(lines)
print result
def _is_pymel(obj):
try: # (1)
module = obj.__module__ # (2)
except AttributeError: # (3)
try:
module = obj.__name__ # (4)
except AttributeError:
return None # (5)
return module.startswith('pymel') # (6)
def _py_to_helpstr(obj):
if isinstance(obj, basestring):
return 'search.html?q=%s' % (obj.replace(' ', '+'))
if not _is_pymel(obj):
return None
if isinstance(obj, types.ModuleType):
return ('generated/%(module)s.html#module-%(module)s' %
dict(module=obj.__name__))
if isinstance(obj, types.MethodType):
return ('generated/classes/%(module)s/'
'%(module)s.%(typename)s.html'
'#%(module)s.%(typename)s.%(methname)s' % dict(
module=obj.__module__,
typename=obj.im_class.__name__,
methname=obj.__name__))
if isinstance(obj, types.FunctionType):
return ('generated/functions/%(module)s/'
'%(module)s.%(funcname)s.html'
'#%(module)s.%(funcname)s' % dict(
module=obj.__module__,
funcname=obj.__name__))
if not isinstance(obj, type):
obj = type(obj)
return ('generated/classes/%(module)s/'
'%(module)s.%(typename)s.html'
'#%(module)s.%(typename)s' % dict(
module=obj.__module__,
typename=obj.__name__))
def test_py_to_helpstr():
def dotest(obj, ideal):
result = _py_to_helpstr(obj)
assert result == ideal, '%s != %s' % (result, ideal)
dotest('maya rocks', 'search.html?q=maya+rocks')
dotest(pmc.nodetypes,
'generated/pymel.core.nodetypes.html'
'#module-pymel.core.nodetypes')
dotest(pmc.nodetypes.Joint,
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint')
dotest(pmc.nodetypes.Joint(),
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint')
dotest(pmc.nodetypes.Joint().getTranslation,
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint.getTranslation')
dotest(pmc.joint,
'generated/functions/pymel.core.animation/'
'pymel.core.animation.joint.html'
'#pymel.core.animation.joint')
dotest(object(), None)
dotest(10, None)
dotest([], None)
dotest(sys, None)
def test_py_to_helpstrFAIL():
assert 1 == 2, '1 != 2'
import webbrowser # (1)
HELP_ROOT_URL = ('http://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/PyMel/')# (2)
def pmhelp(obj): # (3)
"""Gives help for a pymel or python object.
If obj is not a PyMEL object, use Python's built-in
`help` function.
If obj is a string, open a web browser to a search in the
PyMEL help for the string.
Otherwise, open a web browser to the page for the object.
"""
tail = _py_to_helpstr(obj)
if tail is None:
help(obj) # (4)
else:
webbrowser.open(HELP_ROOT_URL + tail) # (5)
if __name__ == '__main__':
test_py_to_helpstr()
print 'Tests ran successfully.'
@@ -1,85 +0,0 @@
@echo off
REM
REM Copyright (c) Contributors to the Open 3D Engine Project.
REM For complete copyright and license terms please see the LICENSE at the root of this distribution.
REM
REM SPDX-License-Identifier: Apache-2.0 OR MIT
REM
REM
:: Set up and run LY Python CMD prompt
:: Sets up the DccScriptingInterface_Env,
:: Puts you in the CMD within the dev environment
:: Set up window
TITLE Lumberyard DCC Scripting Interface Cmd
:: Use obvious color to prevent confusion (Grey with Yellow Text)
COLOR 8E
%~d0
cd %~dp0
:: Keep changes local
SETLOCAL enableDelayedExpansion
:: This maps up to the \Dev folder
IF "%DEV_REL_PATH%"=="" (set DEV_REL_PATH=..\..\..\..\..\..\..\..\..)
:: Change to root Lumberyard dev dir
:: Don't use the LY_DEV so we can test that ENVAR!!!
CD /d %DEV_REL_PATH%
set Rel_Dev=%CD%
echo Rel_Dev = %Rel_Dev%
:: Restore original directory
popd
set DCCSI_PYTHON_INSTALL=%Rel_Dev%\Tools\Python\3.7.5\windows
:: add to the PATH
SET PATH=%DCCSI_PYTHON_INSTALL%;%PATH%
:: dcc scripting interface gem path
set DCCSIG_PATH=%Rel_Dev%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface
echo DCCSIG_PATH = %DCCSIG_PATH%
:: add to the PATH
SET PATH=%DCCSIG_PATH%;%PATH%
:: Constant Vars (Global)
:: global debug (propogates)
IF "%DCCSI_GDEBUG%"=="" (set DCCSI_GDEBUG=false)
echo DCCSI_GDEBUG = %DCCSI_GDEBUG%
:: initiates debugger connection
IF "%DCCSI_DEV_MODE%"=="" (set DCCSI_DEV_MODE=false)
echo DCCSI_DEV_MODE = %DCCSI_DEV_MODE%
:: sets debugger, options: WING, PYCHARM
IF "%DCCSI_GDEBUGGER%"=="" (set DCCSI_GDEBUGGER=WING)
echo DCCSI_GDEBUGGER = %DCCSI_GDEBUGGER%
echo.
echo _____________________________________________________________________
echo.
echo ~ LY DCCsi, DCC Material Converter
echo _____________________________________________________________________
echo.
:: Change to root dir
CD /D %DCCSIG_PATH%
:: add to the PATH
SET PATH=%DCCSIG_PATH%;%PATH%
set PYTHONPATH=%DCCSIG_PATH%;%PYTHONPATH%
CALL %DCCSI_PYTHON_INSTALL%\python.exe "%DCCSIG_PATH%\SDK\Maya\Scripts\Python\kitbash_converter\standalone.py"
ENDLOCAL
:: Return to starting directory
POPD
:END_OF_FILE
exit /b 0
@@ -51,8 +51,8 @@ module_name = 'kitbash_converter.main'
log_file_path = os.path.join(settings.DCCSI_LOG_PATH, f'{module_name}.log')
_log_level = int(20)
_G_DEBUG = True
if _G_DEBUG:
_DCCSI_GDEBUG = True
if _DCCSI_GDEBUG:
_log_level = int(10)
from azpy.constants import FRMT_LOG_LONG
@@ -1,45 +0,0 @@
:: coding:utf-8
:: !/usr/bin/python
::
:: 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
::
::
@echo off
:: Set up and run LY Python CMD prompt
:: Sets up the DccScriptingInterface_Env,
:: Puts you in the CMD within the dev environment
:: Set up window
TITLE Lumberyard DCC Scripting Interface Cmd
:: Use obvious color to prevent confusion (Grey with Yellow Text)
COLOR 8E
%~d0
cd %~dp0
PUSHD %~dp0
:: Keep changes local
SETLOCAL enableDelayedExpansion
CALL %~dp0\Project_Env.bat
echo.
echo _____________________________________________________________________
echo.
echo ~ LY DCC Scripting Interface CMD ...
echo _____________________________________________________________________
echo.
:: Create command prompt with environment
CALL %windir%\system32\cmd.exe
ENDLOCAL
:: Return to starting directory
POPD
:END_OF_FILE
@@ -1,68 +0,0 @@
:: coding:utf-8
:: !/usr/bin/python
::
:: 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
::
::
@echo off
:: Launches maya with a bunch of local hooks for Lumberyard
:: ToDo: move all of this to a .json data driven boostrapping system
%~d0
cd %~dp0
PUSHD %~dp0
echo ________________________________
echo ~ calling PROJ_Env.bat
:: Keep changes local
SETLOCAL enableDelayedExpansion
:: PY version Major
set DCCSI_PY_VERSION_MAJOR=2
echo DCCSI_PY_VERSION_MAJOR = %DCCSI_PY_VERSION_MAJOR%
:: PY version Major
set DCCSI_PY_VERSION_MINOR=7
echo DCCSI_PY_VERSION_MINOR = %DCCSI_PY_VERSION_MINOR%
:: Maya Version
set MAYA_VERSION=2020
echo MAYA_VERSION = %MAYA_VERSION%
:: if a local customEnv.bat exists, run it
IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat
echo ________________________________
echo Launching Maya %MAYA_VERSION% for Lumberyard...
:::: Set Maya native project acess to this project
::set MAYA_PROJECT=%LY_PROJECT%
::echo MAYA_PROJECT = %MAYA_PROJECT%
:: DX11 Viewport
Set MAYA_VP2_DEVICE_OVERRIDE = VirtualDeviceDx11
:: Default to the right version of Maya if we can detect it... and launch
IF EXIST "%MAYA_LOCATION%\bin\Maya.exe" (
start "" "%MAYA_LOCATION%\bin\Maya.exe" %*
) ELSE (
Where maya.exe 2> NUL
IF ERRORLEVEL 1 (
echo Maya.exe could not be found
pause
) ELSE (
start "" Maya.exe %*
)
)
:: Return to starting directory
POPD
:END_OF_FILE
exit /b 0
@@ -1,81 +0,0 @@
:: coding:utf-8
:: !/usr/bin/python
::
:: 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
::
::
@echo off
:: Launches Wing IDE and the DccScriptingInterface Project Files
echo.
echo _____________________________________________________________________
echo.
echo ~ Setting up LY DCCsi WingIDE Dev Env...
echo _____________________________________________________________________
echo.
:: Store current dir
%~d0
cd %~dp0
PUSHD %~dp0
:: Keep changes local
SETLOCAL enableDelayedExpansion
SET ABS_PATH=%~dp0
echo Current Dir, %ABS_PATH%
:: WingIDE version Major
SET WING_VERSION_MAJOR=7
echo WING_VERSION_MAJOR = %WING_VERSION_MAJOR%
:: WingIDE version Major
SET WING_VERSION_MINOR=1
echo WING_VERSION_MINOR = %WING_VERSION_MINOR%
:: note the changed path from IDE to Pro
set WINGHOME=%PROGRAMFILES(X86)%\Wing Pro %WING_VERSION_MAJOR%.%WING_VERSION_MINOR%
echo WINGHOME = %WINGHOME%
CALL %~dp0\Project_Env.bat
echo.
echo _____________________________________________________________________
echo.
echo ~ WingIDE Version %WING_VERSION_MAJOR%.%WING_VERSION_MINOR%
echo _____________________________________________________________________
echo.
SET WING_PROJ=%DCCSIG_PATH%\Solutions\.wing\DCCsi_%WING_VERSION_MAJOR%x.wpr
echo WING_PROJ = %WING_PROJ%
echo.
echo _____________________________________________________________________
echo.
echo ~ Launching %LY_PROJECT% project in WingIDE %WING_VERSION_MAJOR%.%WING_VERSION_MINOR% ...
echo _____________________________________________________________________
echo.
IF EXIST "%WINGHOME%\bin\wing.exe" (
start "" "%WINGHOME%\bin\wing.exe" "%WING_PROJ%"
) ELSE (
Where wing.exe 2> NUL
IF ERRORLEVEL 1 (
echo wing.exe could not be found
pause
) ELSE (
start "" wing.exe "%WING_PROJ%"
)
)
ENDLOCAL
:: Return to starting directory
POPD
:END_OF_FILE
@@ -1,72 +0,0 @@
:: coding:utf-8
:: !/usr/bin/python
::
:: 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
::
::
@echo off
:: Sets up environment for Lumberyard DCC tools and code access
:: Store current dir
%~d0
cd %~dp0
PUSHD %~dp0
for %%a in (.) do set LY_PROJECT=%%~na
echo.
echo _____________________________________________________________________
echo.
echo ~ Setting up LY DSI PROJECT Environment ...
echo _____________________________________________________________________
echo.
echo LY_PROJECT = %LY_PROJECT%
:: Put you project env vars and overrides here
:: chanhe the relative path up to dev
set DEV_REL_PATH=../../..
set ABS_PATH=%~dp0
:: Override the default maya version
set MAYA_VERSION=2020
echo MAYA_VERSION = %MAYA_VERSION%
set LY_PROJECT_PATH=%ABS_PATH%
echo LY_PROJECT_PATH = %LY_PROJECT_PATH%
:: Change to root Lumberyard dev dir
CD /d %LY_PROJECT_PATH%\%DEV_REL_PATH%
set LY_DEV=%CD%
echo LY_DEV = %LY_DEV%
CALL %LY_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Launchers\Windows\Env.bat
rem :: Constant Vars (Global)
rem SET LYPY_GDEBUG=0
rem echo LYPY_GDEBUG = %LYPY_GDEBUG%
rem SET LYPY_DEV_MODE=0
rem echo LYPY_DEV_MODE = %LYPY_DEV_MODE%
rem SET LYPY_DEBUGGER=WING
rem echo LYPY_DEBUGGER = %LYPY_DEBUGGER%
:: Restore original directory
popd
:: Change to root dir
CD /D %ABS_PATH%
:: if the user has set up a custom env call it
IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat
GOTO END_OF_FILE
:: Return to starting directory
POPD
:END_OF_FILE
@@ -80,8 +80,8 @@ module_name = 'legacy_asset_converter.main'
log_file_path = os.path.join(settings.DCCSI_LOG_PATH, f'{module_name}.log')
_log_level = int(20)
_G_DEBUG = True
if _G_DEBUG:
_DCCSI_GDEBUG = True
if _DCCSI_GDEBUG:
_log_level = int(10)
from azpy.constants import FRMT_LOG_LONG
@@ -1,135 +0,0 @@
# -*- coding: utf-8 -*-
# !/usr/bin/python
#
# 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
#
#
# -------------------------------------------------------------------------
import pymel.core as pmc
import sys
import types
def syspath():
print 'sys.path:'
for p in sys.path:
print ' ' + p
def info(obj):
"""Prints information about the object."""
lines = ['Info for %s' % obj.name(),
'Attributes:']
# Get the name of all attributes
for a in obj.listAttr():
lines.append(' ' + a.name())
lines.append('MEL type: %s' % obj.type())
lines.append('MRO:')
lines.extend([' ' + t.__name__ for t in type(obj).__mro__])
result = '\n'.join(lines)
print result
def _is_pymel(obj):
try: # (1)
module = obj.__module__ # (2)
except AttributeError: # (3)
try:
module = obj.__name__ # (4)
except AttributeError:
return None # (5)
return module.startswith('pymel') # (6)
def _py_to_helpstr(obj):
if isinstance(obj, basestring):
return 'search.html?q=%s' % (obj.replace(' ', '+'))
if not _is_pymel(obj):
return None
if isinstance(obj, types.ModuleType):
return ('generated/%(module)s.html#module-%(module)s' %
dict(module=obj.__name__))
if isinstance(obj, types.MethodType):
return ('generated/classes/%(module)s/'
'%(module)s.%(typename)s.html'
'#%(module)s.%(typename)s.%(methname)s' % dict(
module=obj.__module__,
typename=obj.im_class.__name__,
methname=obj.__name__))
if isinstance(obj, types.FunctionType):
return ('generated/functions/%(module)s/'
'%(module)s.%(funcname)s.html'
'#%(module)s.%(funcname)s' % dict(
module=obj.__module__,
funcname=obj.__name__))
if not isinstance(obj, type):
obj = type(obj)
return ('generated/classes/%(module)s/'
'%(module)s.%(typename)s.html'
'#%(module)s.%(typename)s' % dict(
module=obj.__module__,
typename=obj.__name__))
def test_py_to_helpstr():
def dotest(obj, ideal):
result = _py_to_helpstr(obj)
assert result == ideal, '%s != %s' % (result, ideal)
dotest('maya rocks', 'search.html?q=maya+rocks')
dotest(pmc.nodetypes,
'generated/pymel.core.nodetypes.html'
'#module-pymel.core.nodetypes')
dotest(pmc.nodetypes.Joint,
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint')
dotest(pmc.nodetypes.Joint(),
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint')
dotest(pmc.nodetypes.Joint().getTranslation,
'generated/classes/pymel.core.nodetypes/'
'pymel.core.nodetypes.Joint.html'
'#pymel.core.nodetypes.Joint.getTranslation')
dotest(pmc.joint,
'generated/functions/pymel.core.animation/'
'pymel.core.animation.joint.html'
'#pymel.core.animation.joint')
dotest(object(), None)
dotest(10, None)
dotest([], None)
dotest(sys, None)
def test_py_to_helpstrFAIL():
assert 1 == 2, '1 != 2'
import webbrowser # (1)
HELP_ROOT_URL = ('http://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/PyMel/')# (2)
def pmhelp(obj): # (3)
"""Gives help for a pymel or python object.
If obj is not a PyMEL object, use Python's built-in
`help` function.
If obj is a string, open a web browser to a search in the
PyMEL help for the string.
Otherwise, open a web browser to the page for the object.
"""
tail = _py_to_helpstr(obj)
if tail is None:
help(obj) # (4)
else:
webbrowser.open(HELP_ROOT_URL + tail) # (5)
if __name__ == '__main__':
test_py_to_helpstr()
print 'Tests ran successfully.'
@@ -23,7 +23,7 @@ def returnStubDir(stub):
break
if (len(tail) == 0):
path = ""
if _G_DEBUG:
if _DCCSI_GDEBUG:
print('~ Debug Message: I was not able to find the '
'path to that file (stub) in a walk-up from currnet path')
break

Some files were not shown because too many files have changed in this diff Show More