Reenable support for UI Elements that use Render Targets (#2352)
* Re-add support for UI Elements that use Render Targets * Move LyShine pass request from Atom's MainPipeline.pass to project's * Make all dynamic draw contexts in LyShine draw to pass directly without the need of draw list tags * Remove local RPI changes that are no longer needed * Prevent crash if LyShine gem is enabled but its custom pass hasn't been added to the main render pipeline * Revert to default UI pass if the LyShine pass has not been added to project's main render pipeline Signed-off-by: abrmich <abrmich@amazon.com>
This commit is contained in:
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "MainPipeline",
|
||||
"PassClass": "ParentPass",
|
||||
"Slots": [
|
||||
{
|
||||
"Name": "SwapChainOutput",
|
||||
"SlotType": "InputOutput",
|
||||
"ScopeAttachmentUsage": "RenderTarget"
|
||||
}
|
||||
],
|
||||
"PassRequests": [
|
||||
{
|
||||
"Name": "MorphTargetPass",
|
||||
"TemplateName": "MorphTargetPassTemplate"
|
||||
},
|
||||
{
|
||||
"Name": "SkinningPass",
|
||||
"TemplateName": "SkinningPassTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshOutputStream",
|
||||
"AttachmentRef": {
|
||||
"Pass": "MorphTargetPass",
|
||||
"Attachment": "MorphTargetDeltaOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RayTracingAccelerationStructurePass",
|
||||
"TemplateName": "RayTracingAccelerationStructurePassTemplate"
|
||||
},
|
||||
{
|
||||
"Name": "DiffuseProbeGridUpdatePass",
|
||||
"TemplateName": "DiffuseProbeGridUpdatePassTemplate",
|
||||
"ExecuteAfter": [
|
||||
"RayTracingAccelerationStructurePass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DepthPrePass",
|
||||
"TemplateName": "DepthMSAAParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MotionVectorPass",
|
||||
"TemplateName": "MotionVectorParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Depth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "LightCullingPass",
|
||||
"TemplateName": "LightCullingParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthMSAA",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthMSAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ShadowPass",
|
||||
"TemplateName": "ShadowParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "OpaquePass",
|
||||
"TemplateName": "OpaqueParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "DirectionalShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DirectionalESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LightListRemapped",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "LightListRemapped"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthLinear",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthMSAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "TransparentPass",
|
||||
"TemplateName": "TransparentParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "DirectionalShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DirectionalESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LightListRemapped",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "LightListRemapped"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputLinearDepth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "OpaquePass",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DeferredFogPass",
|
||||
"TemplateName": "DeferredFogPassTemplate",
|
||||
"Enabled": false,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "InputLinearDepth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputDepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "RenderTargetInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "TransparentPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "FullscreenTrianglePassData",
|
||||
"ShaderAsset": {
|
||||
"FilePath": "Shaders/ScreenSpace/DeferredFog.shader"
|
||||
},
|
||||
"PipelineViewTag": "MainCamera"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "ReflectionCopyFrameBufferPass",
|
||||
"TemplateName": "ReflectionCopyFrameBufferPassTemplate",
|
||||
"Enabled": false,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DeferredFogPass",
|
||||
"Attachment": "RenderTargetInputOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PostProcessPass",
|
||||
"TemplateName": "PostProcessParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "LightingInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DeferredFogPass",
|
||||
"Attachment": "RenderTargetInputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Depth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "MotionVectors",
|
||||
"AttachmentRef": {
|
||||
"Pass": "MotionVectorPass",
|
||||
"Attachment": "MotionVectorOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AuxGeomPass",
|
||||
"TemplateName": "AuxGeomPassTemplate",
|
||||
"Enabled": true,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "ColorInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "RasterPassData",
|
||||
"DrawListTag": "auxgeom",
|
||||
"PipelineViewTag": "MainCamera"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "DebugOverlayPass",
|
||||
"TemplateName": "DebugOverlayParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "RawLightingInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "RawLightingOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LuminanceMipChainInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "LuminanceMipChainOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "AuxGeomPass",
|
||||
"Attachment": "ColorInputOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "LyShinePass",
|
||||
"TemplateName": "LyShineParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "ColorInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DebugOverlayPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "UIPass",
|
||||
"TemplateName": "UIParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LyShinePass",
|
||||
"Attachment": "ColorInputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "CopyToSwapChain",
|
||||
"TemplateName": "FullscreenCopyTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
"AttachmentRef": {
|
||||
"Pass": "UIPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Output",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,7 @@
|
||||
"ScopeAttachmentUsage": "DepthStencil",
|
||||
"LoadStoreAction": {
|
||||
"ClearValue": {
|
||||
"Type": "DepthStencil",
|
||||
"Value": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
"Type": "DepthStencil"
|
||||
},
|
||||
"LoadActionStencil": "Clear"
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
m_pipelineState = m_shader->AcquirePipelineState(descriptor);
|
||||
}
|
||||
}
|
||||
m_dirty = false;
|
||||
}
|
||||
return m_pipelineState;
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
|
||||
#include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
|
||||
|
||||
// Indicates whether to use pre-multiplied alpha
|
||||
option bool o_preMultiplyAlpha;
|
||||
|
||||
// If true pixels with an alpha value of less than 0.5 are clipped
|
||||
option bool o_alphaTest;
|
||||
|
||||
@@ -86,9 +83,9 @@ struct PSOutput
|
||||
float4 m_color : SV_Target0;
|
||||
};
|
||||
|
||||
float4 SampleTriangleTexture(int texIndex, float2 uv)
|
||||
float4 SampleTriangleTexture(uint texIndex, float2 uv)
|
||||
{
|
||||
if ((InstanceSrg::m_isClamp & (1 << texIndex)) != 0)
|
||||
if ((InstanceSrg::m_isClamp & (1U << texIndex)) != 0)
|
||||
{
|
||||
return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_clampSampler, uv);
|
||||
}
|
||||
@@ -120,14 +117,6 @@ PSOutput MainPS(VSOutput IN)
|
||||
resColor.xyz = LinearToSRGB(resColor.xyz);
|
||||
}
|
||||
|
||||
// Check for flag to premultiply alpha
|
||||
if (o_preMultiplyAlpha)
|
||||
{
|
||||
// premultiply the color by the alpha. This would not be required if we had full access to the separate alpha blend mode
|
||||
float preMult = resColor.w;
|
||||
resColor.xyz *= preMult;
|
||||
}
|
||||
|
||||
// If the o_modulate option is not None it means that the verts have two texture indicies. The second texture is used to
|
||||
// mask the first. This is used for gradient masks.
|
||||
if (o_modulate == Modulate::Alpha)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{
|
||||
"StableId": 1,
|
||||
"Options": {
|
||||
"o_preMultiplyAlpha": "false",
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "true",
|
||||
"o_modulate": "Modulate::None"
|
||||
@@ -13,11 +12,26 @@
|
||||
{
|
||||
"StableId": 2,
|
||||
"Options": {
|
||||
"o_preMultiplyAlpha": "false",
|
||||
"o_alphaTest": "true",
|
||||
"o_srgbWrite": "true",
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"StableId": 3,
|
||||
"Options": {
|
||||
"o_alphaTest": "true",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"StableId": 4,
|
||||
"Options": {
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::Alpha"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "LyShineParentTemplate",
|
||||
"PassClass": "LyShinePass",
|
||||
"Slots": [
|
||||
{
|
||||
"Name": "ColorInputOutput",
|
||||
"SlotType": "InputOutput"
|
||||
},
|
||||
{
|
||||
"Name": "DepthInputOutput",
|
||||
"SlotType": "InputOutput",
|
||||
"ScopeAttachmentUsage": "DepthStencil"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "AssetAliasesSourceData",
|
||||
"ClassData": {
|
||||
"AssetPaths": [
|
||||
{
|
||||
"Name": "LyShineParentTemplate",
|
||||
"Path": "Passes/LyShineParent.pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
FILES_CMAKE
|
||||
lyshine_common_module_files.cmake
|
||||
lyshine_tests_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
LYSHINE_TESTS
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Tests
|
||||
|
||||
@@ -1547,6 +1547,20 @@ AssetTreeEntry* EditorWindow::GetSliceLibraryTree()
|
||||
return m_sliceLibraryTree;
|
||||
}
|
||||
|
||||
AZ::EntityId EditorWindow::GetCanvasForCurrentEditorMode()
|
||||
{
|
||||
AZ::EntityId canvasEntityId;
|
||||
if (GetEditorMode() == UiEditorMode::Edit)
|
||||
{
|
||||
canvasEntityId = GetCanvas();
|
||||
}
|
||||
else
|
||||
{
|
||||
canvasEntityId = GetPreviewModeCanvas();
|
||||
}
|
||||
return canvasEntityId;
|
||||
}
|
||||
|
||||
void EditorWindow::ToggleEditorMode()
|
||||
{
|
||||
m_editorMode = (m_editorMode == UiEditorMode::Edit) ? UiEditorMode::Preview : UiEditorMode::Edit;
|
||||
|
||||
@@ -143,6 +143,9 @@ public: // member functions
|
||||
//! Returns the current mode of the editor (Edit or Preview)
|
||||
UiEditorMode GetEditorMode() { return m_editorMode; }
|
||||
|
||||
//! Returns the UI canvas for the current mode (Edit or Preview)
|
||||
AZ::EntityId GetCanvasForCurrentEditorMode();
|
||||
|
||||
//! Toggle the editor mode between Edit and Preview
|
||||
void ToggleEditorMode();
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
#include "EditorCommon.h"
|
||||
|
||||
#include "UiCanvasComponent.h"
|
||||
|
||||
#include "EditorDefs.h"
|
||||
#include "Settings.h"
|
||||
#include <AzCore/std/containers/map.h>
|
||||
@@ -245,6 +247,7 @@ ViewportWidget::ViewportWidget(EditorWindow* parent)
|
||||
|
||||
FontNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(GetCurrentContextName());
|
||||
}
|
||||
|
||||
ViewportWidget::~ViewportWidget()
|
||||
@@ -252,6 +255,8 @@ ViewportWidget::~ViewportWidget()
|
||||
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
|
||||
FontNotificationBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
LyShinePassDataRequestBus::Handler::BusDisconnect();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
m_uiRenderer.reset();
|
||||
|
||||
@@ -272,6 +277,8 @@ void ViewportWidget::InitUiRenderer()
|
||||
lyShine->SetUiRendererForEditor(m_uiRenderer);
|
||||
|
||||
m_draw2d = AZStd::make_shared<CDraw2d>(GetViewportContext());
|
||||
|
||||
LyShinePassDataRequestBus::Handler::BusConnect(GetViewportContext()->GetRenderScene()->GetId());
|
||||
}
|
||||
|
||||
ViewportInteraction* ViewportWidget::GetViewportInteraction()
|
||||
@@ -487,30 +494,44 @@ void ViewportWidget::EnableCanvasRender()
|
||||
}
|
||||
|
||||
void ViewportWidget::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
// Update
|
||||
UiEditorMode editorMode = m_editorWindow->GetEditorMode();
|
||||
if (editorMode == UiEditorMode::Edit)
|
||||
{
|
||||
UpdateEditMode(deltaTime);
|
||||
}
|
||||
else // if (editorMode == UiEditorMode::Preview)
|
||||
{
|
||||
UpdatePreviewMode(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int ViewportWidget::GetTickOrder()
|
||||
{
|
||||
return AZ::TICK_PRE_RENDER;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void ViewportWidget::OnRenderTick()
|
||||
{
|
||||
if (!m_uiRenderer->IsReady() || !m_canvasRenderIsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
gEnv->pRenderer->SetSrgbWrite(true);
|
||||
#endif
|
||||
|
||||
const float dpiScale = QtHelpers::GetHighDpiScaleFactor(*this);
|
||||
ViewportIcon::SetDpiScaleFactor(dpiScale);
|
||||
|
||||
// Set up to render a frame to this viewport's window
|
||||
GetViewportContext()->RenderTick();
|
||||
|
||||
UiEditorMode editorMode = m_editorWindow->GetEditorMode();
|
||||
if (editorMode == UiEditorMode::Edit)
|
||||
{
|
||||
RenderEditMode(deltaTime);
|
||||
RenderEditMode();
|
||||
}
|
||||
else // if (editorMode == UiEditorMode::Preview)
|
||||
{
|
||||
RenderPreviewMode(deltaTime);
|
||||
RenderPreviewMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,17 +905,37 @@ void ViewportWidget::OnFontTextureUpdated([[maybe_unused]] IFFont* font)
|
||||
m_fontTextureHasChanged = true;
|
||||
}
|
||||
|
||||
LyShine::AttachmentImagesAndDependencies ViewportWidget::GetRenderTargets()
|
||||
{
|
||||
LyShine::AttachmentImagesAndDependencies canvasTargets;
|
||||
|
||||
AZ::EntityId canvasEntityId = m_editorWindow->GetCanvasForCurrentEditorMode();
|
||||
if (canvasEntityId.IsValid())
|
||||
{
|
||||
AZ::Entity* canvasEntity = nullptr;
|
||||
EBUS_EVENT_RESULT(canvasEntity, AZ::ComponentApplicationBus, FindEntity, canvasEntityId);
|
||||
AZ_Assert(canvasEntity, "Canvas entity not found by ID");
|
||||
if (canvasEntity)
|
||||
{
|
||||
UiCanvasComponent* canvasComponent = canvasEntity->FindComponent<UiCanvasComponent>();
|
||||
AZ_Assert(canvasComponent, "Canvas entity has no canvas component");
|
||||
if (canvasComponent)
|
||||
{
|
||||
canvasComponent->GetRenderTargets(canvasTargets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canvasTargets;
|
||||
}
|
||||
|
||||
QPointF ViewportWidget::WidgetToViewport(const QPointF & point) const
|
||||
{
|
||||
return point * WidgetToViewportFactor();
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderEditMode(float deltaTime)
|
||||
void ViewportWidget::UpdateEditMode(float deltaTime)
|
||||
{
|
||||
// sort keys for different layers
|
||||
static const int64_t backgroundKey = -0x1000;
|
||||
static const int64_t topLayerKey = 0x1000000;
|
||||
|
||||
if (m_fontTextureHasChanged)
|
||||
{
|
||||
// A font texture has changed since we last rendered. Force a render graph update for each loaded canvas
|
||||
@@ -908,6 +949,28 @@ void ViewportWidget::RenderEditMode(float deltaTime)
|
||||
return; // this can happen if a render happens during a restart
|
||||
}
|
||||
|
||||
AZ::Vector2 canvasSize;
|
||||
EBUS_EVENT_ID_RESULT(canvasSize, canvasEntityId, UiCanvasBus, GetCanvasSize);
|
||||
|
||||
// Set the target size of the canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false);
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderEditMode()
|
||||
{
|
||||
// sort keys for different layers
|
||||
static const int64_t backgroundKey = -0x1000;
|
||||
static const int64_t topLayerKey = 0x1000000;
|
||||
|
||||
AZ::EntityId canvasEntityId = m_editorWindow->GetCanvas();
|
||||
if (!canvasEntityId.IsValid())
|
||||
{
|
||||
return; // this can happen if a render happens during a restart
|
||||
}
|
||||
|
||||
Draw2dHelper draw2d(m_draw2d.get()); // sets and resets 2D draw mode in constructor/destructor
|
||||
|
||||
QTreeWidgetItemRawPtrQList selection = m_editorWindow->GetHierarchy()->selectedItems();
|
||||
@@ -936,9 +999,6 @@ void ViewportWidget::RenderEditMode(float deltaTime)
|
||||
// Set the target size of the canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false);
|
||||
|
||||
// Render this canvas
|
||||
QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this);
|
||||
AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height());
|
||||
@@ -1037,11 +1097,8 @@ void ViewportWidget::RenderEditMode(float deltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderPreviewMode(float deltaTime)
|
||||
void ViewportWidget::UpdatePreviewMode(float deltaTime)
|
||||
{
|
||||
// sort keys for different layers
|
||||
static const int64_t backgroundKey = -0x1000;
|
||||
|
||||
AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
|
||||
|
||||
if (m_fontTextureHasChanged)
|
||||
@@ -1051,6 +1108,37 @@ void ViewportWidget::RenderPreviewMode(float deltaTime)
|
||||
m_fontTextureHasChanged = false;
|
||||
}
|
||||
|
||||
if (canvasEntityId.IsValid())
|
||||
{
|
||||
QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this);
|
||||
AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height());
|
||||
|
||||
// Get the canvas size
|
||||
AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize();
|
||||
if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f)
|
||||
{
|
||||
// special value of (0,0) means use the viewport size
|
||||
canvasSize = viewportSize;
|
||||
}
|
||||
|
||||
// Set the target size of the canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, true, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true);
|
||||
|
||||
// Execute events that have been queued during the canvas update
|
||||
gEnv->pLyShine->ExecuteQueuedEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderPreviewMode()
|
||||
{
|
||||
// sort keys for different layers
|
||||
static const int64_t backgroundKey = -0x1000;
|
||||
|
||||
AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
|
||||
|
||||
// Rather than scaling to exactly fit we try to draw at one of these preset scale factors
|
||||
// to make it it bit more obvious that the canvas size is changing
|
||||
float zoomScales[] = {
|
||||
@@ -1096,15 +1184,6 @@ void ViewportWidget::RenderPreviewMode(float deltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the target size of the canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, true, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true);
|
||||
|
||||
// Execute events that have been queued during the canvas update
|
||||
gEnv->pLyShine->ExecuteQueuedEvents();
|
||||
|
||||
// match scale to one of the predefined scales. If the scale is so small
|
||||
// that it is less than the smallest scale then leave it as it is
|
||||
for (int i = 0; i < AZ_ARRAY_SIZE(zoomScales); ++i)
|
||||
@@ -1131,14 +1210,6 @@ void ViewportWidget::RenderPreviewMode(float deltaTime)
|
||||
canvasToViewportMatrix.SetTranslation(translation);
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetCanvasToViewportMatrix, canvasToViewportMatrix);
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // mask support with Atom
|
||||
// clear the stencil buffer before rendering each canvas - required for masking
|
||||
// NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target
|
||||
// We also clear the color to a mid grey so that we can see the bounds of the canvas
|
||||
ColorF viewportBackgroundColor(0.5f, 0.5f, 0.5f, 0); // if clearing color we want to set alpha to zero also
|
||||
gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor);
|
||||
#endif
|
||||
|
||||
m_draw2d->SetSortKey(backgroundKey);
|
||||
|
||||
RenderViewportBackground();
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "EditorCommon.h"
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
|
||||
#include <IFont.h>
|
||||
|
||||
@@ -27,6 +29,8 @@ class ViewportWidget
|
||||
: public AtomToolsFramework::RenderViewportWidget
|
||||
, private AzToolsFramework::EditorPickModeNotificationBus::Handler
|
||||
, private FontNotificationBus::Handler
|
||||
, private LyShinePassDataRequestBus::Handler
|
||||
, public AZ::RPI::ViewportContextNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -138,15 +142,29 @@ private: // member functions
|
||||
void OnFontTextureUpdated(IFFont* font) override;
|
||||
// ~FontNotifications
|
||||
|
||||
// LyShinePassDataRequestBus
|
||||
LyShine::AttachmentImagesAndDependencies GetRenderTargets() override;
|
||||
// ~LyShinePassDataRequestBus
|
||||
|
||||
// AZ::TickBus::Handler
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
int GetTickOrder() override;
|
||||
// ~AZ::TickBus::Handler
|
||||
|
||||
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
|
||||
void OnRenderTick() override;
|
||||
|
||||
//! Update UI canvases when in edit mode
|
||||
void UpdateEditMode(float deltaTime);
|
||||
|
||||
//! Render the viewport when in edit mode
|
||||
void RenderEditMode(float deltaTime);
|
||||
void RenderEditMode();
|
||||
|
||||
//! Update UI canvases when in preview mode
|
||||
void UpdatePreviewMode(float deltaTime);
|
||||
|
||||
//! Render the viewport when in preview mode
|
||||
void RenderPreviewMode(float deltaTime);
|
||||
void RenderPreviewMode();
|
||||
|
||||
//! Fill the entire viewport area with a background color
|
||||
void RenderViewportBackground();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <IRenderer.h> // for SVF_P3F_C4B_T2F which will be removed in a coming PR
|
||||
|
||||
#include <LyShine/Draw2d.h>
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
@@ -95,6 +96,12 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc
|
||||
AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet.");
|
||||
|
||||
// Create and initialize a DynamicDrawContext for 2d drawing
|
||||
|
||||
// Get the pass for the dynamic draw context to render to
|
||||
AZ::RPI::RasterPass* uiCanvasPass = nullptr;
|
||||
AZ::RPI::SceneId sceneId = scene->GetId();
|
||||
LyShinePassRequestBus::EventResult(uiCanvasPass, sceneId, &LyShinePassRequestBus::Events::GetUiCanvasPass);
|
||||
|
||||
m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
|
||||
AZ::RPI::ShaderOptionList shaderOptions;
|
||||
shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("true")));
|
||||
@@ -106,7 +113,15 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc
|
||||
{"TEXCOORD0", AZ::RHI::Format::R32G32_FLOAT} });
|
||||
m_dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::PrimitiveType
|
||||
| AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
|
||||
m_dynamicDraw->SetOutputScope(scene.get());
|
||||
if (uiCanvasPass)
|
||||
{
|
||||
m_dynamicDraw->SetOutputScope(uiCanvasPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Render target support is disabled
|
||||
m_dynamicDraw->SetOutputScope(scene.get());
|
||||
}
|
||||
m_dynamicDraw->EndInit();
|
||||
|
||||
AZ::RHI::TargetBlendState targetBlendState;
|
||||
@@ -491,6 +506,7 @@ bool CDraw2d::GetDeferPrimitives()
|
||||
return m_deferCalls;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CDraw2d::SetSortKey(int64_t key)
|
||||
{
|
||||
m_dynamicDraw->SetSortKey(key);
|
||||
|
||||
@@ -163,6 +163,8 @@ CLyShine::CLyShine(ISystem* system)
|
||||
AzFramework::InputTextEventListener::Connect();
|
||||
UiCursorBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(
|
||||
AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName());
|
||||
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
|
||||
|
||||
// These are internal Amazon components, so register them so that we can send back their names to our metrics collection
|
||||
@@ -240,9 +242,11 @@ CLyShine::~CLyShine()
|
||||
{
|
||||
UiCursorBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::InputTextEventListener::Disconnect();
|
||||
AzFramework::InputChannelEventListener::Disconnect();
|
||||
AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
|
||||
LyShinePassDataRequestBus::Handler::BusDisconnect();
|
||||
|
||||
UiCanvasComponent::Shutdown();
|
||||
|
||||
@@ -642,15 +646,19 @@ void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time
|
||||
{
|
||||
// Update the loaded UI canvases
|
||||
Update(deltaTime);
|
||||
|
||||
// Recreate dirty render graphs and send primitive data to the dynamic draw context
|
||||
Render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int CLyShine::GetTickOrder()
|
||||
{
|
||||
return AZ::TICK_UI;
|
||||
return AZ::TICK_PRE_RENDER;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CLyShine::OnRenderTick()
|
||||
{
|
||||
// Recreate dirty render graphs and send primitive data to the dynamic draw context
|
||||
Render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -658,6 +666,16 @@ void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapS
|
||||
{
|
||||
// Load cursor if its path was set before RPI was initialized
|
||||
LoadUiCursor();
|
||||
|
||||
LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
LyShine::AttachmentImagesAndDependencies CLyShine::GetRenderTargets()
|
||||
{
|
||||
LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies;
|
||||
m_uiCanvasManager->GetRenderTargets(attachmentImagesAndDependencies);
|
||||
return attachmentImagesAndDependencies;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
#include <AzFramework/Input/Events/InputTextEventListener.h>
|
||||
|
||||
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Reflect/Image/Image.h>
|
||||
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
#define LYSHINE_INTERNAL_UNIT_TEST
|
||||
#endif
|
||||
@@ -40,7 +43,9 @@ class CLyShine
|
||||
, public AzFramework::InputChannelEventListener
|
||||
, public AzFramework::InputTextEventListener
|
||||
, public AZ::TickBus::Handler
|
||||
, public AZ::RPI::ViewportContextNotificationBus::Handler
|
||||
, protected AZ::Render::Bootstrap::NotificationBus::Handler
|
||||
, protected LyShinePassDataRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -111,10 +116,17 @@ public:
|
||||
int GetTickOrder() override;
|
||||
// ~TickEvents
|
||||
|
||||
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
|
||||
void OnRenderTick() override;
|
||||
|
||||
// AZ::Render::Bootstrap::NotificationBus
|
||||
void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override;
|
||||
// ~AZ::Render::Bootstrap::NotificationBus
|
||||
|
||||
// LyShinePassDataRequestBus
|
||||
LyShine::AttachmentImagesAndDependencies GetRenderTargets() override;
|
||||
// ~LyShinePassDataRequestBus
|
||||
|
||||
// Get the UIRenderer for the game (which is owned by CLyShine). This is not exposed outside the gem.
|
||||
UiRenderer* GetUiRenderer();
|
||||
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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/Debug/Trace.h>
|
||||
#include <Atom/RHI/DrawListTagRegistry.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Pass/PassAttachment.h>
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RPI.Public/Image/AttachmentImagePool.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Reflect/Pass/RasterPassData.h>
|
||||
#include <AzCore/std/iterator.h>
|
||||
|
||||
#include "LyShinePass.h"
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
AZ::RPI::Ptr<LyShinePass> LyShinePass::Create(const AZ::RPI::PassDescriptor& descriptor)
|
||||
{
|
||||
return aznew LyShinePass(descriptor);
|
||||
}
|
||||
|
||||
LyShinePass::LyShinePass(const AZ::RPI::PassDescriptor& descriptor)
|
||||
: Base(descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
LyShinePass::~LyShinePass()
|
||||
{
|
||||
LyShinePassRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void LyShinePass::ResetInternal()
|
||||
{
|
||||
LyShinePassRequestBus::Handler::BusDisconnect();
|
||||
|
||||
Base::ResetInternal();
|
||||
}
|
||||
|
||||
void LyShinePass::BuildInternal()
|
||||
{
|
||||
AZ::RPI::Scene* scene = GetScene();
|
||||
if (scene)
|
||||
{
|
||||
// Listen for rebuild requests
|
||||
LyShinePassRequestBus::Handler::BusConnect(scene->GetId());
|
||||
|
||||
RemoveChildren();
|
||||
|
||||
// Get the current list of render targets being used across all loaded UI Canvases
|
||||
LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies;
|
||||
LyShinePassDataRequestBus::EventResult(
|
||||
attachmentImagesAndDependencies,
|
||||
scene->GetId(),
|
||||
&LyShinePassDataRequestBus::Events::GetRenderTargets
|
||||
);
|
||||
|
||||
AddRttChildPasses(attachmentImagesAndDependencies);
|
||||
AddUiCanvasChildPass(attachmentImagesAndDependencies);
|
||||
}
|
||||
|
||||
Base::BuildInternal();
|
||||
}
|
||||
|
||||
void LyShinePass::RebuildRttChildren()
|
||||
{
|
||||
QueueForBuildAndInitialization();
|
||||
}
|
||||
|
||||
AZ::RPI::RasterPass* LyShinePass::GetRttPass(const AZStd::string& name)
|
||||
{
|
||||
for (auto child:m_children)
|
||||
{
|
||||
if (child->GetName() == AZ::Name(name))
|
||||
{
|
||||
return azrtti_cast<AZ::RPI::RasterPass*>(child.get());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ::RPI::RasterPass* LyShinePass::GetUiCanvasPass()
|
||||
{
|
||||
return m_uiCanvasChildPass.get();
|
||||
}
|
||||
|
||||
void LyShinePass::AddRttChildPasses(LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies)
|
||||
{
|
||||
for (const auto& attachmentImageAndDependencies : attachmentImagesAndDependencies)
|
||||
{
|
||||
AddRttChildPass(attachmentImageAndDependencies.first, attachmentImageAndDependencies.second);
|
||||
}
|
||||
}
|
||||
|
||||
void LyShinePass::AddRttChildPass(AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage, AttachmentImages attachmentImageDependencies)
|
||||
{
|
||||
// Add a pass that renders to the specified texture
|
||||
|
||||
// Create a pass template
|
||||
auto passTemplate = AZStd::make_shared<AZ::RPI::PassTemplate>();
|
||||
passTemplate->m_name = "RttChildPass";
|
||||
passTemplate->m_passClass = AZ::Name("RttChildPass");
|
||||
|
||||
// Slots
|
||||
passTemplate->m_slots.resize(2);
|
||||
|
||||
AZ::RPI::PassSlot& depthInOutSlot = passTemplate->m_slots[0];
|
||||
depthInOutSlot.m_name = "DepthInputOutput";
|
||||
depthInOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput;
|
||||
depthInOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::DepthStencil;
|
||||
depthInOutSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateDepthStencil(0.0f, 0);
|
||||
depthInOutSlot.m_loadStoreAction.m_loadActionStencil = AZ::RHI::AttachmentLoadAction::Clear;
|
||||
|
||||
AZ::RPI::PassSlot& outSlot = passTemplate->m_slots[1];
|
||||
outSlot.m_name = AZ::Name("RenderTargetOutput");
|
||||
outSlot.m_slotType = AZ::RPI::PassSlotType::Output;
|
||||
outSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::RenderTarget;
|
||||
outSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateVector4Float(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
outSlot.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear;
|
||||
|
||||
// Connections
|
||||
passTemplate->m_connections.resize(1);
|
||||
|
||||
AZ::RPI::PassConnection& depthInOutConnection = passTemplate->m_connections[0];
|
||||
depthInOutConnection.m_localSlot = "DepthInputOutput";
|
||||
depthInOutConnection.m_attachmentRef.m_pass = "Parent";
|
||||
depthInOutConnection.m_attachmentRef.m_attachment = "DepthInputOutput";
|
||||
|
||||
// Pass data
|
||||
AZStd::shared_ptr<AZ::RPI::RasterPassData> passData = AZStd::make_shared<AZ::RPI::RasterPassData>();
|
||||
passData->m_drawListTag = AZ::Name("uicanvas");
|
||||
passData->m_pipelineViewTag = AZ::Name("MainCamera");
|
||||
auto size = attachmentImage->GetRHIImage()->GetDescriptor().m_size;
|
||||
passData->m_overrideScissor = AZ::RHI::Scissor(0, 0, size.m_width, size.m_height);
|
||||
passData->m_overrideViewport = AZ::RHI::Viewport(0, size.m_width, 0, size.m_height);
|
||||
passTemplate->m_passData = AZStd::move(passData);
|
||||
// Create a pass descriptor for the new child pass
|
||||
AZ::RPI::PassDescriptor childDesc;
|
||||
childDesc.m_passTemplate = passTemplate;
|
||||
childDesc.m_passName = attachmentImage->GetAttachmentId();
|
||||
|
||||
AZ::RPI::PassSystemInterface* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
AZ::RPI::Ptr<RttChildPass> rttChildPass = passSystem->CreatePass<RttChildPass>(childDesc);
|
||||
AZ_Assert(rttChildPass, "[LyShinePass] Unable to create %s.", passTemplate->m_name.GetCStr());
|
||||
|
||||
// Store the info needed to attach to slots and set up frame graph dependencies
|
||||
rttChildPass->m_attachmentImage = attachmentImage;
|
||||
rttChildPass->m_attachmentImageDependencies = attachmentImageDependencies;
|
||||
|
||||
AddChild(rttChildPass);
|
||||
}
|
||||
|
||||
void LyShinePass::AddUiCanvasChildPass(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies)
|
||||
{
|
||||
if (!m_uiCanvasChildPass)
|
||||
{
|
||||
// Create a pass template
|
||||
auto passTemplate = AZStd::make_shared<AZ::RPI::PassTemplate>();
|
||||
passTemplate->m_name = AZ::Name("LyShineChildPass");
|
||||
passTemplate->m_passClass = AZ::Name("LyShineChildPass");
|
||||
|
||||
// Slots
|
||||
passTemplate->m_slots.resize(2);
|
||||
|
||||
AZ::RPI::PassSlot& depthInOutSlot = passTemplate->m_slots[0];
|
||||
depthInOutSlot.m_name = "DepthInputOutput";
|
||||
depthInOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput;
|
||||
depthInOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::DepthStencil;
|
||||
depthInOutSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateDepthStencil(0.0f, 0);
|
||||
depthInOutSlot.m_loadStoreAction.m_loadActionStencil = AZ::RHI::AttachmentLoadAction::Clear;
|
||||
|
||||
AZ::RPI::PassSlot& inOutSlot = passTemplate->m_slots[1];
|
||||
inOutSlot.m_name = "ColorInputOutput";
|
||||
inOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput;
|
||||
inOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::RenderTarget;
|
||||
|
||||
// Connections
|
||||
passTemplate->m_connections.resize(2);
|
||||
|
||||
AZ::RPI::PassConnection& depthInOutConnection = passTemplate->m_connections[0];
|
||||
depthInOutConnection.m_localSlot = "DepthInputOutput";
|
||||
depthInOutConnection.m_attachmentRef.m_pass = "Parent";
|
||||
depthInOutConnection.m_attachmentRef.m_attachment = "DepthInputOutput";
|
||||
|
||||
AZ::RPI::PassConnection& inOutConnection = passTemplate->m_connections[1];
|
||||
inOutConnection.m_localSlot = "ColorInputOutput";
|
||||
inOutConnection.m_attachmentRef.m_pass = "Parent";
|
||||
inOutConnection.m_attachmentRef.m_attachment = "ColorInputOutput";
|
||||
|
||||
// Pass data
|
||||
AZStd::shared_ptr<AZ::RPI::RasterPassData> passData = AZStd::make_shared<AZ::RPI::RasterPassData>();
|
||||
passData->m_drawListTag = AZ::Name("uicanvas");
|
||||
passData->m_pipelineViewTag = AZ::Name("MainCamera");
|
||||
passTemplate->m_passData = AZStd::move(passData);
|
||||
|
||||
// Create a pass descriptor for the new child pass
|
||||
AZ::RPI::PassDescriptor childDesc;
|
||||
childDesc.m_passTemplate = passTemplate;
|
||||
childDesc.m_passName = AZ::Name("LyShineChildPass");
|
||||
|
||||
AZ::RPI::PassSystemInterface* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
m_uiCanvasChildPass = passSystem->CreatePass<LyShineChildPass>(childDesc);
|
||||
AZ_Assert(m_uiCanvasChildPass, "[LyShinePass] Unable to create %s.", passTemplate->m_name.GetCStr());
|
||||
}
|
||||
|
||||
// Store the info needed to set up frame graph dependencies
|
||||
m_uiCanvasChildPass->m_attachmentImageDependencies.clear();
|
||||
for (const auto& attachmentImageAndDescendents : AttachmentImagesAndDependencies)
|
||||
{
|
||||
m_uiCanvasChildPass->m_attachmentImageDependencies.emplace_back(attachmentImageAndDescendents.first);
|
||||
}
|
||||
|
||||
AddChild(m_uiCanvasChildPass);
|
||||
}
|
||||
|
||||
AZ::RPI::Ptr<LyShineChildPass> LyShineChildPass::Create(const AZ::RPI::PassDescriptor& descriptor)
|
||||
{
|
||||
return aznew LyShineChildPass(descriptor);
|
||||
}
|
||||
|
||||
LyShineChildPass::LyShineChildPass(const AZ::RPI::PassDescriptor& descriptor)
|
||||
: RasterPass(descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
LyShineChildPass::~LyShineChildPass()
|
||||
{
|
||||
}
|
||||
|
||||
void LyShineChildPass::SetupFrameGraphDependencies(AZ::RHI::FrameGraphInterface frameGraph)
|
||||
{
|
||||
AZ::RPI::RasterPass::SetupFrameGraphDependencies(frameGraph);
|
||||
|
||||
for (auto attachmentImage : m_attachmentImageDependencies)
|
||||
{
|
||||
// Ensure that the image is imported into the attachment database.
|
||||
// The image may not be imported if the owning pass has been disabled.
|
||||
auto attachmentImageId = attachmentImage->GetAttachmentId();
|
||||
if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentImageId))
|
||||
{
|
||||
frameGraph.GetAttachmentDatabase().ImportImage(attachmentImageId, attachmentImage->GetRHIImage());
|
||||
}
|
||||
|
||||
AZ::RHI::ImageScopeAttachmentDescriptor desc;
|
||||
desc.m_attachmentId = attachmentImageId;
|
||||
desc.m_imageViewDescriptor = attachmentImage->GetImageView()->GetDescriptor();
|
||||
desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
|
||||
|
||||
frameGraph.UseShaderAttachment(desc, AZ::RHI::ScopeAttachmentAccess::Read);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::RPI::Ptr<RttChildPass> RttChildPass::Create(const AZ::RPI::PassDescriptor& descriptor)
|
||||
{
|
||||
return aznew RttChildPass(descriptor);
|
||||
}
|
||||
|
||||
RttChildPass::RttChildPass(const AZ::RPI::PassDescriptor& descriptor)
|
||||
: LyShineChildPass(descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
RttChildPass::~RttChildPass()
|
||||
{
|
||||
}
|
||||
|
||||
void RttChildPass::BuildInternal()
|
||||
{
|
||||
AttachImageToSlot(AZ::Name("RenderTargetOutput"), m_attachmentImage);
|
||||
}
|
||||
} // namespace LyShine
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.Public/Pass/ParentPass.h>
|
||||
#include <Atom/RPI.Public/Pass/RasterPass.h>
|
||||
#include <AtomCore/std/containers/array_view.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
class LyShineChildPass;
|
||||
|
||||
//! Manages child passes at runtime that render to render targets
|
||||
class LyShinePass final
|
||||
: public AZ::RPI::ParentPass
|
||||
, protected LyShinePassRequestBus::Handler
|
||||
{
|
||||
AZ_RPI_PASS(LyShinePass);
|
||||
using Base = AZ::RPI::ParentPass;
|
||||
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(LyShinePass, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(LyShinePass, "C3B812ED-3771-42F4-A96F-EBD94B4D54CA", Base);
|
||||
|
||||
virtual ~LyShinePass();
|
||||
static AZ::RPI::Ptr<LyShinePass> Create(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
protected:
|
||||
// Pass behavior overrides
|
||||
void ResetInternal() override;
|
||||
void BuildInternal() override;
|
||||
|
||||
// LyShinePassRequestBus overrides
|
||||
void RebuildRttChildren() override;
|
||||
AZ::RPI::RasterPass* GetRttPass(const AZStd::string& name) override;
|
||||
AZ::RPI::RasterPass* GetUiCanvasPass() override;
|
||||
|
||||
private:
|
||||
LyShinePass() = delete;
|
||||
explicit LyShinePass(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
// Build the render to texture child passes
|
||||
void AddRttChildPasses(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies);
|
||||
|
||||
// Add a render to texture child pass
|
||||
void AddRttChildPass(AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage, AttachmentImages dependentAttachmentImages);
|
||||
|
||||
// Append the final pass to render UI Canvas elements to the screen
|
||||
void AddUiCanvasChildPass(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies);
|
||||
|
||||
// Pass that renders the UI Canvas elements to the screen
|
||||
AZ::RPI::Ptr<LyShineChildPass> m_uiCanvasChildPass;
|
||||
};
|
||||
|
||||
// Child pass with potential attachment dependencies
|
||||
class LyShineChildPass
|
||||
: public AZ::RPI::RasterPass
|
||||
{
|
||||
AZ_RPI_PASS(LyShineChildPass);
|
||||
|
||||
friend class LyShinePass;
|
||||
public:
|
||||
AZ_RTTI(LyShineChildPass, "{41D525F9-09EB-4004-97DC-082078FF8DD2}", RasterPass);
|
||||
AZ_CLASS_ALLOCATOR(LyShineChildPass, AZ::SystemAllocator, 0);
|
||||
virtual ~LyShineChildPass();
|
||||
|
||||
//! Creates a LyShineChildPass
|
||||
static AZ::RPI::Ptr<LyShineChildPass> Create(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
protected:
|
||||
LyShineChildPass(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
// Scope producer Overrides...
|
||||
void SetupFrameGraphDependencies(AZ::RHI::FrameGraphInterface frameGraph) override;
|
||||
|
||||
AttachmentImages m_attachmentImageDependencies;
|
||||
};
|
||||
|
||||
// Child pass that renders UI elements to a render target
|
||||
class RttChildPass
|
||||
: public LyShineChildPass
|
||||
{
|
||||
AZ_RPI_PASS(RttChildPass);
|
||||
|
||||
friend class LyShinePass;
|
||||
|
||||
public:
|
||||
AZ_RTTI(RttChildPass, "{54B0574D-2EB3-4054-9E1D-0E0D9C8CB09A}", LyShineChildPass);
|
||||
AZ_CLASS_ALLOCATOR(RttChildPass, AZ::SystemAllocator, 0);
|
||||
virtual ~RttChildPass();
|
||||
|
||||
//! Creates a RttChildPass
|
||||
static AZ::RPI::Ptr<RttChildPass> Create(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
protected:
|
||||
RttChildPass(const AZ::RPI::PassDescriptor& descriptor);
|
||||
|
||||
// Pass behavior overrides
|
||||
void BuildInternal() override;
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> m_attachmentImage;
|
||||
};
|
||||
} // namespace LyShine
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
class AttachmentImage;
|
||||
class RasterPass;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
using AttachmentImages = AZStd::vector<AZ::Data::Instance<AZ::RPI::AttachmentImage>>;
|
||||
using AttachmentImageAndDependentsPair = AZStd::pair<AZ::Data::Instance<AZ::RPI::AttachmentImage>, AttachmentImages>;
|
||||
using AttachmentImagesAndDependencies = AZStd::vector<AttachmentImageAndDependentsPair>;
|
||||
}
|
||||
|
||||
class LyShinePassRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = AZ::RPI::SceneId;
|
||||
|
||||
//! Called when the number of render targets has changed and the LyShine pass needs to rebuild
|
||||
virtual void RebuildRttChildren() = 0;
|
||||
|
||||
//! Returns a render to texture pass based on render target name
|
||||
virtual AZ::RPI::RasterPass* GetRttPass(const AZStd::string& name) = 0;
|
||||
|
||||
//! Returns the final pass that renders the UI canvas contents
|
||||
virtual AZ::RPI::RasterPass* GetUiCanvasPass() = 0;
|
||||
};
|
||||
using LyShinePassRequestBus = AZ::EBus<LyShinePassRequests>;
|
||||
|
||||
class LyShinePassDataRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = AZ::RPI::SceneId;
|
||||
|
||||
//! Get a list of render targets that require a render to texture pass, and any
|
||||
//! other render targets that are drawn on them
|
||||
virtual LyShine::AttachmentImagesAndDependencies GetRenderTargets() = 0;
|
||||
};
|
||||
using LyShinePassDataRequestBus = AZ::EBus<LyShinePassDataRequests>;
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "UiDynamicLayoutComponent.h"
|
||||
#include "UiDynamicScrollBoxComponent.h"
|
||||
#include "UiNavigationSettings.h"
|
||||
#include "LyShinePass.h"
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
@@ -113,9 +114,11 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void LyShineSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
void LyShineSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
(void)required;
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -186,6 +189,17 @@ namespace LyShine
|
||||
RegisterComponentTypeForMenuOrdering(UiDynamicScrollBoxComponent::RTTI_Type());
|
||||
RegisterComponentTypeForMenuOrdering(UiParticleEmitterComponent::RTTI_Type());
|
||||
RegisterComponentTypeForMenuOrdering(UiFlipbookAnimationComponent::RTTI_Type());
|
||||
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
// Add LyShine pass
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
AZ_Assert(passSystem, "Cannot get the pass system.");
|
||||
passSystem->AddPassCreator(AZ::Name("LyShinePass"), &LyShine::LyShinePass::Create);
|
||||
|
||||
// Setup handler for load pass template mappings
|
||||
m_loadTemplatesHandler = AZ::RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler([this]() { this->LoadPassTemplateMappings(); });
|
||||
AZ::RPI::PassSystemInterface::Get()->ConnectEvent(m_loadTemplatesHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -386,4 +400,13 @@ namespace LyShine
|
||||
{
|
||||
UiCursorBus::Broadcast(&UiCursorInterface::SetUiCursor, m_cursorImagePathname.GetAssetPath().c_str());
|
||||
}
|
||||
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void LyShineSystemComponent::LoadPassTemplateMappings()
|
||||
{
|
||||
const char* passTemplatesFile = "Passes/LyShinePassTemplates.azasset";
|
||||
AZ::RPI::PassSystemInterface::Get()->LoadPassTemplateMappings(passTemplatesFile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include <LyShine/UiComponentTypes.h>
|
||||
#include "LyShine.h"
|
||||
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#endif
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
// LyShine depends on the LegacyAllocator and CryStringAllocator. This will be managed
|
||||
@@ -90,6 +94,11 @@ namespace LyShine
|
||||
|
||||
void BroadcastCursorImagePathname();
|
||||
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
// Load pass template mappings for this gem
|
||||
void LoadPassTemplateMappings();
|
||||
#endif
|
||||
|
||||
protected: // data
|
||||
|
||||
CLyShine* m_pLyShine = nullptr;
|
||||
@@ -102,5 +111,9 @@ namespace LyShine
|
||||
|
||||
// We only store this in order to generate metrics on LyShine specific components
|
||||
static const AZStd::list<AZ::ComponentDescriptor*>* m_componentDescriptors;
|
||||
|
||||
#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS)
|
||||
AZ::RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler m_loadTemplatesHandler;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#include "UiRenderer.h"
|
||||
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
|
||||
#ifndef _RELEASE
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
@@ -78,57 +81,28 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void PrimitiveListRenderNode::Render(UiRenderer* uiRenderer)
|
||||
void PrimitiveListRenderNode::Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw)
|
||||
{
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (masks/render targets)
|
||||
for (int i = 0; i < m_numTextures; ++i)
|
||||
{
|
||||
uiRenderer->SetTexture(m_textures[i].m_texture, i, m_textures[i].m_isClampTextureMode);
|
||||
}
|
||||
|
||||
int blendModeState = m_blendModeState;
|
||||
|
||||
IRenderer* renderer = gEnv->pRenderer;
|
||||
renderer->SetState(blendModeState | uiRenderer->GetBaseState());
|
||||
|
||||
if (m_isTextureSRGB)
|
||||
{
|
||||
renderer->SetSrgbWrite(false);
|
||||
}
|
||||
|
||||
// We are using SetColorOp as a way to set flags for the ui.cfx shader by reusing flags
|
||||
// that the FixedPipelineEmu.cfx shader uses. So the names colorOp and alphaOp are used
|
||||
// just because this are the inputs to SetColorOp.
|
||||
uint8 colorOp = m_preMultiplyAlpha ? ColorOp_PreMultiplyAlpha : ColorOp_Normal;
|
||||
uint8 alphaOp = AlphaOp_Normal;
|
||||
switch (m_alphaMaskType)
|
||||
{
|
||||
case AlphaMaskType::None:
|
||||
alphaOp = AlphaOp_Normal;
|
||||
break;
|
||||
case AlphaMaskType::ModulateAlpha:
|
||||
alphaOp = AlphaOp_ModulateAlpha;
|
||||
break;
|
||||
case AlphaMaskType::ModulateAlphaAndColor:
|
||||
alphaOp = AlphaOp_ModulateAlphaAndColor;
|
||||
break;
|
||||
}
|
||||
|
||||
renderer->SetColorOp(colorOp, alphaOp, DEF_TEXARG0, DEF_TEXARG0);
|
||||
|
||||
renderer->DrawDynUiPrimitiveList(m_primitives, m_totalNumVertices, m_totalNumIndices);
|
||||
|
||||
if (m_isTextureSRGB)
|
||||
{
|
||||
renderer->SetSrgbWrite(true);
|
||||
}
|
||||
#endif
|
||||
if (!uiRenderer->IsReady())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
|
||||
UiRenderer::BaseState curBaseState = uiRenderer->GetBaseState();
|
||||
UiRenderer::BaseState prevBaseState = curBaseState;
|
||||
if (m_isTextureSRGB)
|
||||
{
|
||||
curBaseState.m_srgbWrite = false;
|
||||
}
|
||||
|
||||
if (m_alphaMaskType == AlphaMaskType::ModulateAlpha)
|
||||
{
|
||||
curBaseState.m_modulateAlpha = true;
|
||||
}
|
||||
uiRenderer->SetBaseState(curBaseState);
|
||||
|
||||
const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData();
|
||||
|
||||
// Set render state
|
||||
@@ -167,7 +141,7 @@ namespace LyShine
|
||||
drawSrg->SetConstant(uiShaderData.m_isClampInputIndex, isClampTextureMode);
|
||||
|
||||
// Set projection matrix
|
||||
drawSrg->SetConstant(uiShaderData.m_viewProjInputIndex, uiRenderer->GetModelViewProjectionMatrix());
|
||||
drawSrg->SetConstant(uiShaderData.m_viewProjInputIndex, modelViewProjMat);
|
||||
|
||||
drawSrg->Compile();
|
||||
|
||||
@@ -180,6 +154,8 @@ namespace LyShine
|
||||
{
|
||||
dynamicDraw->DrawIndexed(primitive.m_vertices, primitive.m_numVertices, primitive.m_indices, primitive.m_numIndices, AZ::RHI::IndexFormat::Uint16, drawSrg);
|
||||
}
|
||||
|
||||
uiRenderer->SetBaseState(prevBaseState);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -303,33 +279,35 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MaskRenderNode::Render(UiRenderer* uiRenderer)
|
||||
void MaskRenderNode::Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw)
|
||||
{
|
||||
UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState();
|
||||
|
||||
if (m_isMaskingEnabled || m_drawBehind)
|
||||
{
|
||||
SetupBeforeRenderingMask(uiRenderer, true, priorBaseState);
|
||||
SetupBeforeRenderingMask(uiRenderer, dynamicDraw, true, priorBaseState);
|
||||
for (RenderNode* renderNode : m_maskRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw);
|
||||
}
|
||||
SetupAfterRenderingMask(uiRenderer, true, priorBaseState);
|
||||
SetupAfterRenderingMask(uiRenderer, dynamicDraw, true, priorBaseState);
|
||||
}
|
||||
|
||||
for (RenderNode* renderNode : m_contentRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw);
|
||||
}
|
||||
|
||||
if (m_isMaskingEnabled || m_drawInFront)
|
||||
{
|
||||
SetupBeforeRenderingMask(uiRenderer, false, priorBaseState);
|
||||
SetupBeforeRenderingMask(uiRenderer, dynamicDraw, false, priorBaseState);
|
||||
for (RenderNode* renderNode : m_maskRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw);
|
||||
}
|
||||
SetupAfterRenderingMask(uiRenderer, false, priorBaseState);
|
||||
SetupAfterRenderingMask(uiRenderer, dynamicDraw, false, priorBaseState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +345,9 @@ namespace LyShine
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState)
|
||||
void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer,
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
|
||||
bool firstPass, UiRenderer::BaseState priorBaseState)
|
||||
{
|
||||
UiRenderer::BaseState curBaseState = priorBaseState;
|
||||
|
||||
@@ -406,7 +386,6 @@ namespace LyShine
|
||||
curBaseState.m_stencilState.m_backFace = stencilOpState;
|
||||
|
||||
// set up for stencil write
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
|
||||
dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef());
|
||||
curBaseState.m_stencilState.m_enable = true;
|
||||
curBaseState.m_stencilState.m_writeMask = 0xFF;
|
||||
@@ -421,7 +400,9 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState)
|
||||
void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer,
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
|
||||
bool firstPass, UiRenderer::BaseState priorBaseState)
|
||||
{
|
||||
if (m_isMaskingEnabled)
|
||||
{
|
||||
@@ -439,7 +420,6 @@ namespace LyShine
|
||||
uiRenderer->DecrementStencilRef();
|
||||
}
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
|
||||
dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef());
|
||||
|
||||
if (firstPass)
|
||||
@@ -474,16 +454,14 @@ namespace LyShine
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RenderTargetRenderNode::RenderTargetRenderNode(
|
||||
RenderTargetRenderNode* parentRenderTarget,
|
||||
int renderTargetHandle,
|
||||
SDepthTexture* renderTargetDepthSurface,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
|
||||
const AZ::Vector2& viewportTopLeft,
|
||||
const AZ::Vector2& viewportSize,
|
||||
const AZ::Color& clearColor,
|
||||
int nestLevel)
|
||||
: RenderNode(RenderNodeType::RenderTarget)
|
||||
, m_parentRenderTarget(parentRenderTarget)
|
||||
, m_renderTargetHandle(renderTargetHandle)
|
||||
, m_renderTargetDepthSurface(renderTargetDepthSurface)
|
||||
, m_attachmentImage(attachmentImage)
|
||||
, m_viewportX(viewportTopLeft.GetX())
|
||||
, m_viewportY(viewportTopLeft.GetY())
|
||||
, m_viewportWidth(viewportSize.GetX())
|
||||
@@ -491,6 +469,13 @@ namespace LyShine
|
||||
, m_clearColor(clearColor)
|
||||
, m_nestLevel(nestLevel)
|
||||
{
|
||||
AZ::MakeOrthographicMatrixRH(m_modelViewProjMat,
|
||||
m_viewportX,
|
||||
m_viewportX + m_viewportWidth,
|
||||
m_viewportY + m_viewportHeight,
|
||||
m_viewportY,
|
||||
0.0f,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -505,9 +490,11 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderTargetRenderNode::Render(UiRenderer* uiRenderer)
|
||||
void RenderTargetRenderNode::Render(UiRenderer* uiRenderer
|
||||
, [[maybe_unused]] const AZ::Matrix4x4& modelViewProjMat
|
||||
, [[maybe_unused]] AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw)
|
||||
{
|
||||
if (m_renderTargetHandle <= 0)
|
||||
if (!m_attachmentImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -515,39 +502,52 @@ namespace LyShine
|
||||
ISystem* system = gEnv->pSystem;
|
||||
if (system && !gEnv->IsDedicated())
|
||||
{
|
||||
TransformationMatrices backupMatrices;
|
||||
gEnv->pRenderer->Set2DModeNonZeroTopLeft(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight, backupMatrices);
|
||||
|
||||
// this will change the viewport
|
||||
gEnv->pRenderer->SetRenderTarget(m_renderTargetHandle, m_renderTargetDepthSurface);
|
||||
|
||||
// clear the render target before rendering to it
|
||||
// NOTE: the FRT_CLEAR_IMMEDIATE is required since we will have already set the render target
|
||||
// In theory we could call this before setting the render target without the immediate flag
|
||||
// but that doesn't work. Perhaps because FX_Commit is not called.
|
||||
ColorF viewportBackgroundColor(m_clearColor.GetR(), m_clearColor.GetG(), m_clearColor.GetB(), m_clearColor.GetA());
|
||||
gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor);
|
||||
|
||||
// we could use SetSrgbWrite to write to a linear texture here. But that gets complicated with
|
||||
// having to affect all decsendant element renders. So we just let it write srgb to the render target and
|
||||
// allow for that when we render using the render target as a source texture.
|
||||
|
||||
for (RenderNode* renderNode : m_childRenderNodes)
|
||||
// Use a dedicated dynamic draw context for rendering to the texture since it can only have one draw list tag
|
||||
if (!m_dynamicDraw)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
m_dynamicDraw = uiRenderer->CreateDynamicDrawContextForRTT(GetRenderTargetName());
|
||||
}
|
||||
|
||||
gEnv->pRenderer->SetRenderTarget(0); // restore render target
|
||||
if (m_dynamicDraw)
|
||||
{
|
||||
UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState();
|
||||
|
||||
gEnv->pRenderer->Unset2DMode(backupMatrices);
|
||||
UiRenderer::BaseState curBaseState = priorBaseState;
|
||||
curBaseState.m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
|
||||
curBaseState.m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSource1Inverse;
|
||||
uiRenderer->SetBaseState(curBaseState);
|
||||
|
||||
for (RenderNode* renderNode : m_childRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer, m_modelViewProjMat, m_dynamicDraw);
|
||||
}
|
||||
|
||||
uiRenderer->SetBaseState(priorBaseState);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_WarningOnce("UI", false, "Failed to create a Dynamic Draw Context for UI Element's render target. "\
|
||||
"Please ensure that the custom LyShinePass has been added to the project's main render pipeline.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const char* RenderTargetRenderNode::GetRenderTargetName() const
|
||||
{
|
||||
ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_renderTargetHandle);
|
||||
return texture->GetName();
|
||||
return m_attachmentImage->GetRHIImage()->GetName().GetCStr();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int RenderTargetRenderNode::GetNestLevel() const
|
||||
{
|
||||
return m_nestLevel;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const AZ::Data::Instance<AZ::RPI::AttachmentImage> RenderTargetRenderNode::GetRenderTarget() const
|
||||
{
|
||||
return m_attachmentImage;
|
||||
}
|
||||
|
||||
#ifndef _RELEASE
|
||||
@@ -671,31 +671,29 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::BeginRenderToTexture(int renderTargetHandle, SDepthTexture* renderTargetDepthSurface,
|
||||
void RenderGraph::BeginRenderToTexture([[maybe_unused]] int renderTargetHandle, [[maybe_unused]] SDepthTexture* renderTargetDepthSurface,
|
||||
[[maybe_unused]] const AZ::Vector2& viewportTopLeft, [[maybe_unused]] const AZ::Vector2& viewportSize, [[maybe_unused]] const AZ::Color& clearColor)
|
||||
{
|
||||
// LYSHINE_ATOM_TODO - this function will be removed when all IRenderer references are gone from UI components
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::BeginRenderToTexture(AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
|
||||
const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor)
|
||||
{
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
|
||||
// this uses pool allocator
|
||||
RenderTargetRenderNode* renderTargetRenderNode = new RenderTargetRenderNode(
|
||||
m_currentRenderTarget, renderTargetHandle, renderTargetDepthSurface,
|
||||
m_currentRenderTarget, attachmentImage,
|
||||
viewportTopLeft, viewportSize, clearColor, m_renderTargetNestLevel);
|
||||
|
||||
m_currentRenderTarget = renderTargetRenderNode;
|
||||
m_renderNodeListStack.push(&m_currentRenderTarget->GetChildRenderNodeList());
|
||||
m_renderTargetNestLevel++;
|
||||
#else
|
||||
AZ_UNUSED(clearColor);
|
||||
AZ_UNUSED(viewportSize);
|
||||
AZ_UNUSED(viewportTopLeft);
|
||||
AZ_UNUSED(renderTargetDepthSurface);
|
||||
AZ_UNUSED(renderTargetHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::EndRenderToTexture()
|
||||
{
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
|
||||
AZ_Assert(m_currentRenderTarget, "Calling EndRenderToTexture while not defining a render target node");
|
||||
if (m_currentRenderTarget)
|
||||
{
|
||||
@@ -709,7 +707,6 @@ namespace LyShine
|
||||
m_renderNodeListStack.pop();
|
||||
m_renderTargetNestLevel--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void RenderGraph::AddPrimitive(
|
||||
@@ -803,11 +800,22 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::AddAlphaMaskPrimitive(IRenderer::DynUiPrimitive* primitive,
|
||||
ITexture* texture, ITexture* maskTexture,
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode)
|
||||
void RenderGraph::AddAlphaMaskPrimitive([[maybe_unused]] IRenderer::DynUiPrimitive* primitive,
|
||||
[[maybe_unused]] ITexture* texture, [[maybe_unused]] ITexture* maskTexture,
|
||||
[[maybe_unused]] bool isClampTextureMode, [[maybe_unused]] bool isTextureSRGB, [[maybe_unused]] bool isTexturePremultipliedAlpha, [[maybe_unused]] BlendMode blendMode)
|
||||
{
|
||||
// LYSHINE_ATOM_TODO - this function will be removed when all IRenderer references are gone from UI components
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::AddAlphaMaskPrimitiveAtom(IRenderer::DynUiPrimitive* primitive,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> contentAttachmentImage,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> maskAttachmentImage,
|
||||
bool isClampTextureMode,
|
||||
bool isTextureSRGB,
|
||||
bool isTexturePremultipliedAlpha,
|
||||
BlendMode blendMode)
|
||||
{
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
|
||||
AZStd::vector<RenderNode*>* renderNodeList = m_renderNodeListStack.top();
|
||||
|
||||
int texUnit0 = -1;
|
||||
@@ -842,8 +850,8 @@ namespace LyShine
|
||||
{
|
||||
// render state is the same - we can add the primitive to this list if the texture is in
|
||||
// the list or there is space for another texture
|
||||
texUnit0 = primListRenderNode->GetOrAddTexture(texture, true);
|
||||
texUnit1 = primListRenderNode->GetOrAddTexture(maskTexture, true);
|
||||
texUnit0 = primListRenderNode->GetOrAddTexture(contentAttachmentImage, true);
|
||||
texUnit1 = primListRenderNode->GetOrAddTexture(maskAttachmentImage, true);
|
||||
|
||||
if (texUnit0 != -1 && texUnit1 != -1)
|
||||
{
|
||||
@@ -857,7 +865,7 @@ namespace LyShine
|
||||
{
|
||||
// We can't add this primitive to the existing render node, we need to create a new render node
|
||||
// this uses a pool allocator for fast allocation
|
||||
renderNodeToAddTo = new PrimitiveListRenderNode(texture, maskTexture,
|
||||
renderNodeToAddTo = new PrimitiveListRenderNode(contentAttachmentImage, maskAttachmentImage,
|
||||
isClampTextureMode, isTextureSRGB, isPreMultiplyAlpha, alphaMaskType, blendModeState);
|
||||
|
||||
renderNodeList->push_back(renderNodeToAddTo);
|
||||
@@ -881,15 +889,6 @@ namespace LyShine
|
||||
// add this primitive to the render node
|
||||
renderNodeToAddTo->AddPrimitive(primitive);
|
||||
}
|
||||
#else
|
||||
AZ_UNUSED(primitive);
|
||||
AZ_UNUSED(texture);
|
||||
AZ_UNUSED(maskTexture);
|
||||
AZ_UNUSED(isClampTextureMode);
|
||||
AZ_UNUSED(isTextureSRGB);
|
||||
AZ_UNUSED(isTexturePremultipliedAlpha);
|
||||
AZ_UNUSED(blendMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -972,11 +971,8 @@ namespace LyShine
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize)
|
||||
void RenderGraph::Render(UiRenderer* uiRenderer, [[maybe_unused]] const AZ::Vector2& viewportSize)
|
||||
{
|
||||
// LYSHINE_ATOM_TODO - will probably need to support this when converting UI Editor to use Atom
|
||||
AZ_UNUSED(viewportSize);
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
|
||||
|
||||
// Disable stencil and enable blend/color write
|
||||
@@ -984,57 +980,35 @@ namespace LyShine
|
||||
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
|
||||
|
||||
// First render the render targets, they are sorted so that more deeply nested ones are rendered first.
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (render targets)
|
||||
// They only need to be rendered the first time that a render graph is rendered after it has been built.
|
||||
// Though there is a special case, if this is the first time a shader variant has been used it can miss
|
||||
// the first render. So to be safe we only stop rendering to render targets after we have rendered to
|
||||
// them twice with no shader compiles initiated.
|
||||
if (m_renderToRenderTargetCount < 2)
|
||||
if (m_renderToRenderTargetCount == 0)
|
||||
{
|
||||
// Enable the Rtt passes to draw onto the render targets
|
||||
SetRttPassesEnabled(uiRenderer, true);
|
||||
}
|
||||
|
||||
// LYSHINE_ATOM_TODO - It is currently necessary to render to the targets twice. Needs investigation
|
||||
constexpr int timesToRenderToRenderTargets = 2;
|
||||
if (m_renderToRenderTargetCount < timesToRenderToRenderTargets)
|
||||
{
|
||||
for (RenderNode* renderNode : m_renderTargetRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
}
|
||||
|
||||
// if the render targets render OK we don't need to render them every frame. But if a new shader
|
||||
// variant needed to be compiled then they will not have rendered OK. So we check is there are
|
||||
// any shaders still in the process of compiling. Because they are compiled on the render
|
||||
// thread, we may not know until the next frame that a shader needed to be compiled. So we need
|
||||
// the counter.
|
||||
SShaderCacheStatistics stats;
|
||||
gEnv->pRenderer->EF_Query(EFQ_GetShaderCacheInfo, stats);
|
||||
bool waitingOnShadersToCompile = stats.m_nNumShaderAsyncCompiles > 0 ? true : false;
|
||||
if (!waitingOnShadersToCompile)
|
||||
{
|
||||
m_renderToRenderTargetCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderToRenderTargetCount = 0;
|
||||
renderNode->Render(uiRenderer, uiRenderer->GetModelViewProjectionMatrix(), dynamicDraw);
|
||||
}
|
||||
m_renderToRenderTargetCount++;
|
||||
}
|
||||
#else
|
||||
for (RenderNode* renderNode : m_renderTargetRenderNodes)
|
||||
else if (m_renderToRenderTargetCount < timesToRenderToRenderTargets + 1)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
// Disable the rtt render passes since they don't need to be rendered to until the graph becomes invalidated again.
|
||||
// This is also necessary to prevent the render targets' contents getting cleared on load by the pass.
|
||||
SetRttPassesEnabled(uiRenderer, false);
|
||||
m_renderToRenderTargetCount++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (UI Editor)
|
||||
// Set2DMode defines the viewport so we set it to canvas viewport here (the render target render nodes
|
||||
// above will have set the viewport as they needed).
|
||||
TransformationMatrices backupMatrices;
|
||||
gEnv->pRenderer->Set2DMode(static_cast<uint32>(viewportSize.GetX()), static_cast<uint32>(viewportSize.GetY()), backupMatrices);
|
||||
#endif
|
||||
for (RenderNode* renderNode : m_renderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer);
|
||||
renderNode->Render(uiRenderer, uiRenderer->GetModelViewProjectionMatrix(), dynamicDraw);
|
||||
}
|
||||
#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (UI Editor)
|
||||
// end the 2D mode
|
||||
gEnv->pRenderer->Unset2DMode(backupMatrices);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1072,6 +1046,31 @@ namespace LyShine
|
||||
return m_renderNodes.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::GetRenderTargetsAndDependencies(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies)
|
||||
{
|
||||
for (RenderNode* renderNode : m_renderTargetRenderNodes)
|
||||
{
|
||||
const RenderTargetRenderNode* renderTargetRenderNode = static_cast<const RenderTargetRenderNode*>(renderNode);
|
||||
|
||||
if (renderTargetRenderNode->GetNestLevel() == 0)
|
||||
{
|
||||
LyShine::AttachmentImages attachmentImages;
|
||||
const AZStd::vector<RenderNode*>& childNodeList = renderTargetRenderNode->GetChildRenderNodeList();
|
||||
for (auto& childNode : childNodeList)
|
||||
{
|
||||
if (childNode->GetType() == RenderNodeType::RenderTarget)
|
||||
{
|
||||
const RenderTargetRenderNode* childRenderTargetRenderNode = static_cast<const RenderTargetRenderNode*>(childNode);
|
||||
attachmentImages.emplace_back(childRenderTargetRenderNode->GetRenderTarget());
|
||||
}
|
||||
}
|
||||
|
||||
attachmentImagesAndDependencies.emplace_back(AttachmentImageAndDependentsPair(renderTargetRenderNode->GetRenderTarget(), attachmentImages));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _RELEASE
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RenderGraph::ValidateGraph()
|
||||
@@ -1540,4 +1539,19 @@ namespace LyShine
|
||||
return flags;
|
||||
}
|
||||
|
||||
void RenderGraph::SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled)
|
||||
{
|
||||
// Enable or disable the rtt render passes
|
||||
AZ::RPI::SceneId sceneId = uiRenderer->GetViewportContext()->GetRenderScene()->GetId();
|
||||
for (RenderTargetRenderNode* renderTargetRenderNode : m_renderTargetRenderNodes)
|
||||
{
|
||||
// Find the rtt pass to disable
|
||||
AZ::RPI::RasterPass* rttPass = nullptr;
|
||||
LyShinePassRequestBus::EventResult(rttPass, sceneId, &LyShinePassRequestBus::Events::GetRttPass, renderTargetRenderNode->GetRenderTargetName());
|
||||
if (rttPass)
|
||||
{
|
||||
rttPass->SetEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/AttachmentImage.h>
|
||||
#include <Atom/RPI.Reflect/Image/Image.h>
|
||||
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
|
||||
#include "UiRenderer.h"
|
||||
#include "LyShinePass.h"
|
||||
#ifndef _RELEASE
|
||||
#include "LyShineDebug.h"
|
||||
#endif
|
||||
@@ -46,7 +49,9 @@ namespace LyShine
|
||||
RenderNode(RenderNodeType type) : m_type(type) {}
|
||||
virtual ~RenderNode() {};
|
||||
|
||||
virtual void Render(UiRenderer* uiRenderer) = 0;
|
||||
virtual void Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) = 0;
|
||||
|
||||
RenderNodeType GetType() const { return m_type; }
|
||||
|
||||
@@ -70,7 +75,9 @@ namespace LyShine
|
||||
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, const AZ::Data::Instance<AZ::RPI::Image>& maskTexture,
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState);
|
||||
~PrimitiveListRenderNode() override;
|
||||
void Render(UiRenderer* uiRenderer) override;
|
||||
void Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
|
||||
|
||||
void AddPrimitive(IRenderer::DynUiPrimitive* primitive);
|
||||
IRenderer::DynUiPrimitiveList& GetPrimitives() const;
|
||||
@@ -128,7 +135,9 @@ namespace LyShine
|
||||
MaskRenderNode(MaskRenderNode* parentMask, bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront);
|
||||
~MaskRenderNode() override;
|
||||
|
||||
void Render(UiRenderer* uiRenderer) override;
|
||||
void Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
|
||||
|
||||
AZStd::vector<RenderNode*>& GetMaskRenderNodeList() { return m_maskRenderNodes; }
|
||||
const AZStd::vector<RenderNode*>& GetMaskRenderNodeList() const { return m_maskRenderNodes; }
|
||||
@@ -152,8 +161,12 @@ namespace LyShine
|
||||
#endif
|
||||
|
||||
private: // functions
|
||||
void SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState);
|
||||
void SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState);
|
||||
void SetupBeforeRenderingMask(UiRenderer* uiRenderer,
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
|
||||
bool firstPass, UiRenderer::BaseState priorBaseState);
|
||||
void SetupAfterRenderingMask(UiRenderer* uiRenderer,
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
|
||||
bool firstPass, UiRenderer::BaseState priorBaseState);
|
||||
|
||||
private: // data
|
||||
AZStd::vector<RenderNode*> m_maskRenderNodes; //!< The render nodes used to render the mask shape
|
||||
@@ -175,15 +188,17 @@ namespace LyShine
|
||||
// We use a pool allocator to keep these allocations fast.
|
||||
AZ_CLASS_ALLOCATOR(RenderTargetRenderNode, AZ::PoolAllocator, 0);
|
||||
|
||||
RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget, int renderTargetHandle,
|
||||
SDepthTexture* renderTargetDepthSurface,
|
||||
RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
|
||||
const AZ::Vector2& viewportTopLeft,
|
||||
const AZ::Vector2& viewportSize,
|
||||
const AZ::Color& clearColor,
|
||||
int nestLevel);
|
||||
~RenderTargetRenderNode() override;
|
||||
|
||||
void Render(UiRenderer* uiRenderer) override;
|
||||
void Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
, AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
|
||||
|
||||
AZStd::vector<RenderNode*>& GetChildRenderNodeList() { return m_childRenderNodes; }
|
||||
const AZStd::vector<RenderNode*>& GetChildRenderNodeList() const { return m_childRenderNodes; }
|
||||
@@ -197,6 +212,9 @@ namespace LyShine
|
||||
AZ::Color GetClearColor() const { return m_clearColor; }
|
||||
|
||||
const char* GetRenderTargetName() const;
|
||||
int GetNestLevel() const;
|
||||
|
||||
const AZ::Data::Instance<AZ::RPI::AttachmentImage> GetRenderTarget() const;
|
||||
|
||||
#ifndef _RELEASE
|
||||
// A debug-only function useful for debugging
|
||||
@@ -213,13 +231,16 @@ namespace LyShine
|
||||
|
||||
RenderTargetRenderNode* m_parentRenderTarget = nullptr; //! Used while building the render graph.
|
||||
|
||||
int m_renderTargetHandle = -1;
|
||||
SDepthTexture* m_renderTargetDepthSurface = nullptr;
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> m_attachmentImage;
|
||||
|
||||
// Each render target requires a unique dynamic draw context to draw to the raster pass associated with the target
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> m_dynamicDraw;
|
||||
|
||||
float m_viewportX = 0;
|
||||
float m_viewportY = 0;
|
||||
float m_viewportWidth = 0;
|
||||
float m_viewportHeight = 0;
|
||||
AZ::Matrix4x4 m_modelViewProjMat;
|
||||
AZ::Color m_clearColor;
|
||||
int m_nestLevel = 0;
|
||||
};
|
||||
@@ -241,9 +262,10 @@ namespace LyShine
|
||||
void StartChildrenForMask() override;
|
||||
void EndMask() override;
|
||||
|
||||
//! Begin rendering to a texture
|
||||
void BeginRenderToTexture(int renderTargetHandle, SDepthTexture* renderTargetDepthSurface,
|
||||
const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize,
|
||||
const AZ::Color& clearColor) override;
|
||||
const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor) override;
|
||||
|
||||
void EndRenderToTexture() override;
|
||||
|
||||
void AddPrimitive(IRenderer::DynUiPrimitive* primitive, ITexture* texture,
|
||||
@@ -268,6 +290,20 @@ namespace LyShine
|
||||
void AddPrimitiveAtom(IRenderer::DynUiPrimitive* primitive, const AZ::Data::Instance<AZ::RPI::Image>& texture,
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode);
|
||||
|
||||
//! Add an indexed triangle list primitive to the render graph which will use maskTexture as an alpha (gradient) mask
|
||||
void AddAlphaMaskPrimitiveAtom(IRenderer::DynUiPrimitive* primitive,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> contentAttachmentImage,
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> maskAttachmentImage,
|
||||
bool isClampTextureMode,
|
||||
bool isTextureSRGB,
|
||||
bool isTexturePremultipliedAlpha,
|
||||
BlendMode blendMode);
|
||||
|
||||
void BeginRenderToTexture(AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
|
||||
const AZ::Vector2& viewportTopLeft,
|
||||
const AZ::Vector2& viewportSize,
|
||||
const AZ::Color& clearColor);
|
||||
|
||||
//! Render the display graph
|
||||
void Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize);
|
||||
|
||||
@@ -283,6 +319,8 @@ namespace LyShine
|
||||
//! Test whether the render graph contains any render nodes
|
||||
bool IsEmpty();
|
||||
|
||||
void GetRenderTargetsAndDependencies(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies);
|
||||
|
||||
#ifndef _RELEASE
|
||||
// A debug-only function useful for debugging, not called but calls can be added during debugging
|
||||
void ValidateGraph();
|
||||
@@ -311,6 +349,8 @@ namespace LyShine
|
||||
//! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags
|
||||
int GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
|
||||
|
||||
void SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled);
|
||||
|
||||
protected: // data
|
||||
|
||||
AZStd::vector<RenderNode*> m_renderNodes;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 LyShine
|
||||
{
|
||||
//! Ebus to handle render target requests
|
||||
class RenderToTextureRequests
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
virtual AZ::RHI::AttachmentId UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) = 0;
|
||||
virtual void ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) = 0;
|
||||
virtual AZ::Data::Instance<AZ::RPI::AttachmentImage> GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) = 0;
|
||||
};
|
||||
|
||||
using RenderToTextureRequestBus = AZ::EBus<RenderToTextureRequests>;
|
||||
}
|
||||
@@ -49,6 +49,8 @@
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RPI.Public/Image/AttachmentImagePool.h>
|
||||
|
||||
#include "Animation/UiAnimationSystem.h"
|
||||
|
||||
@@ -64,6 +66,8 @@
|
||||
#include <LyShine/Bus/UiFaderBus.h>
|
||||
#endif
|
||||
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! UiCanvasNotificationBus Behavior context handler class
|
||||
class UiCanvasNotificationBusBehaviorHandler
|
||||
@@ -251,14 +255,22 @@ namespace
|
||||
|
||||
UiRenderer* GetUiRendererForGame()
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine ? lyShine->GetUiRenderer() : nullptr;
|
||||
if (gEnv && gEnv->pLyShine)
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine->GetUiRenderer();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UiRenderer* GetUiRendererForEditor()
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine ? lyShine->GetUiRendererForEditor() : nullptr;
|
||||
if (gEnv && gEnv->pLyShine)
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine->GetUiRendererForEditor();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsValidInteractable(const AZ::EntityId& entityId)
|
||||
@@ -1829,6 +1841,46 @@ void UiCanvasComponent::MarkRenderGraphDirty()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::RHI::AttachmentId UiCanvasComponent::UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size)
|
||||
{
|
||||
// Create a render target that UI elements will render to
|
||||
AZ::RHI::ImageDescriptor imageDesc;
|
||||
imageDesc.m_bindFlags = AZ::RHI::ImageBindFlags::Color | AZ::RHI::ImageBindFlags::ShaderReadWrite;
|
||||
imageDesc.m_size = size;
|
||||
imageDesc.m_format = AZ::RHI::Format::R8G8B8A8_UNORM;
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImagePool> pool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool();
|
||||
auto attachmentImage = AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, renderTargetName);
|
||||
if (!attachmentImage)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create render target");
|
||||
return AZ::RHI::AttachmentId();
|
||||
}
|
||||
|
||||
m_attachmentImageMap[attachmentImage->GetAttachmentId()] = attachmentImage;
|
||||
|
||||
// Notify LyShine render pass that it needs to rebuild
|
||||
QueueRttPassRebuild();
|
||||
|
||||
return attachmentImage->GetAttachmentId();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId)
|
||||
{
|
||||
m_attachmentImageMap.erase(attachmentId);
|
||||
|
||||
// Notify LyShine render pass that it needs to rebuild
|
||||
QueueRttPassRebuild();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> UiCanvasComponent::GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId)
|
||||
{
|
||||
return m_attachmentImageMap[attachmentId];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::UpdateCanvas(float deltaTime, bool isInGame)
|
||||
{
|
||||
@@ -1864,6 +1916,8 @@ void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, Ui
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderInEditor = uiRenderer ? true : false;
|
||||
|
||||
if (!uiRenderer)
|
||||
{
|
||||
uiRenderer = GetUiRendererForGame();
|
||||
@@ -1948,6 +2002,12 @@ void UiCanvasComponent::ScheduleElementDestroy(AZ::EntityId entityId)
|
||||
m_elementsScheduledForDestroy.push_back(entityId);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies)
|
||||
{
|
||||
m_renderGraph.GetRenderTargetsAndDependencies(attachmentImagesAndDependencies);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::DestroyScheduledElements()
|
||||
{
|
||||
@@ -1959,6 +2019,17 @@ void UiCanvasComponent::DestroyScheduledElements()
|
||||
m_elementsScheduledForDestroy.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::QueueRttPassRebuild()
|
||||
{
|
||||
UiRenderer* uiRenderer = m_renderInEditor ? GetUiRendererForEditor() : GetUiRendererForGame();
|
||||
if (uiRenderer && uiRenderer->GetViewportContext()) // can be null in automated testing
|
||||
{
|
||||
AZ::RPI::SceneId sceneId = uiRenderer->GetViewportContext()->GetRenderScene()->GetId();
|
||||
EBUS_EVENT_ID(sceneId, LyShinePassRequestBus, RebuildRttChildren);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _RELEASE
|
||||
void UiCanvasComponent::GetDebugInfoInteractables(AZ::EntityId& activeInteractable, AZ::EntityId& hoverInteractable) const
|
||||
@@ -2350,6 +2421,7 @@ void UiCanvasComponent::Activate()
|
||||
UiCanvasComponentImplementationBus::Handler::BusConnect(m_entity->GetId());
|
||||
UiEditorCanvasBus::Handler::BusConnect(m_entity->GetId());
|
||||
UiAnimationBus::Handler::BusConnect(m_entity->GetId());
|
||||
LyShine::RenderToTextureRequestBus::Handler::BusConnect(m_entity->GetId());
|
||||
|
||||
// Reconnect to buses that we connect to intermittently
|
||||
// This will only happen if we have been deactivated and reactivated at runtime
|
||||
@@ -2382,6 +2454,7 @@ void UiCanvasComponent::Deactivate()
|
||||
UiCanvasComponentImplementationBus::Handler::BusDisconnect();
|
||||
UiEditorCanvasBus::Handler::BusDisconnect();
|
||||
UiAnimationBus::Handler::BusDisconnect();
|
||||
LyShine::RenderToTextureRequestBus::Handler::BusDisconnect();
|
||||
|
||||
// disconnect from any other buses we could be connected to
|
||||
if (m_hoverInteractable.IsValid() && AZ::EntityBus::Handler::BusIsConnectedId(m_hoverInteractable))
|
||||
@@ -2400,6 +2473,12 @@ void UiCanvasComponent::Deactivate()
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
|
||||
// Destroy owned render targets
|
||||
m_attachmentImageMap.clear();
|
||||
|
||||
//! Notify LyShine pass that it needs to rebuild
|
||||
QueueRttPassRebuild();
|
||||
|
||||
delete m_layoutManager;
|
||||
m_layoutManager = nullptr;
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "TextureAtlas/TextureAtlasBus.h"
|
||||
#include "TextureAtlas/TextureAtlasNotificationBus.h"
|
||||
|
||||
#include "RenderToTextureBus.h"
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class SerializeContext;
|
||||
@@ -51,6 +53,7 @@ class UiCanvasComponent
|
||||
, public IUiAnimationListener
|
||||
, public UiEditorCanvasBus::Handler
|
||||
, public UiCanvasComponentImplementationBus::Handler
|
||||
, public LyShine::RenderToTextureRequestBus::Handler
|
||||
{
|
||||
public: // constants
|
||||
static const AZ::Vector2 s_defaultCanvasSize;
|
||||
@@ -232,6 +235,12 @@ public: // member functions
|
||||
void MarkRenderGraphDirty() override;
|
||||
// ~UiCanvasComponentImplementationInterface
|
||||
|
||||
// RenderToTextureRequests
|
||||
AZ::RHI::AttachmentId UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) override;
|
||||
void ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override;
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override;
|
||||
// ~RenderToTextureRequests
|
||||
|
||||
void UpdateCanvas(float deltaTime, bool isInGame);
|
||||
void RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, UiRenderer* uiRenderer = nullptr);
|
||||
|
||||
@@ -257,6 +266,10 @@ public: // member functions
|
||||
//! Queue an element to be destroyed at end of frame
|
||||
void ScheduleElementDestroy(AZ::EntityId entityId);
|
||||
|
||||
bool IsRenderGraphDirty() { return m_renderGraph.GetDirtyFlag(); }
|
||||
|
||||
void GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies);
|
||||
|
||||
#ifndef _RELEASE
|
||||
struct DebugInfoNumElements
|
||||
{
|
||||
@@ -427,6 +440,9 @@ private: // member functions
|
||||
|
||||
void DestroyScheduledElements();
|
||||
|
||||
//! Notify LyShine pass that it needs to rebuild its Rtt child passes
|
||||
void QueueRttPassRebuild();
|
||||
|
||||
private: // static member functions
|
||||
|
||||
static AZ::u64 CreateUniqueId();
|
||||
@@ -597,4 +613,8 @@ private: // static data
|
||||
|
||||
LyShine::RenderGraph m_renderGraph; //!< the render graph for rendering the canvas, can be cached between frames
|
||||
bool m_isRendering = false;
|
||||
bool m_renderInEditor = false; //!< indicates whether this canvas will render in the Editor viewport or the Game viewport
|
||||
|
||||
//! Map of attachments used by this canvas's elements
|
||||
AZStd::unordered_map<AZ::RHI::AttachmentId, AZ::Data::Instance<AZ::RPI::AttachmentImage>> m_attachmentImageMap;
|
||||
};
|
||||
|
||||
@@ -301,6 +301,17 @@ void UiCanvasManager::OnFontTextureUpdated([[maybe_unused]] IFFont* font)
|
||||
m_fontTextureHasChanged = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasManager::GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies)
|
||||
{
|
||||
for (auto canvas : m_loadedCanvases)
|
||||
{
|
||||
LyShine::AttachmentImagesAndDependencies canvasTargets;
|
||||
canvas->GetRenderTargets(canvasTargets);
|
||||
attachmentImagesAndDependencies.insert(attachmentImagesAndDependencies.end(), canvasTargets.begin(), canvasTargets.end());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasManager::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
@@ -606,13 +617,6 @@ void UiCanvasManager::RenderLoadedCanvases()
|
||||
m_fontTextureHasChanged = false;
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // render target conversion to Atom
|
||||
// clear the stencil buffer before rendering the loaded canvases - required for masking
|
||||
// NOTE: We want to use ClearTargetsImmediately instead of ClearTargetsLater since we will not be setting the render target
|
||||
ColorF viewportBackgroundColor(0, 0, 0, 0); // if clearing color we want to set alpha to zero also
|
||||
gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR_STENCIL, viewportBackgroundColor);
|
||||
#endif
|
||||
|
||||
for (auto canvas : m_loadedCanvases)
|
||||
{
|
||||
if (!canvas->GetIsRenderToTexture())
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <LyShine/Bus/UiCanvasManagerBus.h>
|
||||
#include <LyShine/Bus/UiCanvasBus.h>
|
||||
#include <LyShine/UiEntityContext.h>
|
||||
#include "LyShinePassDataBus.h"
|
||||
#include <IFont.h>
|
||||
|
||||
class UiCanvasComponent;
|
||||
@@ -92,6 +93,9 @@ public: // member functions
|
||||
bool HandleInputEventForLoadedCanvases(const AzFramework::InputChannel& inputChannel);
|
||||
bool HandleTextEventForLoadedCanvases(const AZStd::string& textUTF8);
|
||||
|
||||
// Get the render targets used by all currently loaded UI Canvases
|
||||
void GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies);
|
||||
|
||||
#ifndef _RELEASE
|
||||
void DebugDisplayCanvasData(int setting) const;
|
||||
void DebugDisplayDrawCallData() const;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
#include "UiFaderComponent.h"
|
||||
#include "RenderGraph.h"
|
||||
#include <LyShine/Draw2d.h>
|
||||
|
||||
#include <AzCore/Math/Crc.h>
|
||||
@@ -14,6 +15,9 @@
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/AttachmentImage.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
|
||||
#include <LyShine/Bus/UiElementBus.h>
|
||||
#include <LyShine/Bus/UiRenderBus.h>
|
||||
#include <LyShine/Bus/UiCanvasBus.h>
|
||||
@@ -22,6 +26,7 @@
|
||||
#include <ITimer.h>
|
||||
|
||||
#include "UiSerialize.h"
|
||||
#include "RenderToTextureBus.h"
|
||||
|
||||
// BehaviorContext UiFaderNotificationBus forwarder
|
||||
class BehaviorUiFaderNotificationBusHandler
|
||||
@@ -120,7 +125,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter
|
||||
AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft;
|
||||
|
||||
bool needsResize = static_cast<int>(renderTargetSize.GetX()) != m_renderTargetWidth || static_cast<int>(renderTargetSize.GetY()) != m_renderTargetHeight;
|
||||
if (m_renderTargetHandle == -1 || needsResize)
|
||||
if (m_attachmentImageId.IsEmpty() || needsResize)
|
||||
{
|
||||
// We delay first creation of the render target until render time since size is not known in Activate
|
||||
// We also call this if the size has changed
|
||||
@@ -128,7 +133,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter
|
||||
}
|
||||
|
||||
// if the render target failed to be created (zero size for example) we don't render the element at all
|
||||
if (m_renderTargetHandle == -1)
|
||||
if (m_attachmentImageId.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -139,7 +144,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter
|
||||
else
|
||||
{
|
||||
// destroy previous render target, if exists
|
||||
if (m_renderTargetHandle != -1)
|
||||
if (!m_attachmentImageId.IsEmpty())
|
||||
{
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
@@ -452,54 +457,22 @@ void UiFaderComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligne
|
||||
m_viewportTopLeft = pixelAlignedTopLeft;
|
||||
m_viewportSize = renderTargetSize;
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom
|
||||
// Check if the render target already exists
|
||||
if (m_renderTargetHandle != -1)
|
||||
{
|
||||
// Render target exists, resize it to the given size
|
||||
if (!gEnv->pRenderer->ResizeRenderTarget(m_renderTargetHandle, static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY())))
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to resize render target for UiFaderComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a render target that this element and its children will be rendered to.
|
||||
m_renderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_renderTargetName.c_str(),
|
||||
static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8);
|
||||
// LYSHINE_ATOM_TODO: optimize by reusing/resizing targets
|
||||
DestroyRenderTarget();
|
||||
|
||||
if (m_renderTargetHandle == -1)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create render target for UiFaderComponent");
|
||||
}
|
||||
}
|
||||
|
||||
// if depth surface already exists then destroy it
|
||||
if (m_renderTargetDepthSurface)
|
||||
// Create a render target that this element and its children will be rendered to
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
AZ::RHI::Size imageSize(renderTargetSize.GetX(), renderTargetSize.GetY(), 1);
|
||||
EBUS_EVENT_ID_RESULT(m_attachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_renderTargetName.c_str()), imageSize);
|
||||
if (m_attachmentImageId.IsEmpty())
|
||||
{
|
||||
gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface);
|
||||
m_renderTargetDepthSurface = nullptr;
|
||||
AZ_Warning("UI", false, "Failed to create render target for UiFaderComponent");
|
||||
}
|
||||
|
||||
if (m_renderTargetHandle != -1)
|
||||
{
|
||||
// Also create a depth surface to render the canvas to, we need depth for masking
|
||||
// since that uses the stencil buffer. We support any combination of nesting faders and masks
|
||||
m_renderTargetDepthSurface = gEnv->pRenderer->CreateDepthSurface(
|
||||
static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY()));
|
||||
|
||||
if (!m_renderTargetDepthSurface)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create depth surface for UiFaderComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// at this point either all render targets and depth surfaces are created or none are.
|
||||
// If all succeeded then update the render target size
|
||||
if (m_renderTargetHandle != -1)
|
||||
if (!m_attachmentImageId.IsEmpty())
|
||||
{
|
||||
m_renderTargetWidth = static_cast<int>(renderTargetSize.GetX());
|
||||
m_renderTargetHeight = static_cast<int>(renderTargetSize.GetY());
|
||||
@@ -511,16 +484,12 @@ void UiFaderComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligne
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiFaderComponent::DestroyRenderTarget()
|
||||
{
|
||||
if (m_renderTargetHandle != -1)
|
||||
if (!m_attachmentImageId.IsEmpty())
|
||||
{
|
||||
gEnv->pRenderer->DestroyRenderTarget(m_renderTargetHandle);
|
||||
m_renderTargetHandle = -1;
|
||||
}
|
||||
|
||||
if (m_renderTargetDepthSurface)
|
||||
{
|
||||
gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface);
|
||||
m_renderTargetDepthSurface = nullptr;
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_attachmentImageId);
|
||||
m_attachmentImageId = AZ::RHI::AttachmentId{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,14 +563,20 @@ void UiFaderComponent::RenderStandardFader(LyShine::IRenderGraph* renderGraph, U
|
||||
void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface,
|
||||
UiRenderInterface* renderInterface, int numChildren, bool isInGame)
|
||||
{
|
||||
// Get the render target
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage;
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
EBUS_EVENT_ID_RESULT(attachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_attachmentImageId);
|
||||
|
||||
// Render the element and its children to a render target
|
||||
{
|
||||
// we always clear to transparent black - the accumulation of alpha in the render target requires it
|
||||
AZ::Color clearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Start building the render to texture node in the render graph
|
||||
renderGraph->BeginRenderToTexture(m_renderTargetHandle, m_renderTargetDepthSurface,
|
||||
m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
|
||||
lyRenderGraph->BeginRenderToTexture(attachmentImage, m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
|
||||
// We don't want this fader or parent faders to affect what is rendered to the render target since we will
|
||||
// apply those fades when we render from the render target.
|
||||
@@ -624,14 +599,13 @@ void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElem
|
||||
float desiredAlpha = renderGraph->GetAlphaFade() * m_fade;
|
||||
uint8 desiredPackedAlpha = static_cast<uint8>(desiredAlpha * 255.0f);
|
||||
|
||||
UCol desiredPackedColor;
|
||||
// This is a special case. We have an input texture that already has premultiplied alpha.
|
||||
// So we tell the shader not to premultiply the output colors and we premultiply the alpha
|
||||
// into the vertex colors so that they are premultiplied too.
|
||||
desiredPackedColor.r = desiredPackedColor.g = desiredPackedColor.b = desiredPackedColor.a = desiredPackedAlpha;
|
||||
if (m_cachedPrimitive.m_vertices[0].color.dcolor != desiredPackedColor.dcolor)
|
||||
// If the fade value has changed we need to update the alpha values in the vertex colors but we do
|
||||
// not want to touch or recompute the RGB values
|
||||
if (m_cachedPrimitive.m_vertices[0].color.a != desiredPackedAlpha)
|
||||
{
|
||||
// go through the cached vertices and update the color values
|
||||
// go through all the cached vertices and update the alpha values
|
||||
UCol desiredPackedColor = m_cachedPrimitive.m_vertices[0].color;
|
||||
desiredPackedColor.a = desiredPackedAlpha;
|
||||
for (int i = 0; i < m_cachedPrimitive.m_numVertices; ++i)
|
||||
{
|
||||
m_cachedPrimitive.m_vertices[i].color = desiredPackedColor;
|
||||
@@ -639,21 +613,20 @@ void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElem
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom
|
||||
// Add a primitive to render a quad using the render target we have created
|
||||
{
|
||||
// Set the texture and other render state required
|
||||
ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_renderTargetHandle);
|
||||
bool isClampTextureMode = true;
|
||||
bool isTextureSRGB = true;
|
||||
bool isTexturePremultipliedAlpha = true;
|
||||
LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
|
||||
|
||||
// add a render node to render from the render target texture to the current target
|
||||
renderGraph->AddPrimitive(&m_cachedPrimitive, texture,
|
||||
isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
|
||||
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
|
||||
if (lyRenderGraph)
|
||||
{
|
||||
// Set the texture and other render state required
|
||||
AZ::Data::Instance<AZ::RPI::Image> image = attachmentImage;
|
||||
bool isClampTextureMode = true;
|
||||
bool isTextureSRGB = true;
|
||||
bool isTexturePremultipliedAlpha = true;
|
||||
LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
|
||||
lyRenderGraph->AddPrimitiveAtom(&m_cachedPrimitive, image, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <Atom/RHI.Reflect/AttachmentId.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class UiFaderComponent
|
||||
@@ -156,11 +157,8 @@ private: // data
|
||||
//! This is generated from the entity ID and cached
|
||||
AZStd::string m_renderTargetName;
|
||||
|
||||
//! When rendering to a texture this is the texture ID of the render target
|
||||
int m_renderTargetHandle = -1;
|
||||
|
||||
//! When rendering to a texture this is our depth surface
|
||||
SDepthTexture* m_renderTargetDepthSurface = nullptr;
|
||||
//! When rendering to a texture this is the attachment image for the render target
|
||||
AZ::RHI::AttachmentId m_attachmentImageId;
|
||||
|
||||
//! The positions used for the render to texture viewport and to render the render target to the screen
|
||||
AZ::Vector2 m_viewportTopLeft;
|
||||
|
||||
@@ -14,12 +14,17 @@
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
#include "IRenderer.h"
|
||||
#include "RenderToTextureBus.h"
|
||||
#include "RenderGraph.h"
|
||||
#include <LyShine/Bus/UiTransformBus.h>
|
||||
#include <LyShine/Bus/UiElementBus.h>
|
||||
#include <LyShine/Bus/UiRenderBus.h>
|
||||
#include <LyShine/Bus/UiVisualBus.h>
|
||||
#include <LyShine/Bus/UiCanvasBus.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/AttachmentImage.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC MEMBER FUNCTIONS
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -79,7 +84,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf
|
||||
AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft;
|
||||
|
||||
bool needsResize = static_cast<int>(renderTargetSize.GetX()) != m_renderTargetWidth || static_cast<int>(renderTargetSize.GetY()) != m_renderTargetHeight;
|
||||
if (m_contentRenderTargetHandle == -1 || needsResize)
|
||||
if (m_contentAttachmentImageId.IsEmpty() || needsResize)
|
||||
{
|
||||
// Need to create or resize the render target
|
||||
CreateOrResizeRenderTarget(pixelAlignedTopLeft, pixelAlignedBottomRight);
|
||||
@@ -89,7 +94,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf
|
||||
// in theory the child mask element could still be non-zero size and could reveal things. But the way gradient masks
|
||||
// currently work is that the size of the render target is defined by the size of this element, therefore nothing would
|
||||
// be revealed by the mask if it is zero sized.
|
||||
if (m_contentRenderTargetHandle == -1)
|
||||
if (m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -101,7 +106,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf
|
||||
else
|
||||
{
|
||||
// using stencil mask, not going to use render targets, destroy previous render target, if exists
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
if (!m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
@@ -113,7 +118,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf
|
||||
else
|
||||
{
|
||||
// masking disabled, not going to use render targets, destroy previous render target, if exists
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
if (!m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
@@ -553,77 +558,30 @@ void UiMaskComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligned
|
||||
m_viewportTopLeft = pixelAlignedTopLeft;
|
||||
m_viewportSize = renderTargetSize;
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom
|
||||
// Check if the render target already exists
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
{
|
||||
// Render target exists, resize it to the given size
|
||||
if (!gEnv->pRenderer->ResizeRenderTarget(m_contentRenderTargetHandle, static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY())))
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to resize content render target for UiMaskComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a render target that this element and its children will be rendered to.
|
||||
m_contentRenderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_renderTargetName.c_str(),
|
||||
static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8);
|
||||
// LYSHINE_ATOM_TODO: optimize by reusing/resizing targets
|
||||
DestroyRenderTarget();
|
||||
|
||||
if (m_contentRenderTargetHandle == -1)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create content render target for UiMaskComponent");
|
||||
}
|
||||
// Create a render target that this element and its children will be rendered to
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
AZ::RHI::Size imageSize(renderTargetSize.GetX(), renderTargetSize.GetY(), 1);
|
||||
EBUS_EVENT_ID_RESULT(m_contentAttachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_renderTargetName.c_str()), imageSize);
|
||||
if (m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create content render target for UiMaskComponent");
|
||||
}
|
||||
|
||||
// if depth surface already exists then destroy it
|
||||
if (m_renderTargetDepthSurface)
|
||||
// Create separate render target for the mask texture
|
||||
EBUS_EVENT_ID_RESULT(m_maskAttachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_maskRenderTargetName.c_str()), imageSize);
|
||||
if (m_maskAttachmentImageId.IsEmpty())
|
||||
{
|
||||
gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface);
|
||||
m_renderTargetDepthSurface = nullptr;
|
||||
AZ_Warning("UI", false, "Failed to create mask render target for UiMaskComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
{
|
||||
// Also create a depth surface to render the canvas to, we need depth for masking
|
||||
// since that uses the stencil buffer. We support any combination of nesting faders and masks
|
||||
m_renderTargetDepthSurface = gEnv->pRenderer->CreateDepthSurface(
|
||||
static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY()));
|
||||
|
||||
if (!m_renderTargetDepthSurface)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create depth surface for UiMaskComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the mask render target already exists
|
||||
if (m_maskRenderTargetHandle != -1)
|
||||
{
|
||||
// Render target exists, resize it to the given size
|
||||
if (!gEnv->pRenderer->ResizeRenderTarget(m_maskRenderTargetHandle, static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY())))
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to resize mask render target for UiMaskComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create separate render target for the mask texture
|
||||
m_maskRenderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_maskRenderTargetName.c_str(),
|
||||
static_cast<int>(renderTargetSize.GetX()), static_cast<int>(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8);
|
||||
|
||||
if (m_maskRenderTargetHandle == -1)
|
||||
{
|
||||
AZ_Warning("UI", false, "Failed to create mask render target for UiMaskComponent");
|
||||
DestroyRenderTarget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// at this point either all render targets and depth surfaces are created or none are.
|
||||
// If all succeeded then update the render target size
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
if (!m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
m_renderTargetWidth = static_cast<int>(renderTargetSize.GetX());
|
||||
m_renderTargetHeight = static_cast<int>(renderTargetSize.GetY());
|
||||
@@ -635,22 +593,22 @@ void UiMaskComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligned
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiMaskComponent::DestroyRenderTarget()
|
||||
{
|
||||
if (m_contentRenderTargetHandle != -1)
|
||||
if (!m_contentAttachmentImageId.IsEmpty())
|
||||
{
|
||||
gEnv->pRenderer->DestroyRenderTarget(m_contentRenderTargetHandle);
|
||||
m_contentRenderTargetHandle = -1;
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_contentAttachmentImageId);
|
||||
|
||||
m_contentAttachmentImageId = AZ::RHI::AttachmentId{};
|
||||
}
|
||||
|
||||
if (m_renderTargetDepthSurface)
|
||||
if (!m_maskAttachmentImageId.IsEmpty())
|
||||
{
|
||||
gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface);
|
||||
m_renderTargetDepthSurface = nullptr;
|
||||
}
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_maskAttachmentImageId);
|
||||
|
||||
if (m_maskRenderTargetHandle != -1)
|
||||
{
|
||||
gEnv->pRenderer->DestroyRenderTarget(m_maskRenderTargetHandle);
|
||||
m_maskRenderTargetHandle = -1;
|
||||
m_maskAttachmentImageId = AZ::RHI::AttachmentId{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,6 +705,14 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph
|
||||
// we always clear to transparent black - the accumulation of alpha in the render target requires it
|
||||
AZ::Color clearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Get the render targets
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> contentAttachmentImage;
|
||||
AZ::Data::Instance<AZ::RPI::AttachmentImage> maskAttachmentImage;
|
||||
AZ::EntityId canvasEntityId;
|
||||
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
||||
EBUS_EVENT_ID_RESULT(contentAttachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_contentAttachmentImageId);
|
||||
EBUS_EVENT_ID_RESULT(maskAttachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_maskAttachmentImageId);
|
||||
|
||||
// We don't want parent faders to affect what is rendered to the render target since we will
|
||||
// apply those fades when we render from the render target.
|
||||
// Note that this means that, if there are parent (no render to texture) faders, we get a "free"
|
||||
@@ -756,8 +722,8 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph
|
||||
// mask render target
|
||||
{
|
||||
// Start building the render to texture node in the render graph
|
||||
renderGraph->BeginRenderToTexture(m_maskRenderTargetHandle, m_renderTargetDepthSurface,
|
||||
m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
|
||||
lyRenderGraph->BeginRenderToTexture(maskAttachmentImage, m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
|
||||
// Render the visual component for this element (if there is one) plus the child mask element (if there is one)
|
||||
RenderMaskPrimitives(renderGraph, renderInterface, childMaskElementInterface, isInGame);
|
||||
@@ -769,8 +735,8 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph
|
||||
// content render target
|
||||
{
|
||||
// Start building the render to texture node for the content render target in the render graph
|
||||
renderGraph->BeginRenderToTexture(m_contentRenderTargetHandle, m_renderTargetDepthSurface,
|
||||
m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
|
||||
lyRenderGraph->BeginRenderToTexture(contentAttachmentImage, m_viewportTopLeft, m_viewportSize, clearColor);
|
||||
|
||||
// Render the "content" - the child elements excluding the child mask element (if any)
|
||||
RenderContentPrimitives(renderGraph, elementInterface, childMaskElementInterface, numChildren, isInGame);
|
||||
@@ -790,14 +756,13 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph
|
||||
float desiredAlpha = renderGraph->GetAlphaFade();
|
||||
uint32 desiredPackedAlpha = static_cast<uint8>(desiredAlpha * 255.0f);
|
||||
|
||||
UCol desiredPackedColor;
|
||||
// This is a special case. We have an input texture that already has premultiplied alpha.
|
||||
// So we tell the shader not to premultiply the output colors and we premultiply the alpha
|
||||
// into the vertex colors so that they are premultiplied too.
|
||||
desiredPackedColor.r = desiredPackedColor.g = desiredPackedColor.b = desiredPackedColor.a = desiredPackedAlpha;
|
||||
if (m_cachedPrimitive.m_vertices[0].color.dcolor != desiredPackedColor.dcolor)
|
||||
// If the fade value has changed we need to update the alpha values in the vertex colors but we do
|
||||
// not want to touch or recompute the RGB values
|
||||
if (m_cachedPrimitive.m_vertices[0].color.a != desiredPackedAlpha)
|
||||
{
|
||||
// go through the cached vertices and update the color values
|
||||
// go through all the cached vertices and update the alpha values
|
||||
UCol desiredPackedColor = m_cachedPrimitive.m_vertices[0].color;
|
||||
desiredPackedColor.a = desiredPackedAlpha;
|
||||
for (int i = 0; i < m_cachedPrimitive.m_numVertices; ++i)
|
||||
{
|
||||
m_cachedPrimitive.m_vertices[i].color = desiredPackedColor;
|
||||
@@ -805,22 +770,29 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom
|
||||
// Add a primitive to do the alpha mask
|
||||
{
|
||||
// Set the texture and other render state required
|
||||
ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_contentRenderTargetHandle);
|
||||
ITexture* maskTexture = gEnv->pRenderer->EF_GetTextureByID(m_maskRenderTargetHandle);
|
||||
bool isClampTextureMode = true;
|
||||
bool isTextureSRGB = true;
|
||||
bool isTexturePremultipliedAlpha = true;
|
||||
LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
|
||||
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
|
||||
if (lyRenderGraph)
|
||||
{
|
||||
// Set the texture and other render state required
|
||||
AZ::Data::Instance<AZ::RPI::Image> contentImage = contentAttachmentImage;
|
||||
AZ::Data::Instance<AZ::RPI::Image> maskImage = maskAttachmentImage;
|
||||
bool isClampTextureMode = true;
|
||||
bool isTextureSRGB = true;
|
||||
bool isTexturePremultipliedAlpha = false;
|
||||
LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
|
||||
|
||||
// add a render node to render using the two render targets, one as an alpha mask of the other
|
||||
renderGraph->AddAlphaMaskPrimitive(&m_cachedPrimitive, texture, maskTexture,
|
||||
isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
|
||||
// add a render node to render using the two render targets, one as an alpha mask of the other
|
||||
lyRenderGraph->AddAlphaMaskPrimitiveAtom(&m_cachedPrimitive,
|
||||
contentAttachmentImage,
|
||||
maskAttachmentImage,
|
||||
isClampTextureMode,
|
||||
isTextureSRGB,
|
||||
isTexturePremultipliedAlpha,
|
||||
blendMode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <LyShine/IRenderGraph.h>
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <Atom/RHI.Reflect/AttachmentId.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class UiMaskComponent
|
||||
@@ -184,15 +185,16 @@ private: // data
|
||||
//! This is generated from the entity ID and cached
|
||||
AZStd::string m_maskRenderTargetName;
|
||||
|
||||
//! When rendering to a texture this is the texture ID of the render target
|
||||
int m_contentRenderTargetHandle = -1;
|
||||
//! When rendering to a texture this is the attachment image for the render target
|
||||
AZ::RHI::AttachmentId m_contentAttachmentImageId;
|
||||
|
||||
//! When rendering to a texture this is our depth surface, we use the same one for rendering the mask elements
|
||||
//! and the content elements - it is cleared in between.
|
||||
SDepthTexture* m_renderTargetDepthSurface = nullptr;
|
||||
|
||||
//! When rendering to a texture this is the texture ID of the render target
|
||||
int m_maskRenderTargetHandle = -1;
|
||||
//! When rendering to a texture this is the attachment image for the render target
|
||||
AZ::RHI::AttachmentId m_maskAttachmentImageId;
|
||||
|
||||
//! The positions used for the render to texture viewport and to render the render target to the screen
|
||||
AZ::Vector2 m_viewportTopLeft = AZ::Vector2::CreateZero();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
#include "UiRenderer.h"
|
||||
#include "LyShinePassDataBus.h"
|
||||
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
|
||||
@@ -60,25 +61,32 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra
|
||||
AZ::Data::Instance<AZ::RPI::Shader> uiShader = AZ::RPI::LoadShader(uiShaderFilepath);
|
||||
|
||||
// Create scene to be used by the dynamic draw context
|
||||
AZ::RPI::ScenePtr scene;
|
||||
if (m_viewportContext)
|
||||
{
|
||||
// Create a new scene based on the user specified viewport context
|
||||
scene = CreateScene(m_viewportContext);
|
||||
m_scene = CreateScene(m_viewportContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No viewport context specified, use default scene
|
||||
scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
|
||||
m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
|
||||
}
|
||||
|
||||
// Create a dynamic draw context for UI Canvas drawing for the scene
|
||||
CreateDynamicDrawContext(scene, uiShader);
|
||||
m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader);
|
||||
|
||||
// Cache shader data such as input indices for later use
|
||||
CacheShaderData(m_dynamicDraw);
|
||||
if (m_dynamicDraw)
|
||||
{
|
||||
// Cache shader data such as input indices for later use
|
||||
CacheShaderData(m_dynamicDraw);
|
||||
|
||||
m_isRPIReady = true;
|
||||
m_isRPIReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(LogName, false, "Failed to create a dynamic draw context for LyShine. \
|
||||
This can happen if the LyShine pass hasn't been added to the main render pipeline.");
|
||||
}
|
||||
}
|
||||
|
||||
AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportContext> viewportContext)
|
||||
@@ -107,22 +115,40 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportCon
|
||||
return atomScene;
|
||||
}
|
||||
|
||||
void UiRenderer::CreateDynamicDrawContext(AZ::RPI::ScenePtr scene, AZ::Data::Instance<AZ::RPI::Shader> uiShader)
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContext(
|
||||
AZ::RPI::ScenePtr scene,
|
||||
AZ::Data::Instance<AZ::RPI::Shader> uiShader)
|
||||
{
|
||||
m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
|
||||
// Find the pass that renders the UI canvases after the rtt passes
|
||||
AZ::RPI::RasterPass* uiCanvasPass = nullptr;
|
||||
AZ::RPI::SceneId sceneId = m_scene->GetId();
|
||||
LyShinePassRequestBus::EventResult(uiCanvasPass, sceneId, &LyShinePassRequestBus::Events::GetUiCanvasPass);
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
|
||||
|
||||
// Initialize the dynamic draw context
|
||||
m_dynamicDraw->InitShader(uiShader);
|
||||
m_dynamicDraw->InitVertexFormat(
|
||||
dynamicDraw->InitShader(uiShader);
|
||||
dynamicDraw->InitVertexFormat(
|
||||
{ { "POSITION", AZ::RHI::Format::R32G32_FLOAT },
|
||||
{ "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM },
|
||||
{ "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT },
|
||||
{ "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } }
|
||||
);
|
||||
m_dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState
|
||||
dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState
|
||||
| AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
|
||||
m_dynamicDraw->SetOutputScope(scene.get());
|
||||
m_dynamicDraw->EndInit();
|
||||
|
||||
if (uiCanvasPass)
|
||||
{
|
||||
dynamicDraw->SetOutputScope(uiCanvasPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Render target support is disabled
|
||||
dynamicDraw->SetOutputScope(m_scene.get());
|
||||
}
|
||||
dynamicDraw->EndInit();
|
||||
|
||||
return dynamicDraw;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AZ::RPI::ViewportContext> UiRenderer::GetViewportContext()
|
||||
@@ -158,19 +184,26 @@ void UiRenderer::CacheShaderData(const AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext>
|
||||
isClampIndexName);
|
||||
|
||||
// Cache shader variants that will be used
|
||||
// LYSHINE_ATOM_TODO - more variants will be used in future phase (masks/render target support)
|
||||
AZ::RPI::ShaderOptionList shaderOptionsDefault;
|
||||
shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_preMultiplyAlpha"), AZ::Name("false")));
|
||||
shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
|
||||
shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true")));
|
||||
shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
|
||||
m_uiShaderData.m_shaderVariantDefault = dynamicDraw->UseShaderVariant(shaderOptionsDefault);
|
||||
AZ::RPI::ShaderOptionList shaderOptionsAlphaTest;
|
||||
shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_preMultiplyAlpha"), AZ::Name("false")));
|
||||
shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true")));
|
||||
shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true")));
|
||||
shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
|
||||
m_uiShaderData.m_shaderVariantAlphaTest = dynamicDraw->UseShaderVariant(shaderOptionsAlphaTest);
|
||||
AZ::RPI::ShaderOptionList shaderOptionsTextureLinear;
|
||||
shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
|
||||
shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true")));
|
||||
shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
|
||||
m_uiShaderData.m_shaderVariantTextureLinear = dynamicDraw->UseShaderVariant(shaderOptionsTextureLinear);
|
||||
AZ::RPI::ShaderOptionList shaderOptionsTextureSrgb;
|
||||
shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
|
||||
shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
|
||||
shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
|
||||
m_uiShaderData.m_shaderVariantTextureSrgb = dynamicDraw->UseShaderVariant(shaderOptionsTextureSrgb);
|
||||
AZ::RPI::ShaderOptionList shaderVariantAlphaTestMask;
|
||||
shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true")));
|
||||
shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
|
||||
shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
|
||||
m_uiShaderData.m_shaderVariantAlphaTestMask = dynamicDraw->UseShaderVariant(shaderVariantAlphaTestMask);
|
||||
AZ::RPI::ShaderOptionList shaderVariantGradientMask;
|
||||
shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
|
||||
shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
|
||||
shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::Alpha")));
|
||||
m_uiShaderData.m_shaderVariantGradientMask = dynamicDraw->UseShaderVariant(shaderVariantGradientMask);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -215,6 +248,38 @@ AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::GetDynamicDrawContext()
|
||||
return m_dynamicDraw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContextForRTT(const AZStd::string& rttName)
|
||||
{
|
||||
// find the rtt pass with the specified name
|
||||
AZ::RPI::RasterPass* rttPass = nullptr;
|
||||
AZ::RPI::SceneId sceneId = m_scene->GetId();
|
||||
LyShinePassRequestBus::EventResult(rttPass, sceneId, &LyShinePassRequestBus::Events::GetRttPass, rttName);
|
||||
if (!rttPass)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
|
||||
|
||||
// Initialize the dynamic draw context
|
||||
dynamicDraw->InitShader(m_dynamicDraw->GetShader());
|
||||
dynamicDraw->InitVertexFormat(
|
||||
{ { "POSITION", AZ::RHI::Format::R32G32_FLOAT },
|
||||
{ "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM },
|
||||
{ "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT },
|
||||
{ "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } }
|
||||
);
|
||||
dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState
|
||||
| AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
|
||||
|
||||
dynamicDraw->SetOutputScope(rttPass);
|
||||
|
||||
dynamicDraw->EndInit();
|
||||
|
||||
return dynamicDraw;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const UiRenderer::UiShaderData& UiRenderer::GetUiShaderData()
|
||||
{
|
||||
@@ -270,11 +335,27 @@ void UiRenderer::SetBaseState(BaseState state)
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::RPI::ShaderVariantId UiRenderer::GetCurrentShaderVariant()
|
||||
{
|
||||
AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantDefault;
|
||||
AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantTextureLinear;
|
||||
|
||||
if (m_baseState.m_useAlphaTest)
|
||||
{
|
||||
variantId = m_uiShaderData.m_shaderVariantAlphaTest;
|
||||
variantId = m_uiShaderData.m_shaderVariantAlphaTestMask;
|
||||
}
|
||||
else if (m_baseState.m_modulateAlpha)
|
||||
{
|
||||
variantId = m_uiShaderData.m_shaderVariantGradientMask;
|
||||
}
|
||||
else if (!m_baseState.m_useAlphaTest && m_baseState.m_srgbWrite)
|
||||
{
|
||||
variantId = m_uiShaderData.m_shaderVariantTextureLinear;
|
||||
}
|
||||
else if (!m_baseState.m_useAlphaTest && !m_baseState.m_srgbWrite)
|
||||
{
|
||||
variantId = m_uiShaderData.m_shaderVariantTextureSrgb;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(LogName, 0, "Unsupported shader variant.");
|
||||
}
|
||||
|
||||
return variantId;
|
||||
|
||||
@@ -36,8 +36,10 @@ public: // types
|
||||
AZ::RHI::ShaderInputConstantIndex m_viewProjInputIndex;
|
||||
AZ::RHI::ShaderInputConstantIndex m_isClampInputIndex;
|
||||
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantDefault;
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantAlphaTest;
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantTextureLinear;
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantTextureSrgb;
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantAlphaTestMask;
|
||||
AZ::RPI::ShaderVariantId m_shaderVariantGradientMask;
|
||||
};
|
||||
|
||||
// Base state
|
||||
@@ -56,17 +58,23 @@ public: // types
|
||||
m_blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
m_blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
|
||||
m_blendState.m_blendOp = AZ::RHI::BlendOp::Add;
|
||||
m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
|
||||
m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::Zero;
|
||||
m_blendState.m_blendAlphaOp = AZ::RHI::BlendOp::Add;
|
||||
|
||||
// Disable stencil
|
||||
m_stencilState = AZ::RHI::StencilState();
|
||||
m_stencilState.m_enable = 0;
|
||||
|
||||
m_useAlphaTest = false;
|
||||
m_modulateAlpha = false;
|
||||
}
|
||||
|
||||
AZ::RHI::TargetBlendState m_blendState;
|
||||
AZ::RHI::StencilState m_stencilState;
|
||||
bool m_useAlphaTest = false;
|
||||
bool m_modulateAlpha = false;
|
||||
bool m_srgbWrite = true;
|
||||
};
|
||||
|
||||
public: // member functions
|
||||
@@ -93,6 +101,8 @@ public: // member functions
|
||||
//! Return the dynamic draw context associated with this UI renderer
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> GetDynamicDrawContext();
|
||||
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> CreateDynamicDrawContextForRTT(const AZStd::string& rttName);
|
||||
|
||||
//! Return the shader data for the ui shader
|
||||
const UiShaderData& GetUiShaderData();
|
||||
|
||||
@@ -123,6 +133,9 @@ public: // member functions
|
||||
//! Decrement the current stencil reference value
|
||||
void DecrementStencilRef();
|
||||
|
||||
//! Return the viewport context set by the user, or the default if not set
|
||||
AZStd::shared_ptr<AZ::RPI::ViewportContext> GetViewportContext();
|
||||
|
||||
#ifndef _RELEASE
|
||||
//! Setup to record debug texture data before rendering
|
||||
void DebugSetRecordingOptionForTextureData(int recordingOption);
|
||||
@@ -143,10 +156,9 @@ private: // member functions
|
||||
AZ::RPI::ScenePtr CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportContext> viewportContext);
|
||||
|
||||
//! Create a dynamic draw context for this renderer
|
||||
void CreateDynamicDrawContext(AZ::RPI::ScenePtr scene, AZ::Data::Instance<AZ::RPI::Shader>);
|
||||
|
||||
//! Return the viewport context set by the user, or the default if not set
|
||||
AZStd::shared_ptr<AZ::RPI::ViewportContext> GetViewportContext();
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> CreateDynamicDrawContext(
|
||||
AZ::RPI::ScenePtr scene,
|
||||
AZ::Data::Instance<AZ::RPI::Shader> uiShader);
|
||||
|
||||
//! Bind the global white texture for all the texture units we use
|
||||
void BindNullTexture();
|
||||
@@ -168,6 +180,8 @@ protected: // attributes
|
||||
// Set by user when viewport context is not the main/default viewport
|
||||
AZStd::shared_ptr<AZ::RPI::ViewportContext> m_viewportContext;
|
||||
|
||||
AZ::RPI::ScenePtr m_scene;
|
||||
|
||||
#ifndef _RELEASE
|
||||
int m_debugTextureDataRecordLevel = 0;
|
||||
AZStd::unordered_set<ITexture*> m_texturesUsedInFrame; // LYSHINE_ATOM_TODO - convert to RPI::Image
|
||||
|
||||
@@ -163,11 +163,9 @@ namespace UnitTest
|
||||
SSystemGlobalEnvironment* prevEnv = gEnv;
|
||||
gEnv = &env;
|
||||
gEnv->pTimer = &m_timer;
|
||||
gEnv->pLyShine = nullptr;
|
||||
|
||||
UiCanvasComponent* uiCanvasComponent;
|
||||
UiTooltipDisplayComponent* uiTooltipDisplayComponent;
|
||||
UiTooltipComponent* uiTooltipComponent;
|
||||
std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip();
|
||||
auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip();
|
||||
uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover);
|
||||
AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity();
|
||||
|
||||
@@ -193,11 +191,9 @@ namespace UnitTest
|
||||
SSystemGlobalEnvironment* prevEnv = gEnv;
|
||||
gEnv = &env;
|
||||
gEnv->pTimer = &m_timer;
|
||||
gEnv->pLyShine = nullptr;
|
||||
|
||||
UiCanvasComponent* uiCanvasComponent;
|
||||
UiTooltipDisplayComponent* uiTooltipDisplayComponent;
|
||||
UiTooltipComponent* uiTooltipComponent;
|
||||
std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip();
|
||||
auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip();
|
||||
uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover);
|
||||
AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity();
|
||||
|
||||
@@ -221,11 +217,9 @@ namespace UnitTest
|
||||
SSystemGlobalEnvironment* prevEnv = gEnv;
|
||||
gEnv = &env;
|
||||
gEnv->pTimer = &m_timer;
|
||||
gEnv->pLyShine = nullptr;
|
||||
|
||||
UiCanvasComponent* uiCanvasComponent;
|
||||
UiTooltipDisplayComponent* uiTooltipDisplayComponent;
|
||||
UiTooltipComponent* uiTooltipComponent;
|
||||
std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip();
|
||||
auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip();
|
||||
uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress);
|
||||
AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity();
|
||||
|
||||
@@ -249,11 +243,9 @@ namespace UnitTest
|
||||
SSystemGlobalEnvironment* prevEnv = gEnv;
|
||||
gEnv = &env;
|
||||
gEnv->pTimer = &m_timer;
|
||||
gEnv->pLyShine = nullptr;
|
||||
|
||||
UiCanvasComponent* uiCanvasComponent;
|
||||
UiTooltipDisplayComponent* uiTooltipDisplayComponent;
|
||||
UiTooltipComponent* uiTooltipComponent;
|
||||
std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip();
|
||||
auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip();
|
||||
uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress);
|
||||
AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity();
|
||||
|
||||
@@ -277,11 +269,9 @@ namespace UnitTest
|
||||
SSystemGlobalEnvironment* prevEnv = gEnv;
|
||||
gEnv = &env;
|
||||
gEnv->pTimer = &m_timer;
|
||||
gEnv->pLyShine = nullptr;
|
||||
|
||||
UiCanvasComponent* uiCanvasComponent;
|
||||
UiTooltipDisplayComponent* uiTooltipDisplayComponent;
|
||||
UiTooltipComponent* uiTooltipComponent;
|
||||
std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip();
|
||||
auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip();
|
||||
uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnClick);
|
||||
AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity();
|
||||
|
||||
|
||||
@@ -11,8 +11,11 @@ set(FILES
|
||||
Include/LyShine/Draw2d.h
|
||||
Source/LyShine.cpp
|
||||
Source/LyShine.h
|
||||
Source/LyShinePassDataBus.h
|
||||
Source/LyShineDebug.cpp
|
||||
Source/LyShineDebug.h
|
||||
Source/LyShinePass.cpp
|
||||
Source/LyShinePass.h
|
||||
Source/StringUtfUtils.h
|
||||
Source/UiImageComponent.cpp
|
||||
Source/UiImageComponent.h
|
||||
@@ -28,6 +31,7 @@ set(FILES
|
||||
Source/LyShineLoadScreen.h
|
||||
Source/RenderGraph.cpp
|
||||
Source/RenderGraph.h
|
||||
Source/RenderToTextureBus.h
|
||||
Source/TextMarkup.cpp
|
||||
Source/TextMarkup.h
|
||||
Source/UiButtonComponent.cpp
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Name": "LyShinePass",
|
||||
"TemplateName": "LyShineParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "ColorInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DebugOverlayPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
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 os
|
||||
import sys
|
||||
|
||||
# Parse arguments
|
||||
if len(sys.argv) != 3:
|
||||
print('Incorrect number of args')
|
||||
exit()
|
||||
|
||||
engine_path = sys.argv[1]
|
||||
if not os.path.exists(engine_path):
|
||||
print(f'Given path {engine_path} does not exist')
|
||||
exit()
|
||||
|
||||
project_path = sys.argv[2]
|
||||
if not os.path.exists(project_path):
|
||||
print(f'Given path {project_path} does not exist')
|
||||
exit()
|
||||
|
||||
sys.path.insert(0, os.path.join(engine_path, 'Gems/Atom/RPI/Tools/'))
|
||||
|
||||
from atom_rpi_tools.pass_data import PassTemplate
|
||||
import atom_rpi_tools.utils as utils
|
||||
|
||||
# Folder of this py file
|
||||
dir_name = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Patch render pipeline to insert a custom LyShine parent pass
|
||||
|
||||
# Gem::Atom_Feature_Common gem's path since default render pipeline is comming from this gem
|
||||
gem_assets_path = os.path.join(engine_path,'Gems/Atom/feature/Common/Assets/')
|
||||
|
||||
pipeline_relatvie_path = 'Passes/MainPipeline.pass'
|
||||
srcRenderPipeline = os.path.join(gem_assets_path, pipeline_relatvie_path)
|
||||
destRenderPipeline = os.path.join(project_path, pipeline_relatvie_path)
|
||||
# If the project doesn't have a customized main pipeline
|
||||
# copy the default render pipeline from Atom_Common_Feature gem to same path in project folder
|
||||
utils.find_or_copy_file(destRenderPipeline, srcRenderPipeline)
|
||||
|
||||
# Load project render pipeline
|
||||
renderPipeline = PassTemplate(destRenderPipeline)
|
||||
|
||||
# Skip if LyShinePass already exist
|
||||
newPassName = 'LyShinePass'
|
||||
if renderPipeline.find_pass(newPassName)>-1:
|
||||
print('Skip merging. LyShinePass already exists')
|
||||
exit()
|
||||
|
||||
# Insert LyShinePass between DebugOverlayPass and UIPass
|
||||
refPass = 'DebugOverlayPass'
|
||||
# The data file for new pass request is in the same folder of the py file
|
||||
newPassRequestFilePath = os.path.join(dir_name, 'LyShinePass.data')
|
||||
newPassRequestData = utils.load_json_file(newPassRequestFilePath)
|
||||
insertIndex = renderPipeline.find_pass(refPass) + 1
|
||||
if insertIndex>-1:
|
||||
renderPipeline.insert_pass_request(insertIndex, newPassRequestData)
|
||||
else:
|
||||
print('Failed to find ', refPass)
|
||||
exit()
|
||||
|
||||
# Update attachment references for the passes following LyShinePass
|
||||
renderPipeline.replace_references_after(newPassName, 'DebugOverlayPass', 'InputOutput', 'LyShinePass', 'ColorInputOutput')
|
||||
|
||||
# Save the updated render pipeline
|
||||
renderPipeline.save()
|
||||
Reference in New Issue
Block a user