Merge branch 'development' into Atom/santorac/RemixableMaterialTypes3

There were lots of material system conflicts that had to be resolved. I expect the build is broken at this commit, and I'll fix it in followup commits.

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
santorac
2022-01-25 14:47:24 -08:00
9789 changed files with 757680 additions and 902265 deletions
@@ -1,149 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
// If true pixels with an alpha value of less than 0.5 are clipped
option bool o_alphaTest;
// If true both the texture color and diffuse color are converted from linear to sRGB color space
option bool o_srgbWrite;
// Indicates how to use the second texture indexed by a vertex (if at all)
option enum class Modulate { None, Alpha, AlphaAndColor } o_modulate;
// Each vertex can select one or two of the 16 textures bound
// We use an array of textures and a bitmask that indicates whether to use clamp
// sampler (bit set) or wrap. The nth bit has the correct sampler value for the nth texture
ShaderResourceGroup InstanceSrg : SRG_PerDraw
{
row_major float4x4 m_worldToProj;
uint m_isClamp;
Texture2D m_texture[16];
Sampler m_wrapSampler
{
MaxAnisotropy = 16;
AddressU = Wrap;
AddressV = Wrap;
AddressW = Wrap;
};
Sampler m_clampSampler
{
MaxAnisotropy = 16;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
};
struct VSInput
{
float2 m_position : POSITION;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
uint2 m_flags : BLENDINDICES;
};
struct VSOutput
{
float4 m_position : SV_Position;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
nointerpolation uint m_texIndex : COLOR1;
nointerpolation uint m_texHasColorChannel : COLOR2;
nointerpolation uint m_texIndex2 : COLOR3;
};
VSOutput MainVS(VSInput IN)
{
float4x4 worldToProj = InstanceSrg::m_worldToProj;
float4 posPS = mul(worldToProj, float4(IN.m_position, 1.0f, 1.0f));
VSOutput OUT;
OUT.m_position = posPS;
OUT.m_color = IN.m_color;
OUT.m_uv = IN.m_uv;
OUT.m_texIndex = IN.m_flags.x & 0x00FF;
OUT.m_texHasColorChannel = ((IN.m_flags.x & 0xFF00) > 0) ? 1 : 0;
OUT.m_texIndex2 = IN.m_flags.y & 0x00FF;
return OUT;
};
struct PSOutput
{
float4 m_color : SV_Target0;
};
float4 SampleTriangleTexture(uint texIndex, float2 uv)
{
if ((InstanceSrg::m_isClamp & (1U << texIndex)) != 0)
{
return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_clampSampler, uv);
}
else
{
return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_wrapSampler, uv);
}
}
PSOutput MainPS(VSOutput IN)
{
PSOutput OUT;
float4 baseTex = SampleTriangleTexture(IN.m_texIndex, IN.m_uv.xy);
float4 inDiffuse = IN.m_color;
// If the texture does not have a color channel then the alpha channel will be in the R channel of the R8 texture
baseTex = (IN.m_texHasColorChannel) ? baseTex : float4(1.0f, 1.0f, 1.0f, baseTex.x);
float4 resColor = baseTex * inDiffuse;
if (o_alphaTest)
{
clip(resColor.w - 0.5);
}
// Should use srgb anytime after tonemapping
if (o_srgbWrite)
{
resColor.xyz = LinearToSRGB(resColor.xyz);
}
// 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)
{
float4 maskTexAlpha = SampleTriangleTexture(IN.m_texIndex2, IN.m_uv.xy);
resColor.w *= maskTexAlpha.w;
if (o_alphaTest)
{
// This is a rare case that would only happen if a gradient mask is used inside the mask primitive for a stencil mask
clip(resColor.w - 0.5);
}
}
else if (o_modulate == Modulate::AlphaAndColor)
{
float4 maskTex = SampleTriangleTexture(IN.m_texIndex2, IN.m_uv.xy);
resColor *= maskTex.w;
if (o_alphaTest)
{
// This is a rare case that would only happen if a gradient mask is used inside the mask primitive for a stencil mask
clip(resColor.w - 0.5);
}
}
OUT.m_color = resColor;
return OUT;
};
@@ -1,39 +0,0 @@
{
"Source" : "LyShineUI",
"DepthStencilState" : {
"Depth" : {
"Enable" : false,
"CompareFunc" : "Always"
}
},
"RasterState" : {
"DepthClipEnable" : false,
"CullMode" : "None"
},
"BlendState" : {
"Enable" : true,
"BlendSource" : "AlphaSource",
"BlendDest" : "AlphaSourceInverse",
"BlendOp" : "Add"
},
"DrawList" : "2dpass",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -1,37 +0,0 @@
{
"Shader" : "LyShineUI.shader",
"Variants" : [
{
"StableId": 1,
"Options": {
"o_alphaTest": "false",
"o_srgbWrite": "true",
"o_modulate": "Modulate::None"
}
},
{
"StableId": 2,
"Options": {
"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"
}
}
]
}
@@ -1,5 +1,5 @@
{
"Source" : "SimpleTextured",
"Source" : "SimpleTextured.azsl",
"DepthStencilState" : {
"Depth" : {
@@ -6,4 +6,8 @@
#
#
set(gem_path ${CMAKE_CURRENT_LIST_DIR})
set(gem_json ${gem_path}/gem.json)
o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path)
add_subdirectory(Code)
@@ -6,7 +6,7 @@
#
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME})
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path})
ly_add_target(
NAME Atom_AtomBridge.Static STATIC
@@ -68,6 +68,14 @@ ly_create_alias(NAME Atom_AtomBridge.Clients NAMESPACE Gem TARGETS Gem::Atom_Ato
ly_create_alias(NAME Atom_AtomBridge.Servers NAMESPACE Gem TARGETS Gem::Atom_AtomBridge)
if(PAL_TRAIT_BUILD_HOST_TOOLS)
set(additional_tool_deps ${pal_dir}/additional_${PAL_PLATFORM_NAME_LOWERCASE}_tool_deps.cmake)
foreach(pal_tools_platform ${LY_PAL_TOOLS_ENABLED})
string(TOLOWER ${pal_tools_platform} pal_tools_platform_lowercase)
ly_get_list_relative_pal_filename(pal_runtime_dependencies_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${pal_tools_platform})
list(APPEND additional_tool_deps ${pal_runtime_dependencies_source_dir}/additional_${pal_tools_platform_lowercase}_tool_deps.cmake)
endforeach()
ly_add_target(
NAME Atom_AtomBridge.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
@@ -79,7 +87,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
PUBLIC
Include
PLATFORM_INCLUDE_FILES
${pal_dir}/additional_${PAL_PLATFORM_NAME_LOWERCASE}_tool_deps.cmake
${additional_tool_deps}
COMPILE_DEFINITIONS
PRIVATE
EDITOR
@@ -67,12 +67,12 @@ namespace AZ
void AtomBridgeSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
provided.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
}
void AtomBridgeSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
incompatible.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
}
void AtomBridgeSystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
@@ -108,7 +108,7 @@ namespace AZ
{
m_dynamicDrawManager.reset();
AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect();
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
RPI::Scene* scene = AZ::RPI::Scene::GetSceneForEntityContextId(m_entityContextId);
// Check if scene is emptry since scene might be released already when running AtomSampleViewer
if (scene)
{
@@ -157,9 +157,9 @@ namespace AZ
void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
AZ_UNUSED(bootstrapScene);
// Make default AtomDebugDisplayViewportInterface
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> mainEntityDebugDisplay = AZStd::make_shared<AtomDebugDisplayViewportInterface>(AzFramework::g_defaultSceneEntityDebugDisplayId);
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> mainEntityDebugDisplay =
AZStd::make_shared<AtomDebugDisplayViewportInterface>(AzFramework::g_defaultSceneEntityDebugDisplayId, bootstrapScene);
m_activeViewportsList[AzFramework::g_defaultSceneEntityDebugDisplayId] = mainEntityDebugDisplay;
}
@@ -256,12 +256,11 @@ namespace AZ::AtomBridge
viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler);
}
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress)
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene)
{
ResetRenderState();
m_viewportId = defaultInstanceAddress;
m_defaultInstance = true;
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
InitInternal(scene, nullptr);
}
@@ -349,14 +348,7 @@ namespace AZ::AtomBridge
void AtomDebugDisplayViewportInterface::SetAlpha(float a)
{
m_rendState.m_color.SetA(a);
if (a < 1.0f)
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
}
else
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent;
}
m_rendState.m_opacityType = a < 1.0f ? AZ::RPI::AuxGeomDraw::OpacityType::Translucent : AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
}
void AtomDebugDisplayViewportInterface::DrawQuad(
@@ -800,7 +792,8 @@ namespace AZ::AtomBridge
const float startAngle = DegToRad(startAngleDegrees);
const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle;
SingleColorDynamicSizeLineHelper lines(1+static_cast<int>(sweepAngleDegrees/angularStepDegrees));
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
float aspectRadius = radius / GetAspectRatio();
AZ::Vector3 radiusV3 = AZ::Vector3(aspectRadius, radius, radius);
AZ::Vector3 pos = AZ::Vector3(center.GetX(), center.GetY(), z);
CreateAxisAlignedArc(
lines,
@@ -1016,6 +1009,55 @@ namespace AZ::AtomBridge
}
}
void AtomDebugDisplayViewportInterface::DrawWireCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height)
{
if (m_auxGeomPtr)
{
const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement();
const AZ::Vector3 worldCenter = ToWorldSpacePosition(center);
const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis);
m_auxGeomPtr->DrawCylinderNoEnds(
worldCenter,
worldAxis,
scale * radius,
scale * height,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Line,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawSolidCylinderNoEnds(
const AZ::Vector3& center,
const AZ::Vector3& axis,
float radius,
float height,
bool drawShaded)
{
if (m_auxGeomPtr)
{
const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement();
const AZ::Vector3 worldCenter = ToWorldSpacePosition(center);
const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis);
m_auxGeomPtr->DrawCylinderNoEnds(
worldCenter,
worldAxis,
scale * radius,
scale * height,
m_rendState.m_color,
drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawWireCapsule(
const AZ::Vector3& center,
const AZ::Vector3& axis,
@@ -1025,83 +1067,24 @@ namespace AZ::AtomBridge
if (m_auxGeomPtr && radius > FLT_EPSILON && axis.GetLengthSq() > FLT_EPSILON)
{
AZ::Vector3 axisNormalized = axis.GetNormalizedEstimate();
SingleColorStaticSizeLineHelper<(16+1) * 5> lines; // 360/22.5 = 16, 5 possible calls to CreateArbitraryAxisArc
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
float stepAngle = DegToRad(22.5f);
float Deg0 = DegToRad(0.0f);
const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement();
const AZ::Vector3 worldCenter = ToWorldSpacePosition(center);
const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis);
// Draw cylinder part (or just a circle around the middle)
// Draw cylinder part (if cylinder height is too small, ignore cylinder and just draw both hemispheres)
if (heightStraightSection > FLT_EPSILON)
{
DrawWireCylinder(center, axis, radius, heightStraightSection);
}
else
{
float Deg360 = DegToRad(360.0f);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg0,
Deg360,
center,
radiusV3,
axisNormalized
);
DrawWireCylinderNoEnds(worldCenter, worldAxis, scale * radius, scale * heightStraightSection);
}
float Deg90 = DegToRad(90.0f);
float Deg180 = DegToRad(180.0f);
AZ::Vector3 ortho1Normalized, ortho2Normalized;
CalcBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized);
AZ::Vector3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f;
AZ::Vector3 topCenter = center + centerToTopCircleCenter;
AZ::Vector3 bottomCenter = center - centerToTopCircleCenter;
// Draw top cap as two criss-crossing 180deg arcs
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg90,
Deg90 + Deg180,
topCenter,
radiusV3,
ortho1Normalized
);
// Top hemisphere
DrawWireHemisphere(center + centerToTopCircleCenter, worldAxis, scale * radius);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg180,
Deg180 + Deg180,
topCenter,
radiusV3,
ortho2Normalized
);
// Draw bottom cap
CreateArbitraryAxisArc(
lines,
stepAngle,
-Deg90,
-Deg90 + Deg180,
bottomCenter,
radiusV3,
ortho1Normalized
);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg0,
Deg0 + Deg180,
bottomCenter,
radiusV3,
ortho2Normalized
);
lines.Draw(m_auxGeomPtr, m_rendState);
// Bottom hemisphere
DrawWireHemisphere(center - centerToTopCircleCenter, -worldAxis, scale * radius);
}
}
@@ -1148,6 +1131,25 @@ namespace AZ::AtomBridge
}
}
void AtomDebugDisplayViewportInterface::DrawWireHemisphere(const AZ::Vector3& pos, const AZ::Vector3& axis, float radius)
{
if (m_auxGeomPtr)
{
const float scale = GetCurrentTransform().RetrieveScale().GetMaxElement();
m_auxGeomPtr->DrawHemisphere(
ToWorldSpacePosition(pos),
axis,
scale * radius,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Line,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius)
{
if (m_auxGeomPtr)
@@ -1353,8 +1355,9 @@ namespace AZ::AtomBridge
// if 2d draw need to project pos to screen first
AzFramework::TextDrawParameters params;
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
params.m_position = AZ::Vector3(x, y, 1.0f);
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
params.m_color = m_rendState.m_color;
params.m_scale = AZ::Vector2(size);
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment
@@ -124,7 +124,7 @@ namespace AZ::AtomBridge
AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler);
explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr);
explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress);
explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene);
~AtomDebugDisplayViewportInterface();
void ResetRenderState();
@@ -168,9 +168,12 @@ namespace AZ::AtomBridge
void DrawSolidCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded) override;
void DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) override;
void DrawSolidCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded) override;
void DrawWireCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) override;
void DrawSolidCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded) override;
void DrawWireCapsule(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float heightStraightSection) override;
void DrawWireSphere(const AZ::Vector3& pos, float radius) override;
void DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius) override;
void DrawWireHemisphere(const AZ::Vector3& pos, const AZ::Vector3& axis, float radius) override;
void DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override;
void DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) override;
void DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override;
@@ -109,12 +109,12 @@ namespace AZ
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0x66d04369));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0x66d04369));
}
static void Reflect(AZ::ReflectContext* context);
@@ -8,7 +8,6 @@
#include "FlyCameraInputComponent.h"
#include <ISystem.h>
#include <ITimer.h>
#include <IConsole.h>
#include <AzCore/Component/Component.h>
+4 -1
View File
@@ -2,14 +2,17 @@
"gem_name": "Atom_AtomBridge",
"display_name": "Atom Bridge",
"license": "Apache-2.0 Or MIT",
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Atom Bridge",
"canonical_tags": [
"Gem"
],
"user_tags": [],
"requirements": "",
"documentation_url": "",
"dependencies": [
"Atom_RPI",
"Atom_Bootstrap",
@@ -0,0 +1,13 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{400C0F36-1069-5F0E-8E55-87123BA075CD}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shaders/simpletextured.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</Class>
</ObjectStream>
@@ -6,4 +6,8 @@
#
#
set(gem_path ${CMAKE_CURRENT_LIST_DIR})
set(gem_json ${gem_path}/gem.json)
o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path)
add_subdirectory(Code)
@@ -6,7 +6,7 @@
#
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path})
ly_add_target(
NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
@@ -133,18 +133,6 @@ namespace AZ
typedef std::vector<FontEffect> FontEffects;
typedef FontEffects::iterator FontEffectsIterator;
struct FontPipelineStateMapKey
{
AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline)
AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default
bool operator<(const FontPipelineStateMapKey& other) const
{
return m_sceneId < other.m_sceneId
|| (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag);
}
};
struct FontShaderData
{
AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture";
@@ -46,7 +46,7 @@ static void DumfontTexture(IConsoleCmdArgs* cmdArgs)
if (fontName && *fontName && *fontName != '0')
{
AZStd::string fontFilePath("@devroot@/");
AZStd::string fontFilePath("@engroot@/");
fontFilePath += fontName;
fontFilePath += ".bmp";
@@ -561,12 +561,10 @@ uint32_t AZ::FFont::GetNumQuadsForText(const char* str, const bool asciiMultiLin
++numQuads;
}
uint32_t nextCh = 0;
const wchar_t* pChar = strW.c_str();
while (uint32_t ch = *pChar)
{
++pChar;
nextCh = *pChar;
switch (ch)
{
@@ -1726,15 +1724,13 @@ void AZ::FFont::DrawScreenAlignedText3d(
{
return;
}
AZ::Vector3 positionNDC = AzFramework::WorldToScreenNdc(
params.m_position,
currentView->GetWorldToViewMatrix(),
currentView->GetViewToClipMatrix()
);
// Text behind the camera shouldn't get rendered. WorldToScreenNDC returns values in the range 0 - 1, so Z < 0.5 is behind the screen
const AZ::Vector3 positionNdc = AzFramework::WorldToScreenNdc(
params.m_position, currentView->GetWorldToViewMatrixAsMatrix3x4(), currentView->GetViewToClipMatrix());
// Text behind the camera shouldn't get rendered. WorldToScreenNdc returns values in the range 0 - 1, so Z < 0.5 is behind the screen
// and >= 0.5 is in front of the screen.
if (positionNDC.GetZ() < 0.5f)
if (positionNdc.GetZ() < 0.5f)
{
return;
}
@@ -1744,9 +1740,9 @@ void AZ::FFont::DrawScreenAlignedText3d(
DrawStringUInternal(
*internalParams.m_viewport,
internalParams.m_viewportContext,
positionNDC.GetX() * internalParams.m_viewport->GetWidth(),
(1.0f - positionNDC.GetY()) * internalParams.m_viewport->GetHeight(),
positionNDC.GetZ(), // Z
positionNdc.GetX() * internalParams.m_viewport->GetWidth(),
(1.0f - positionNdc.GetY()) * internalParams.m_viewport->GetHeight(),
positionNdc.GetZ(), // Z
text.data(),
params.m_multiline,
internalParams.m_ctx
+4 -1
View File
@@ -2,14 +2,17 @@
"gem_name": "AtomFont",
"display_name": "Atom Font",
"license": "Apache-2.0 Or MIT",
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Font Rendering for Atom",
"canonical_tags": [
"Gem"
],
"user_tags": [],
"requirements": "",
"documentation_url": "",
"dependencies": [
"Atom_RHI",
"Atom_RPI",
@@ -84,14 +84,6 @@ namespace AtomImGuiTools
{
m_imguiGpuProfiler.Draw(m_showGpuProfiler, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
}
if (m_showCpuProfiler)
{
const AZ::RHI::CpuTimingStatistics* stats = AZ::RHI::RHISystemInterface::Get()->GetCpuTimingStatistics();
if (stats)
{
m_imguiCpuProfiler.Draw(m_showCpuProfiler, *stats);
}
}
if (m_showTransientAttachmentProfiler)
{
auto* transientStats = AZ::RHI::RHISystemInterface::Get()->GetTransientAttachmentStatistics();
@@ -112,12 +104,6 @@ namespace AtomImGuiTools
{
ImGui::MenuItem("Pass Viewer", "", &m_showPassTree);
ImGui::MenuItem("Gpu Profiler", "", &m_showGpuProfiler);
if (ImGui::MenuItem("Cpu Profiler", "", &m_showCpuProfiler))
{
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
AZ::RHI::FrameSchedulerStatisticsFlags::GatherCpuTimingStatistics, m_showCpuProfiler);
AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(m_showCpuProfiler);
}
if (ImGui::MenuItem("Transient Attachment Profiler", "", &m_showTransientAttachmentProfiler))
{
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
@@ -15,7 +15,6 @@
#if defined(IMGUI_ENABLED)
#include <ImGuiBus.h>
#include <imgui/imgui.h>
#include <Atom/Utils/ImGuiCpuProfiler.h>
#include <Atom/Utils/ImGuiGpuProfiler.h>
#include <Atom/Utils/ImGuiPassTree.h>
#include <Atom/Utils/ImGuiShaderMetrics.h>
@@ -63,9 +62,6 @@ namespace AtomImGuiTools
AZ::Render::ImGuiGpuProfiler m_imguiGpuProfiler;
bool m_showGpuProfiler = false;
AZ::Render::ImGuiCpuProfiler m_imguiCpuProfiler;
bool m_showCpuProfiler = false;
AZ::Render::ImGuiTransientAttachmentProfiler m_imguiTransientAttachmentProfiler;
bool m_showTransientAttachmentProfiler = false;
@@ -2,9 +2,11 @@
"gem_name": "AtomImGuiTools",
"display_name": "Atom ImGui",
"license": "Apache-2.0 Or MIT",
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Tool",
"summary": "",
"summary": "ImGui tools for Atom",
"canonical_tags": [
"Gem"
],
@@ -13,6 +15,7 @@
"Rendering"
],
"requirements": "",
"documentation_url": "",
"dependencies": [
"ImguiAtom",
"Atom"
@@ -1,5 +1,5 @@
{
"Source" : "TexturedIcon",
"Source" : "TexturedIcon.azsl",
"DepthStencilState" : {
"Depth" : {
@@ -0,0 +1,13 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{7B093FA3-A834-5061-9ADD-C6DCA97A4B60}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shaders/texturedicon.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</Class>
</ObjectStream>
@@ -8,6 +8,7 @@
#include "AtomViewportDisplayIconsSystemComponent.h"
#include <AzCore/Math/VectorConversions.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
@@ -73,7 +74,7 @@ namespace AZ::Render
void AtomViewportDisplayIconsSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
required.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
required.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
}
void AtomViewportDisplayIconsSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -117,8 +118,7 @@ namespace AZ::Render
return;
}
auto perViewportDynamicDrawInterface =
AtomBridge::PerViewportDynamicDraw::Get();
auto perViewportDynamicDrawInterface = AtomBridge::PerViewportDynamicDraw::Get();
if (!perViewportDynamicDrawInterface)
{
return;
@@ -131,7 +131,7 @@ namespace AZ::Render
return;
}
// Find our icon, falling back on a grey placeholder if its image is unavailable
// Find our icon, falling back on a gray placeholder if its image is unavailable
AZ::Data::Instance<AZ::RPI::Image> image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Grey);
if (auto iconIt = m_iconData.find(drawParameters.m_icon); iconIt != m_iconData.end())
{
@@ -172,13 +172,16 @@ namespace AZ::Render
}
else if (drawParameters.m_positionSpace == CoordinateSpace::WorldSpace)
{
// Calculate the ndc point (0.0-1.0 range) including depth
const AZ::Vector3 ndcPoint = AzFramework::WorldToScreenNdc(
drawParameters.m_position, viewportContext->GetCameraViewMatrixAsMatrix3x4(),
viewportContext->GetCameraProjectionMatrix());
// Calculate our screen space position using the viewport size
// We want this instead of RenderViewportWidget::WorldToScreen which works in QWidget virtual coordinate space
AzFramework::ScreenPoint position = AzFramework::WorldToScreen(
drawParameters.m_position, viewportContext->GetCameraViewMatrix(), viewportContext->GetCameraProjectionMatrix(),
viewportSize);
screenPosition.SetX(aznumeric_cast<float>(position.m_x));
screenPosition.SetY(aznumeric_cast<float>(position.m_y));
const AzFramework::ScreenPoint screenPoint = AzFramework::ScreenPointFromNdc(AZ::Vector3ToVector2(ndcPoint), viewportSize);
screenPosition = AzFramework::Vector3FromScreenPoint(screenPoint, ndcPoint.GetZ());
}
struct Vertex
@@ -210,7 +213,12 @@ namespace AZ::Render
createVertex(-0.5f, 0.5f, 0.f, 1.f)
};
AZStd::array<Indice, 6> indices = {0, 1, 2, 0, 2, 3};
dynamicDraw->DrawIndexed(&vertices, static_cast<uint32_t>(vertices.size()), &indices, static_cast<uint32_t>(indices.size()), RHI::IndexFormat::Uint16, drawSrg);
dynamicDraw->SetSortKey(
aznumeric_cast<int64_t>(screenPosition.GetZ() * aznumeric_cast<float>(AZStd::numeric_limits<int64_t>::max())));
dynamicDraw->DrawIndexed(
&vertices, static_cast<uint32_t>(vertices.size()), &indices, static_cast<uint32_t>(indices.size()), RHI::IndexFormat::Uint16,
drawSrg);
}
QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& path) const
@@ -354,7 +362,7 @@ namespace AZ::Render
{
// Once the shader is loaded, register it with the dynamic draw context
Data::Asset<RPI::ShaderAsset> shaderAsset = asset;
AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(m_drawContextName, [shaderAsset](RPI::Ptr<RPI::DynamicDrawContext> drawContext)
AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(m_drawContextName, [shaderAsset](RPI::Ptr<RPI::DynamicDrawContext> dynamicDraw)
{
AZ_Assert(shaderAsset->IsReady(), "Attempting to register the AtomViewportDisplayIconsSystemComponent"
" dynamic draw context before the shader asset is loaded. The shader should be loaded first"
@@ -362,12 +370,11 @@ namespace AZ::Render
" will be executed during scene processing and there may be multiple scenes executing in parallel.");
Data::Instance<RPI::Shader> shader = RPI::Shader::FindOrCreate(shaderAsset);
drawContext->InitShader(shader);
drawContext->InitVertexFormat(
{ {"POSITION", RHI::Format::R32G32B32_FLOAT},
{"COLOR", RHI::Format::R8G8B8A8_UNORM},
{"TEXCOORD", RHI::Format::R32G32_FLOAT} });
drawContext->EndInit();
dynamicDraw->InitShader(shader);
dynamicDraw->InitVertexFormat({ { "POSITION", RHI::Format::R32G32B32_FLOAT },
{ "COLOR", RHI::Format::R8G8B8A8_UNORM },
{ "TEXCOORD", RHI::Format::R32G32_FLOAT } });
dynamicDraw->EndInit();
});
m_drawContextRegistered = true;
@@ -2,14 +2,17 @@
"gem_name": "AtomViewportDisplayIcons",
"display_name": "Atom Viewport Display Icons",
"license": "Apache-2.0 Or MIT",
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Viewport display icons for Atom",
"canonical_tags": [
"Gem"
],
"user_tags": [],
"requirements": "",
"documentation_url": "",
"dependencies": [
"Atom_RHI",
"Atom_RPI",
@@ -130,7 +130,8 @@ namespace AZ::Render
}
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene())
if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene() ||
!AZ::Interface<AzFramework::FontQueryInterface>::Get())
{
return;
}
@@ -183,15 +184,6 @@ namespace AZ::Render
DrawFramerate();
}
void AtomViewportDisplayInfoSystemComponent::OnFrameEnd()
{
auto currentTime = AZStd::chrono::system_clock::now();
if (!m_fpsHistory.empty())
{
m_fpsHistory.back().m_endFrameTime = currentTime;
}
}
AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const
{
return aznumeric_cast<AtomBridge::ViewportInfoDisplayState>(r_displayInfo.operator int());
@@ -257,11 +249,11 @@ namespace AZ::Render
void AtomViewportDisplayInfoSystemComponent::UpdateFramerate()
{
auto currentTime = AZStd::chrono::system_clock::now();
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front().m_beginFrameTime) > m_fpsInterval)
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front()) > m_fpsInterval)
{
m_fpsHistory.pop_front();
}
m_fpsHistory.push_back(FrameTimingInfo(currentTime));
m_fpsHistory.push_back(currentTime);
}
void AtomViewportDisplayInfoSystemComponent::DrawFramerate()
@@ -270,42 +262,42 @@ namespace AZ::Render
double minFPS = DBL_MAX;
double maxFPS = 0;
AZStd::chrono::duration<double> deltaTime;
AZStd::chrono::milliseconds totalFrameMS(0);
for (const auto& time : m_fpsHistory)
{
if (lastTime.has_value())
{
deltaTime = time.m_beginFrameTime - lastTime.value();
deltaTime = time - lastTime.value();
double fps = AZStd::chrono::seconds(1) / deltaTime;
minFPS = AZStd::min(minFPS, fps);
maxFPS = AZStd::max(maxFPS, fps);
}
lastTime = time.m_beginFrameTime;
if (time.m_endFrameTime.has_value())
{
totalFrameMS += time.m_endFrameTime.value() - time.m_beginFrameTime;
}
lastTime = time;
}
double averageFPS = 0;
double averageFrameMs = 0;
if (m_fpsHistory.size() > 1)
{
deltaTime = m_fpsHistory.back().m_beginFrameTime - m_fpsHistory.front().m_beginFrameTime;
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size() - 1) / deltaTime;
averageFrameMs = aznumeric_cast<double>(totalFrameMS.count()) / (m_fpsHistory.size() - 1);
deltaTime = m_fpsHistory.back() - m_fpsHistory.front();
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size()) / deltaTime;
averageFrameMs = 1000.0f/averageFPS;
}
const double frameIntervalSeconds = m_fpsInterval.count();
auto ClampedFloatDisplay = [](double value, const char* format) -> AZStd::string
{
constexpr float upperLimit = 10000.0f;
return value > upperLimit ? "inf" : AZStd::string::format(format, value);
};
DrawLine(
AZStd::string::format(
"FPS %.1f [%.0f..%.0f], %.1fms/frame, avg over %.1fs",
averageFPS,
minFPS == DBL_MAX ? 0.0 : minFPS,
maxFPS,
averageFrameMs,
"FPS %s [%s..%s], %sms/frame, avg over %.1fs",
ClampedFloatDisplay(averageFPS, "%.1f").c_str(),
ClampedFloatDisplay(minFPS, "%.0f").c_str(),
ClampedFloatDisplay(maxFPS, "%.0f").c_str(),
ClampedFloatDisplay(averageFrameMs, "%.1f").c_str(),
frameIntervalSeconds),
AZ::Colors::Yellow);
}
@@ -45,7 +45,6 @@ namespace AZ
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
void OnRenderTick() override;
void OnFrameEnd() override;
// AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides...
AtomBridge::ViewportInfoDisplayState GetDisplayState() const override;
@@ -62,8 +61,6 @@ namespace AZ
void DrawPassInfo();
void DrawFramerate();
void UpdateScene(AZ::RPI::ScenePtr scene);
static constexpr float BaseFontSize = 0.7f;
AZStd::string m_rendererDescription;
@@ -71,17 +68,7 @@ namespace AZ
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;
float m_lineSpacing;
AZStd::chrono::duration<double> m_fpsInterval = AZStd::chrono::seconds(1);
struct FrameTimingInfo
{
AZStd::chrono::system_clock::time_point m_beginFrameTime;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_endFrameTime;
explicit FrameTimingInfo(AZStd::chrono::system_clock::time_point beginFrameTime)
: m_beginFrameTime(beginFrameTime)
{
}
};
AZStd::deque<FrameTimingInfo> m_fpsHistory;
AZStd::deque<AZStd::chrono::system_clock::time_point> m_fpsHistory;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_lastMemoryUpdate;
bool m_updateRootPassQuery = true;
};
@@ -2,14 +2,17 @@
"gem_name": "AtomViewportDisplayInfo",
"display_name": "Atom Viewport Display Info",
"license": "Apache-2.0 Or MIT",
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
"origin": "Open 3D Engine - o3de.org",
"origin_url": "https://github.com/o3de/o3de",
"type": "Code",
"summary": "",
"summary": "Viewport Display Information for Atom",
"canonical_tags": [
"Gem"
],
"user_tags": [],
"requirements": "",
"documentation_url": "",
"dependencies": [
"Atom_RHI",
"Atom_RPI"
-9
View File
@@ -6,13 +6,4 @@
#
#
add_subdirectory(CommonFeatures)
add_subdirectory(ImguiAtom)
add_subdirectory(AtomImGuiTools)
add_subdirectory(EMotionFXAtom)
add_subdirectory(AtomFont)
add_subdirectory(TechnicalArt)
add_subdirectory(AtomBridge)
add_subdirectory(AtomViewportDisplayInfo)
add_subdirectory(AtomViewportDisplayIcons)
@@ -836,7 +836,7 @@
</Class>
<Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
<Class name="AZ::Render::MeshComponentConfig" field="Configuration" version="1" type="{63737345-51B1-472B-9355-98F99993909B}">
<Class name="Asset" field="ModelAsset" value="id={935F694A-8639-515B-8133-81CDC7948E5B}:1087c6db,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/groudplane/groundplane_521x521m.azmodel},loadBehavior=1" version="2" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
<Class name="Asset" field="ModelAsset" value="id={0CD745C0-6AA8-569A-A68A-73A3270986C4}:10904372,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/groudplane/groundplane_512x512m.azmodel},loadBehavior=1" version="2" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
<Class name="AZ::s64" field="SortKey" value="0" type="{70D8A282-A1EA-462D-9D04-51EDE81FAC2F}"/>
<Class name="unsigned char" field="LodOverride" value="255" type="{72B9409A-7D1A-4831-9CFE-FCB3FADD3426}"/>
<Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d72cec207a7677ba027eac72f41285907237e04a45ebacf64341de86fc6f022d
size 159115308
@@ -1,39 +1,33 @@
{
"description": "",
"materialType": "Materials/Types/StandardPBR.materialtype",
"parentMaterial": "Materials/Presets/PBR/metal_brass.material",
"propertyLayoutVersion": 3,
"materialType": "Materials/Types/StandardPBR.materialtype",
"materialTypeVersion": 4,
"properties": {
"occlusion": {
"diffuseTextureMap": "Objects/Lucy/Lucy_ao.tif",
"diffuseTextureMapUv": "Unwrapped"
},
"baseColor": {
"color": [
0.6745098233222961,
0.48627451062202456,
0.19607843458652497,
1.0
],
"factor": 1.0,
"textureBlendMode": "Lerp",
"textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png",
"textureMap": "Hermanubis_bronze_BaseColor.png",
"textureMapUv": "Unwrapped"
},
"general": {
"applySpecularAA": true
},
"metallic": {
"textureMap": "Objects/Lucy/Lucy_bronze_Metallic.png",
"textureMap": "Hermanubis_bronze_Metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_Normal.png",
"textureMap": "Hermanubis_Normal.png",
"textureMapUv": "Unwrapped"
},
"occlusion": {
"diffuseTextureMap": "Hermanubis_ao.tif",
"diffuseTextureMapUv": "Unwrapped"
},
"roughness": {
"textureMap": "Objects/Lucy/Lucy_bronze_Roughness.png",
"textureMap": "Hermanubis_bronze_Roughness.png",
"textureMapUv": "Unwrapped",
"upperBound": 0.6767677068710327
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4c9d1030b9467b58d640fbedf1bc58ab9a5f7d68811b2452dd8d60114287b731
size 12410812
@@ -1,13 +1,9 @@
{
"description": "",
"materialType": "Materials/Types/StandardPBR.materialtype",
"parentMaterial": "Materials/Presets/PBR/metal_brass.material",
"propertyLayoutVersion": 3,
"materialType": "Materials/Types/StandardPBR.materialtype",
"materialTypeVersion": 4,
"properties": {
"occlusion": {
"diffuseTextureMap": "Objects/Lucy/Lucy_ao.tif",
"diffuseTextureMapUv": "Unwrapped"
},
"baseColor": {
"color": [
1.0,
@@ -17,7 +13,7 @@
],
"factor": 1.0,
"textureBlendMode": "Lerp",
"textureMap": "Objects/Lucy/Lucy_Stone_BaseColor.png",
"textureMap": "Hermanubis_Stone_BaseColor.png",
"textureMapUv": "Unwrapped"
},
"clearCoat": {
@@ -39,13 +35,17 @@
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_Normal.png",
"textureMap": "Hermanubis_Normal.png",
"textureMapUv": "Unwrapped"
},
"occlusion": {
"diffuseTextureMap": "Hermanubis_ao.tif",
"diffuseTextureMapUv": "Unwrapped"
},
"roughness": {
"factor": 1.0,
"lowerBound": 0.15000000596046449,
"textureMap": "Objects/Lucy/Lucy_bronze_Roughness.png",
"lowerBound": 0.15000000596046448,
"textureMap": "Hermanubis_bronze_Roughness.png",
"textureMapUv": "Unwrapped",
"upperBound": 0.7300000190734863
}
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:00e19e317613be5420fd78bac1159e66d1c4deeb1f32cd4fc8c20b1ea3a5ead1
size 153114272
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6a4a65d139a6088dd4ac34f3ba3f6a7a98b8fe9545150ee7d9879fbc2a55d8d4
size 9022128
@@ -0,0 +1,45 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{4F3761EF-E279-5FDD-98C3-EF90F924FBAC}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="lightingpresets/thumbnail.lightingpreset.azasset" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="284780167" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="models/sphere.azmodel" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{CF91AE08-8FD5-538B-A5F2-427DFA9D5E1C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="materials/basic_grey.azmaterial" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{DCE9A5B2-1907-5A0D-8A96-5ABF608D103B}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/mainpipeline.pass" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{6B01EDAB-1951-5588-AB7B-DF2F703950D4}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="passes/smaaconfiguration.azasset" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</Class>
</ObjectStream>
@@ -6,4 +6,8 @@
#
#
set(gem_path ${CMAKE_CURRENT_LIST_DIR})
set(gem_json ${gem_path}/gem.json)
o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path)
add_subdirectory(Code)
@@ -6,8 +6,8 @@
#
#
ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common)
o3de_pal_dir(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path})
set(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Public HEADERONLY
@@ -77,8 +77,7 @@ ly_create_alias(NAME AtomLyIntegration_CommonFeatures.Servers NAMESPACE Gem
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE
NAME AtomLyIntegration_CommonFeatures.Editor.Static STATIC
NAMESPACE Gem
AUTOUIC
AUTOMOC
@@ -86,6 +85,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
FILES_CMAKE
atomlyintegration_commonfeatures_editor_files.cmake
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
@@ -96,7 +97,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
PRIVATE
ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
BUILD_DEPENDENCIES
PRIVATE
PUBLIC
Gem::AtomLyIntegration_CommonFeatures.Static
Gem::Atom_RPI.Edit
Gem::AtomToolsFramework.Static
@@ -106,9 +107,28 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
Legacy::Editor.Headers
Legacy::EditorCommon
Legacy::CryCommon
)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
BUILD_DEPENDENCIES
PRIVATE
Gem::AtomLyIntegration_CommonFeatures.Editor.Static
RUNTIME_DEPENDENCIES
Gem::Atom_RPI.Editor
Gem::Atom_Feature_Common.Editor
Gem::AtomToolsFramework.Editor
Legacy::EditorCommon
)
@@ -125,6 +145,33 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::AtomLyIntegration_CommonFeatures.Editor
Gem::GradientSignal.Tools
)
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_editor_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
AZ::AzTestShared
AZ::AzToolsFramework
AZ::AzToolsFrameworkTestCommon
Gem::AtomLyIntegration_CommonFeatures.Static
Gem::AtomLyIntegration_CommonFeatures.Editor.Static
)
ly_add_googletest(
NAME Gem::AtomLyIntegration_CommonFeatures.Editor.Tests
)
endif()
endif()
# AtomLyIntegration_CommonFeatures gem targets are required as part of the Editor and AssetProcessor
@@ -120,13 +120,6 @@ namespace AZ
//! Sets the filter method of shadows.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Gets the width of softening boundary between shadowed area and lit area in degrees.
virtual float GetSofteningBoundaryWidthAngle() const = 0;
//! Sets the width of softening boundary between shadowed area and lit area in degrees.
//! 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0;
//! Gets the sample count for filtering of the shadow boundary.
virtual uint32_t GetFilteringSampleCount() const = 0;
@@ -139,6 +132,13 @@ namespace AZ
//! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow.
virtual void SetEsmExponent(float exponent) = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @return Returns the amount of bias to apply.
virtual float GetNormalShadowBias() const = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
};
//! The EBus for requests to for setting and getting light component properties.
@@ -57,9 +57,9 @@ namespace AZ
// Shadows (only used for supported shapes)
bool m_enableShadow = false;
float m_bias = 0.1f;
float m_normalShadowBias = 0.0f;
ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
float m_boundaryWidthInDegrees = 0.25f;
uint16_t m_filteringSampleCount = 12;
float m_esmExponent = 87.0f;
@@ -153,15 +153,6 @@ namespace AZ
//! @param method filter method.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! This gets the width of boundary between shadowed area and lit area.
//! @return Boundary width. The shadow is gradually changed the degree of shadowed.
virtual float GetSofteningBoundaryWidth() const = 0;
//! This specifies the width of boundary between shadowed area and lit area.
//! @param width Boundary width. The shadow is gradually changed the degree of shadowed.
//! If width == 0, softening edge is disabled. Units are in meters.
virtual void SetSofteningBoundaryWidth(float width) = 0;
//! This gets the sample count for filtering of the shadow boundary.
//! @return Sample Count for filtering (up to 64)
virtual uint32_t GetFilteringSampleCount() const = 0;
@@ -177,6 +168,30 @@ namespace AZ
//! Sets whether the directional shadowmap should use receiver plane bias.
//! @param enable flag specifying whether to enable the receiver plane bias feature
virtual void SetShadowReceiverPlaneBiasEnabled(bool enable) = 0;
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
//! @return Returns the amount of bias to apply.
virtual float GetShadowBias() const = 0;
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
//! @param Sets the amount of bias to apply.
virtual void SetShadowBias(float bias) = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @return Returns the amount of bias to apply.
virtual float GetNormalShadowBias() const = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
//! Gets whether the directional shadow map has cascade blending enabled.
//! This smooths out the border between cascades at the cost of some performance in the blend area.
virtual bool GetCascadeBlendingEnabled() const = 0;
//! Sets whether the directional shadow map has cascade blending enabled.
//! @param enable flag specifying whether to enable cascade blending.
virtual void SetCascadeBlendingEnabled(bool enable) = 0;
};
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
@@ -101,9 +101,8 @@ namespace AZ
//! Method of shadow's filtering.
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
//! Width of the boundary between shadowed area and lit one.
//! If this is 0, edge softening is disabled. Units are in meters.
float m_boundaryWidth = 0.03f; // 3cm
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
float m_normalShadowBias = 0.0f;
//! Sample Count for filtering (from 4 to 64)
//! It is used only when the pixel is predicted as on the boundary.
@@ -113,6 +112,12 @@ namespace AZ
//! This uses partial derivatives to reduce shadow acne when using large pcf kernels.
bool m_receiverPlaneBiasEnabled = true;
//! Reduces shadow acne by applying a small amount of offset along shadow-space z.
float m_shadowBias = 0.0f;
// If true, sample between two adjacent shadow map cascades in a small boundary area to smooth out the transition.
bool m_cascadeBlendingEnabled = false;
bool IsSplitManual() const;
bool IsSplitAutomatic() const;
bool IsCascadeCorrectionDisabled() const;
@@ -0,0 +1,34 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/Feature/Material/MaterialAssignmentId.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
class QPixmap;
namespace AZ
{
namespace Render
{
//! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like
//! being informed that material preview images are available
class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Notify that a material preview image is ready
virtual void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0;
};
using EditorMaterialSystemComponentNotificationBus = AZ::EBus<EditorMaterialSystemComponentNotifications>;
} // namespace Render
} // namespace AZ
@@ -5,20 +5,22 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/Feature/Material/MaterialAssignmentId.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
#include <QPixmap>
namespace AZ
{
namespace Render
{
//! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor
class EditorMaterialSystemComponentRequests
: public AZ::EBusTraits
//! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing
//! different operations like opening the material editor, the material instance inspector, and managing material preview images
class EditorMaterialSystemComponentRequests : public AZ::EBusTraits
{
public:
// Only a single handler is allowed
@@ -31,6 +33,14 @@ namespace AZ
//! Open material instance editor
virtual void OpenMaterialInspector(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
//! Generate a material preview image
virtual void RenderMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
//! Get recently rendered material preview image
virtual QPixmap GetRenderedMaterialPreview(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0;
};
using EditorMaterialSystemComponentRequestBus = AZ::EBus<EditorMaterialSystemComponentRequests>;
} // namespace Render
@@ -43,6 +43,9 @@ namespace AZ
virtual void ClearInvalidMaterialOverrides() = 0;
//! Repair materials that reference missing assets by assigning the default asset
virtual void RepairInvalidMaterialOverrides() = 0;
//! Repair material property overrides that reference missing properties by auto-renaming them where possible
//! @return the number of properties that were updated
virtual uint32_t ApplyAutomaticPropertyUpdates() = 0;
//! Set default material override
virtual void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) = 0;
//! Get default material override
@@ -57,52 +60,8 @@ namespace AZ
virtual void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) = 0;
//! Set a material property override value wrapped by an AZStd::any
virtual void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) = 0;
//! Set a material property override value to a bool
virtual void SetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value) = 0;
//! Set a material property override value to a integer
virtual void SetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value) = 0;
//! Set a material property override value to a unsigned integer
virtual void SetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value) = 0;
//! Set a material property override value to a float
virtual void SetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value) = 0;
//! Set a material property override value to a Vector2
virtual void SetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value) = 0;
//! Set a material property override value to a Vector3
virtual void SetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value) = 0;
//! Set a material property override value to a Vector4
virtual void SetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value) = 0;
//! Set a material property override value to a color
virtual void SetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value) = 0;
//! Set a material property override value to an image asset
virtual void SetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Asset<AZ::RPI::ImageAsset>& value) = 0;
//! Set a material property override value to an image instance
virtual void SetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Instance<AZ::RPI::Image>& value) = 0;
//! Set a material property override value to a string
virtual void SetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value) = 0;
//! Get a material property override value wrapped by an AZStd::any
virtual AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a bool
virtual bool GetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as an integer
virtual int32_t GetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as an unsigned integer
virtual uint32_t GetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a float
virtual float GetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a Vector2
virtual AZ::Vector2 GetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a Vector3
virtual AZ::Vector3 GetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a Vector4
virtual AZ::Vector4 GetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a Color
virtual AZ::Color GetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as an image asset
virtual AZ::Data::Asset<AZ::RPI::ImageAsset> GetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as an image instance
virtual AZ::Data::Instance<AZ::RPI::Image> GetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Get a material property override value as a string
virtual AZStd::string GetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const = 0;
//! Clear property override for a specific material assignment
virtual void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) = 0;
//! Clear property overrides for a specific material assignment
@@ -119,6 +78,21 @@ namespace AZ
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) = 0;
//! Get Model UV overrides for a specific material assignment
virtual AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const = 0;
//! Set material property override value with a specific type
template<typename T>
void SetPropertyOverrideT(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const T& value)
{
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
}
//! Get material property override value with a specific type
template<typename T>
T GetPropertyOverrideT(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
{
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
return !value.empty() && value.is<T>() ? AZStd::any_cast<T>(value) : T{};
}
};
using MaterialComponentRequestBus = EBus<MaterialComponentRequests>;
@@ -151,7 +125,9 @@ namespace AZ
//! Returns the list of all ModelMaterialSlot's for the model, across all LODs.
virtual RPI::ModelMaterialSlotMap GetModelMaterialSlots() const = 0;
//! Returns the available, overridable material slots and the default assigned materials
virtual MaterialAssignmentMap GetMaterialAssignments() const = 0;
virtual AZStd::unordered_set<AZ::Name> GetModelUvNames() const = 0;
};
using MaterialReceiverRequestBus = EBus<MaterialReceiverRequests>;
@@ -161,6 +137,7 @@ namespace AZ
: public ComponentBus
{
public:
//! Notification that overridable material slots are available or have changed
virtual void OnMaterialAssignmentsChanged() = 0;
};
using MaterialReceiverNotificationBus = EBus<MaterialReceiverNotifications>;
@@ -51,6 +51,9 @@ namespace AZ
virtual void SetVisibility(bool visible) = 0;
virtual bool GetVisibility() const = 0;
virtual void SetRayTracingEnabled(bool enabled) = 0;
virtual bool GetRayTracingEnabled() const = 0;
virtual AZ::Aabb GetWorldBounds() = 0;
virtual AZ::Aabb GetLocalBounds() = 0;
@@ -1,33 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
namespace AZ
{
namespace LyIntegration
{
namespace Thumbnails
{
//! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation
//! Duplicates will be ignored
//! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp
class ThumbnailFeatureProcessorProviderRequests
: public AZ::EBusTraits
{
public:
//! Get a list of custom feature processors to register with thumbnail renderer
virtual const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const = 0;
};
using ThumbnailFeatureProcessorProviderBus = AZ::EBus<ThumbnailFeatureProcessorProviderRequests>;
} // namespace Thumbnails
} // namespace LyIntegration
} // namespace AZ
@@ -6,10 +6,10 @@
*
*/
#include "AttachmentComponent.h"
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <MathConversion.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Animation/AttachmentComponentBus.h>
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
@@ -57,13 +57,17 @@ namespace AZ
behaviorContext->EBus<LmbrCentral::AttachmentComponentRequestBus>("AttachmentComponentRequestBus")
->Event("Attach", &LmbrCentral::AttachmentComponentRequestBus::Events::Attach)
->Event("Detach", &LmbrCentral::AttachmentComponentRequestBus::Events::Detach)
->Event("SetAttachmentOffset", &LmbrCentral::AttachmentComponentRequestBus::Events::SetAttachmentOffset);
->Event("SetAttachmentOffset", &LmbrCentral::AttachmentComponentRequestBus::Events::SetAttachmentOffset)
->Event("GetJointName", &LmbrCentral::AttachmentComponentRequestBus::Events::GetJointName)
->Event("GetTargetEntityId", &LmbrCentral::AttachmentComponentRequestBus::Events::GetTargetEntityId)
->Event("GetOffset", &LmbrCentral::AttachmentComponentRequestBus::Events::GetOffset);
behaviorContext->EBus<LmbrCentral::AttachmentComponentNotificationBus>("AttachmentComponentNotificationBus")
->Handler<BehaviorAttachmentComponentNotificationBusHandler>();
}
}
void AttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AttachmentConfiguration::Reflect(context);
@@ -12,6 +12,7 @@
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
namespace AZ
{
@@ -70,7 +71,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(
AZ::Edit::Attributes::HelpPageURL,
"https://o3de.org/docs/user-guide/components/reference/attachment/")
"https://o3de.org/docs/user-guide/components/reference/animation/attachment/")
->DataElement(0, &EditorAttachmentComponent::m_targetId, "Target entity", "Attach to this entity.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetIdChanged)
->DataElement(
@@ -34,9 +34,9 @@ namespace AZ
// Shadows
->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow)
->Field("Shadow Bias", &AreaLightComponentConfig::m_bias)
->Field("Normal Shadow Bias", &AreaLightComponentConfig::m_normalShadowBias)
->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize)
->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod)
->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees)
->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount)
->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent)
;
@@ -70,12 +70,12 @@ namespace AZ::Render
->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow)
->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias)
->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias)
->Event("GetNormalShadowBias", &AreaLightRequestBus::Events::GetNormalShadowBias)
->Event("SetNormalShadowBias", &AreaLightRequestBus::Events::SetNormalShadowBias)
->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize)
->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize)
->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &AreaLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::GetSofteningBoundaryWidthAngle)
->Event("SetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::SetSofteningBoundaryWidthAngle)
->Event("GetFilteringSampleCount", &AreaLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent)
@@ -93,9 +93,9 @@ namespace AZ::Render
->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow")
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias")
->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent");
;
@@ -261,6 +261,11 @@ namespace AZ::Render
m_lightShapeDelegate->SetPhotometricUnit(m_configuration.m_intensityMode);
m_lightShapeDelegate->SetIntensity(m_configuration.m_intensity);
}
if (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AttenuationRadiusChanged();
}
}
void AreaLightComponentController::ChromaChanged()
@@ -305,9 +310,9 @@ namespace AZ::Render
if (m_configuration.m_enableShadow)
{
m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias);
m_lightShapeDelegate->SetNormalShadowBias(m_configuration.m_normalShadowBias);
m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize);
m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees);
m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent);
}
@@ -478,6 +483,20 @@ namespace AZ::Render
}
}
void AreaLightComponentController::SetNormalShadowBias(float bias)
{
m_configuration.m_normalShadowBias = bias;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetNormalShadowBias(bias);
}
}
float AreaLightComponentController::GetNormalShadowBias() const
{
return m_configuration.m_normalShadowBias;
}
ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const
{
return m_configuration.m_shadowmapMaxSize;
@@ -506,20 +525,6 @@ namespace AZ::Render
}
}
float AreaLightComponentController::GetSofteningBoundaryWidthAngle() const
{
return m_configuration.m_boundaryWidthInDegrees;
}
void AreaLightComponentController::SetSofteningBoundaryWidthAngle(float width)
{
m_configuration.m_boundaryWidthInDegrees = width;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(width);
}
}
uint32_t AreaLightComponentController::GetFilteringSampleCount() const
{
return m_configuration.m_filteringSampleCount;
@@ -82,12 +82,12 @@ namespace AZ
void SetShadowmapMaxSize(ShadowmapSize size) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidthAngle() const override;
void SetSofteningBoundaryWidthAngle(float width) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
float GetEsmExponent() const override;
void SetEsmExponent(float exponent) override;
float GetNormalShadowBias() const override;
void SetNormalShadowBias(float bias) override;
void HandleDisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
@@ -37,9 +37,11 @@ namespace AZ
->Field("IsCascadeCorrectionEnabled", &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled)
->Field("IsDebugColoringEnabled", &DirectionalLightComponentConfig::m_isDebugColoringEnabled)
->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod)
->Field("SofteningBoundaryWidth", &DirectionalLightComponentConfig::m_boundaryWidth)
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled);
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled)
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias)
->Field("Normal Shadow Bias", &DirectionalLightComponentConfig::m_normalShadowBias)
->Field("CascadeBlendingEnabled", &DirectionalLightComponentConfig::m_cascadeBlendingEnabled);
}
}
@@ -112,8 +114,7 @@ namespace AZ
bool DirectionalLightComponentConfig::IsShadowPcfDisabled() const
{
return !(m_shadowFilterMethod == ShadowFilterMethod::Pcf ||
m_shadowFilterMethod == ShadowFilterMethod::EsmPcf);
return !(m_shadowFilterMethod == ShadowFilterMethod::Pcf);
}
bool DirectionalLightComponentConfig::IsEsmDisabled() const
@@ -80,12 +80,16 @@ namespace AZ
->Event("SetDebugColoringEnabled", &DirectionalLightRequestBus::Events::SetDebugColoringEnabled)
->Event("GetShadowFilterMethod", &DirectionalLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &DirectionalLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::GetSofteningBoundaryWidth)
->Event("SetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::SetSofteningBoundaryWidth)
->Event("GetFilteringSampleCount", &DirectionalLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::GetShadowReceiverPlaneBiasEnabled)
->Event("SetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::SetShadowReceiverPlaneBiasEnabled)
->Event("GetShadowBias", &DirectionalLightRequestBus::Events::GetShadowBias)
->Event("SetShadowBias", &DirectionalLightRequestBus::Events::SetShadowBias)
->Event("GetNormalShadowBias", &DirectionalLightRequestBus::Events::GetNormalShadowBias)
->Event("SetNormalShadowBias", &DirectionalLightRequestBus::Events::SetNormalShadowBias)
->Event("GetCascadeBlendingEnabled", &DirectionalLightRequestBus::Events::GetCascadeBlendingEnabled)
->Event("SetCascadeBlendingEnabled", &DirectionalLightRequestBus::Events::SetCascadeBlendingEnabled)
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
@@ -99,9 +103,11 @@ namespace AZ
->VirtualProperty("ViewFrustumCorrectionEnabled", "GetViewFrustumCorrectionEnabled", "SetViewFrustumCorrectionEnabled")
->VirtualProperty("DebugColoringEnabled", "GetDebugColoringEnabled", "SetDebugColoringEnabled")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidth", "GetSofteningBoundaryWidth", "SetSofteningBoundaryWidth")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled");
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled")
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias")
->VirtualProperty("BlendBetweenCascadesEnabled", "GetCascadeBlendingEnabled", "SetCascadeBlendingEnabled");
;
}
}
@@ -404,26 +410,39 @@ namespace AZ
}
}
float DirectionalLightComponentController::GetSofteningBoundaryWidth() const
{
return m_configuration.m_boundaryWidth;
}
void DirectionalLightComponentController::SetSofteningBoundaryWidth(float width)
{
width = GetMin(Shadow::MaxSofteningBoundaryWidth, GetMax(0.f, width));
m_configuration.m_boundaryWidth = width;
if (m_featureProcessor)
{
m_featureProcessor->SetShadowBoundaryWidth(m_lightHandle, width);
}
}
uint32_t DirectionalLightComponentController::GetFilteringSampleCount() const
{
return aznumeric_cast<uint32_t>(m_configuration.m_filteringSampleCount);
}
void DirectionalLightComponentController::SetShadowBias(float bias)
{
m_configuration.m_shadowBias = bias;
if (m_featureProcessor)
{
m_featureProcessor->SetShadowBias(m_lightHandle, bias);
}
}
float DirectionalLightComponentController::GetShadowBias() const
{
return m_configuration.m_shadowBias;
}
void DirectionalLightComponentController::SetNormalShadowBias(float bias)
{
m_configuration.m_normalShadowBias = bias;
if (m_featureProcessor)
{
m_featureProcessor->SetNormalShadowBias(m_lightHandle, bias);
}
}
float DirectionalLightComponentController::GetNormalShadowBias() const
{
return m_configuration.m_normalShadowBias;
}
void DirectionalLightComponentController::SetFilteringSampleCount(uint32_t count)
{
const uint16_t count16 = GetMin(Shadow::MaxPcfSamplingCount, aznumeric_cast<uint16_t>(count));
@@ -517,9 +536,11 @@ namespace AZ
SetViewFrustumCorrectionEnabled(m_configuration.m_isCascadeCorrectionEnabled);
SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled);
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
SetSofteningBoundaryWidth(m_configuration.m_boundaryWidth);
SetShadowBias(m_configuration.m_shadowBias);
SetNormalShadowBias(m_configuration.m_normalShadowBias);
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled);
SetCascadeBlendingEnabled(m_configuration.m_cascadeBlendingEnabled);
// [GFX TODO][ATOM-1726] share config for multiple light (e.g., light ID).
// [GFX TODO][ATOM-2416] adapt to multiple viewports.
@@ -619,5 +640,16 @@ namespace AZ
m_featureProcessor->SetShadowReceiverPlaneBiasEnabled(m_lightHandle, enable);
}
bool DirectionalLightComponentController::GetCascadeBlendingEnabled() const
{
return m_configuration.m_cascadeBlendingEnabled;
}
void DirectionalLightComponentController::SetCascadeBlendingEnabled(bool enable)
{
m_configuration.m_cascadeBlendingEnabled = enable;
m_featureProcessor->SetCascadeBlendingEnabled(m_lightHandle, enable);
}
} // namespace Render
} // namespace AZ
@@ -76,12 +76,16 @@ namespace AZ
void SetDebugColoringEnabled(bool enabled) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidth() const override;
void SetSofteningBoundaryWidth(float width) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
bool GetShadowReceiverPlaneBiasEnabled() const override;
void SetShadowReceiverPlaneBiasEnabled(bool enable) override;
float GetShadowBias() const override;
void SetShadowBias(float bias) override;
float GetNormalShadowBias() const override;
void SetNormalShadowBias(float bias) override;
bool GetCascadeBlendingEnabled() const override;
void SetCascadeBlendingEnabled(bool enable) override;
private:
friend class EditorDirectionalLightComponent;
@@ -47,53 +47,60 @@ namespace AZ::Render
return m_shapeBus->GetRadius() * GetTransform().GetUniformScale();
}
void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& /*color*/, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, [[maybe_unused]]const Color&, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
{
if (isSelected)
debugDisplay.PushMatrix(transform);
const float radius = GetConfig()->m_attenuationRadius;
const float shapeRadius = m_shapeBus->GetRadius();
auto DrawConicalFrustum = [&debugDisplay](uint32_t numRadiusLines, const Color& color, float brightness, float topRadius, float bottomRadius, float height)
{
debugDisplay.PushMatrix(transform);
float radius = GetConfig()->m_attenuationRadius;
const Color displayColor = Color(color.GetAsVector3() * brightness);
debugDisplay.SetColor(displayColor);
debugDisplay.DrawWireDisk(Vector3(0.0, 0.0, height), Vector3::CreateAxisZ(), bottomRadius);
if (GetConfig()->m_enableShutters)
for (uint32_t i = 0; i < numRadiusLines; ++i)
{
float innerRadians = DegToRad(GetConfig()->m_innerShutterAngleDegrees);
float outerRadians = DegToRad(GetConfig()->m_outerShutterAngleDegrees);
// Draw a cone using the cone angle and attenuation radius
innerRadians = GetMin(innerRadians, outerRadians);
float coneRadiusInner = sin(innerRadians) * radius;
float coneHeightInner = cos(innerRadians) * radius;
float coneRadiusOuter = sin(outerRadians) * radius;
float coneHeightOuter = cos(outerRadians) * radius;
auto DrawConicalFrustum = [&debugDisplay](uint32_t numRadiusLines, float topRadius, float bottomRadius, float height, float brightness)
{
debugDisplay.SetColor(Color(brightness, brightness, brightness, 1.0f));
debugDisplay.DrawWireDisk(Vector3(0.0, 0.0, height), Vector3::CreateAxisZ(), bottomRadius);
for (uint32_t i = 0; i < numRadiusLines; ++i)
{
float radiusLineAngle = float(i) / numRadiusLines * Constants::TwoPi;
debugDisplay.DrawLine(
Vector3(cos(radiusLineAngle) * topRadius, sin(radiusLineAngle) * topRadius, 0),
Vector3(cos(radiusLineAngle) * bottomRadius, sin(radiusLineAngle) * bottomRadius, height)
);
}
};
DrawConicalFrustum(16, m_shapeBus->GetRadius(), m_shapeBus->GetRadius() + coneRadiusInner, coneHeightInner, 1.0f);
DrawConicalFrustum(16, m_shapeBus->GetRadius(), m_shapeBus->GetRadius() + coneRadiusOuter, coneHeightOuter, 0.65f);
float radiusLineAngle = float(i) / numRadiusLines * Constants::TwoPi;
float cosAngle = cos(radiusLineAngle);
float sinAngle = sin(radiusLineAngle);
debugDisplay.DrawLine(
Vector3(cosAngle * topRadius, sinAngle * topRadius, 0),
Vector3(cosAngle * bottomRadius,sinAngle * bottomRadius, height)
);
}
else
{
debugDisplay.DrawWireDisk(Vector3::CreateZero(), Vector3::CreateAxisZ(), radius);
debugDisplay.DrawArc(Vector3::CreateZero(), radius, 270.0f, 180.0f, 3.0f, 0);
debugDisplay.DrawArc(Vector3::CreateZero(), radius, 0.0f, 180.0f, 3.0f, 1);
}
debugDisplay.PopMatrix();
};
const Color coneColor = isSelected ? Color::CreateOne() : Color(0.0f, 0.75f, 0.75f, 1.0);
const uint32_t innerConeLines = 8;
float innerRadians, outerRadians;
if (GetConfig()->m_enableShutters)
{ // With shutters enabled, draw inner and outer debug display frustums
innerRadians = DegToRad(GetConfig()->m_innerShutterAngleDegrees);
outerRadians = DegToRad(GetConfig()->m_outerShutterAngleDegrees);
// Draw a cone using the cone angle and attenuation radius
innerRadians = GetMin(innerRadians, outerRadians);
float coneRadiusOuter = sin(outerRadians) * radius;
float coneHeightOuter = cos(outerRadians) * radius;
// Outer cone frustum 'faded' debug cone
const uint32_t outerConeLines = 9;
DrawConicalFrustum(outerConeLines, coneColor, 0.75f, shapeRadius, shapeRadius + coneRadiusOuter, coneHeightOuter);
}
else
{ // Generic debug display frustum
const float coneAngle = 25.0f;
innerRadians = DegToRad(coneAngle); // 25 degrees debug display
}
// Inner cone frustum
float coneRadiusInner = sin(innerRadians) * radius;
float coneHeightInner = cos(innerRadians) * radius;
DrawConicalFrustum(innerConeLines, coneColor, 1.0f, shapeRadius, shapeRadius + coneRadiusInner, coneHeightInner);
debugDisplay.PopMatrix();
}
void DiskLightDelegate::SetEnableShutters(bool enabled)
@@ -131,6 +138,14 @@ namespace AZ::Render
}
}
void DiskLightDelegate::SetNormalShadowBias(float bias)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias);
}
}
void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
@@ -147,14 +162,6 @@ namespace AZ::Render
}
}
void DiskLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees));
}
}
void DiskLightDelegate::SetFilteringSampleCount(uint32_t count)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
@@ -44,9 +44,9 @@ namespace AZ
void SetShadowBias(float bias) override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;
void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float exponent) override;
void SetNormalShadowBias(float bias) override;
private:
@@ -49,7 +49,7 @@ namespace AZ
->Attribute(Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AreaLight.svg")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/area-light/")
->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/light/")
;
editContext->Class<AreaLightComponentController>(
@@ -75,7 +75,7 @@ namespace AZ
->DataElement(Edit::UIHandlers::Color, &AreaLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected)
->Attribute("ColorEditorConfiguration", RPI::ColorUtils::GetLinearRgbEditorConfig())
->Attribute("ColorEditorConfiguration", RPI::ColorUtils::GetRgbEditorConfig())
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_intensityMode, "Intensity mode", "Allows specifying which photometric unit to work in.")
->Attribute(AZ::Edit::Attributes::EnumValues, &AreaLightComponentConfig::GetValidPhotometricUnits)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected)
@@ -136,7 +136,7 @@ namespace AZ
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 100.0f)
->Attribute(Edit::Attributes::SoftMin, 0.0f)
->Attribute(Edit::Attributes::SoftMax, 1.0f)
->Attribute(Edit::Attributes::SoftMax, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
@@ -154,15 +154,6 @@ namespace AZ
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening boundary width",
"Width of the boundary between shadowed area and lit one. "
"Units are in degrees. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 1.f)
->Attribute(Edit::Attributes::Suffix, " deg")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count",
"This is only used when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
@@ -180,7 +171,16 @@ namespace AZ
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled)
;
->DataElement(
Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n",
"Reduces acne by biasing the shadowmap lookup along the geometric normal.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
;
}
}
@@ -44,7 +44,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO][ATOM-1998] create icons.
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://") // [GFX TODO][ATOM-1998] create page
->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/directional-light/") // [GFX TODO][ATOM-1998] create page
;
editContext->Class<DirectionalLightComponentController>(
@@ -59,7 +59,7 @@ namespace AZ
->ClassElement(Edit::ClassElements::EditorData, "")
->DataElement(Edit::UIHandlers::Color, &DirectionalLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig())
->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetRgbEditorConfig())
->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_intensityMode, "Intensity mode", "Allows specifying light values in lux or Ev100")
->EnumAttribute(PhotometricUnit::Lux, "Lux")
->EnumAttribute(PhotometricUnit::Ev100Illuminance, "Ev100")
@@ -133,17 +133,8 @@ namespace AZ
->EnumAttribute(ShadowFilterMethod::Esm, "ESM")
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening boundary width",
"Width of the boundary between shadowed area and lit one. "
"Units are in meters. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 0.1f)
->Attribute(Edit::Attributes::Suffix, " m")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsEsmDisabled)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count",
"This is used only when the pixel is predicted as on the boundary. "
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count\n",
"This is used only when the pixel is predicted to be on the boundary.\n"
"Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 64)
@@ -151,10 +142,30 @@ namespace AZ
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::CheckBox, &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled,
"Shadow Receiver Plane Bias Enable",
"Shadow Receiver Plane Bias Enable\n",
"This reduces shadow acne when using large pcf kernels.")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled);
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_shadowBias,
"Shadow Bias\n",
"Reduces acne by applying a fixed bias along z in shadow-space.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 0.2)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n",
"Reduces acne by biasing the shadowmap lookup along the geometric normal.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(
Edit::UIHandlers::CheckBox, &DirectionalLightComponentConfig::m_cascadeBlendingEnabled,
"Blend between cascades\n", "Enables smooth blending between shadow map cascades.")
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
;
}
}
@@ -56,10 +56,10 @@ namespace AZ
void SetShadowBias([[maybe_unused]] float bias) override {};
void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {};
void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {};
void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {};
void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {};
void SetEsmExponent([[maybe_unused]] float esmExponent) override{};
void SetNormalShadowBias([[maybe_unused]] float bias) override{};
protected:
void InitBase(EntityId entityId);
@@ -75,12 +75,12 @@ namespace AZ
virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0;
//! Sets the filter method for the shadow
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Sets the width of boundary between shadowed area and lit area in degrees.
virtual void SetSofteningBoundaryWidthAngle(float widthInDegrees) = 0;
//! Sets the sample count for filtering of the shadow boundary, max 64.
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow.
virtual void SetEsmExponent(float exponent) = 0;
//! Sets the normal bias. Reduces acne by biasing the shadowmap lookup along the geometric normal.
virtual void SetNormalShadowBias(float bias) = 0;
};
} // namespace Render
} // namespace AZ
@@ -92,14 +92,6 @@ namespace AZ::Render
}
}
void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees));
}
}
void SphereLightDelegate::SetFilteringSampleCount(uint32_t count)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
@@ -115,4 +107,13 @@ namespace AZ::Render
GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent);
}
}
void SphereLightDelegate::SetNormalShadowBias(float bias)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias);
}
}
} // namespace AZ::Render
@@ -34,9 +34,9 @@ namespace AZ
void SetShadowBias(float bias) override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;
void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float esmExponent) override;
void SetNormalShadowBias(float bias) override;
private:
@@ -8,6 +8,7 @@
#include <Decals/DecalComponentController.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
@@ -229,7 +230,7 @@ namespace AZ
{
DecalNotificationBus::Event(m_entityId, &DecalNotifications::OnMaterialChanged, m_configuration.m_materialAsset);
if (m_featureProcessor && m_configuration.m_materialAsset.GetId().IsValid())
if (m_featureProcessor)
{
m_featureProcessor->SetDecalMaterial(m_handle, m_configuration.m_materialAsset.GetId());
}
@@ -192,7 +192,7 @@ namespace AZ
u32 EditorDecalComponent::OnConfigurationChanged()
{
BaseClass::OnConfigurationChanged();
m_controller.ConfigurationChanged();
return Edit::PropertyRefreshLevels::AttributesAndValues;
}
@@ -48,11 +48,7 @@ namespace AZ
void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId)
{
AZ_UNUSED(entityId);
const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get();
m_featureProcessor = scene->GetFeatureProcessor<DiffuseGlobalIlluminationFeatureProcessorInterface>();
m_featureProcessor = AZ::RPI::Scene::GetFeatureProcessorForEntity<DiffuseGlobalIlluminationFeatureProcessorInterface>(entityId);
OnConfigChanged();
}
@@ -19,5 +19,6 @@ namespace AZ
static constexpr float DefaultDiffuseProbeGridAmbientMultiplier = 1.0f;
static constexpr float DefaultDiffuseProbeGridViewBias = 0.2f;
static constexpr float DefaultDiffuseProbeGridNormalBias = 0.1f;
static constexpr DiffuseProbeGridNumRaysPerProbe DefaultDiffuseProbeGridNumRaysPerProbe = DiffuseProbeGridNumRaysPerProbe::NumRaysPerProbe_288;
} // namespace Render
} // namespace AZ
@@ -15,7 +15,7 @@
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/EntityContextBus.h>
@@ -34,22 +34,21 @@ namespace AZ
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<DiffuseProbeGridComponentConfig>()
->Version(0)
->Version(2) // Added NumRaysPerProbe setting
->Field("ProbeSpacing", &DiffuseProbeGridComponentConfig::m_probeSpacing)
->Field("Extents", &DiffuseProbeGridComponentConfig::m_extents)
->Field("AmbientMultiplier", &DiffuseProbeGridComponentConfig::m_ambientMultiplier)
->Field("ViewBias", &DiffuseProbeGridComponentConfig::m_viewBias)
->Field("NormalBias", &DiffuseProbeGridComponentConfig::m_normalBias)
->Field("NumRaysPerProbe", &DiffuseProbeGridComponentConfig::m_numRaysPerProbe)
->Field("EditorMode", &DiffuseProbeGridComponentConfig::m_editorMode)
->Field("RuntimeMode", &DiffuseProbeGridComponentConfig::m_runtimeMode)
->Field("BakedIrradianceTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureRelativePath)
->Field("BakedDistanceTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedDistanceTextureRelativePath)
->Field("BakedRelocationTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedRelocationTextureRelativePath)
->Field("BakedClassificationTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedClassificationTextureRelativePath)
->Field("BakedProbeDataTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedProbeDataTextureRelativePath)
->Field("BakedIrradianceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureAsset)
->Field("BakedDistanceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedDistanceTextureAsset)
->Field("BakedRelocationTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedRelocationTextureAsset)
->Field("BakedClassificationTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedClassificationTextureAsset)
->Field("BakedProbeDataTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedProbeDataTextureAsset)
;
}
}
@@ -121,19 +120,16 @@ namespace AZ
if (m_featureProcessor->AreBakedTexturesReferenced(
m_configuration.m_bakedIrradianceTextureRelativePath,
m_configuration.m_bakedDistanceTextureRelativePath,
m_configuration.m_bakedRelocationTextureRelativePath,
m_configuration.m_bakedClassificationTextureRelativePath))
m_configuration.m_bakedProbeDataTextureRelativePath))
{
// clear the baked texture paths and assets, since they belong to the original entity (not the clone)
m_configuration.m_bakedIrradianceTextureRelativePath.clear();
m_configuration.m_bakedDistanceTextureRelativePath.clear();
m_configuration.m_bakedRelocationTextureRelativePath.clear();
m_configuration.m_bakedClassificationTextureRelativePath.clear();
m_configuration.m_bakedProbeDataTextureRelativePath.clear();
m_configuration.m_bakedIrradianceTextureAsset.Reset();
m_configuration.m_bakedDistanceTextureAsset.Reset();
m_configuration.m_bakedRelocationTextureAsset.Reset();
m_configuration.m_bakedClassificationTextureAsset.Reset();
m_configuration.m_bakedProbeDataTextureAsset.Reset();
}
// add this diffuse probe grid to the feature processor
@@ -143,29 +139,27 @@ namespace AZ
m_featureProcessor->SetAmbientMultiplier(m_handle, m_configuration.m_ambientMultiplier);
m_featureProcessor->SetViewBias(m_handle, m_configuration.m_viewBias);
m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias);
m_featureProcessor->SetNumRaysPerProbe(m_handle, m_configuration.m_numRaysPerProbe);
// load the baked texture assets, but only if they are all valid
if (m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedDistanceTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedRelocationTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedClassificationTextureAsset.GetId().IsValid())
m_configuration.m_bakedProbeDataTextureAsset.GetId().IsValid())
{
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedIrradianceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedDistanceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedRelocationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedClassificationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedProbeDataTextureAsset.GetId());
m_configuration.m_bakedIrradianceTextureAsset.QueueLoad();
m_configuration.m_bakedDistanceTextureAsset.QueueLoad();
m_configuration.m_bakedRelocationTextureAsset.QueueLoad();
m_configuration.m_bakedClassificationTextureAsset.QueueLoad();
m_configuration.m_bakedProbeDataTextureAsset.QueueLoad();
}
else if (m_configuration.m_runtimeMode == DiffuseProbeGridMode::Baked ||
m_configuration.m_runtimeMode == DiffuseProbeGridMode::AutoSelect ||
m_configuration.m_editorMode == DiffuseProbeGridMode::Baked ||
m_configuration.m_editorMode == DiffuseProbeGridMode::AutoSelect)
{
AZ_Error("DiffuseProbeGrid", false, "DiffuseProbeGrid mdoe is set to Baked or Auto-Select, but it does not have baked texture assets. Please re-bake this DiffuseProbeGrid.");
AZ_Error("DiffuseProbeGrid", false, "DiffuseProbeGrid mode is set to Baked or Auto-Select, but it does not have baked texture assets. Please re-bake this DiffuseProbeGrid.");
}
m_featureProcessor->SetMode(m_handle, m_configuration.m_runtimeMode);
@@ -191,13 +185,11 @@ namespace AZ
// if all assets are ready we can set the baked texture images
if (m_configuration.m_bakedIrradianceTextureAsset.IsReady() &&
m_configuration.m_bakedDistanceTextureAsset.IsReady() &&
m_configuration.m_bakedRelocationTextureAsset.IsReady() &&
m_configuration.m_bakedClassificationTextureAsset.IsReady())
m_configuration.m_bakedProbeDataTextureAsset.IsReady())
{
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedIrradianceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedDistanceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedRelocationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedClassificationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedProbeDataTextureAsset.GetId());
UpdateBakedTextures();
}
@@ -330,6 +322,17 @@ namespace AZ
m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias);
}
void DiffuseProbeGridComponentController::SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe)
{
if (!m_featureProcessor)
{
return;
}
m_configuration.m_numRaysPerProbe = numRaysPerProbe;
m_featureProcessor->SetNumRaysPerProbe(m_handle, m_configuration.m_numRaysPerProbe);
}
void DiffuseProbeGridComponentController::SetEditorMode(DiffuseProbeGridMode editorMode)
{
if (!m_featureProcessor)
@@ -365,8 +368,7 @@ namespace AZ
callback,
m_configuration.m_bakedIrradianceTextureRelativePath,
m_configuration.m_bakedDistanceTextureRelativePath,
m_configuration.m_bakedRelocationTextureRelativePath,
m_configuration.m_bakedClassificationTextureRelativePath);
m_configuration.m_bakedProbeDataTextureRelativePath);
}
void DiffuseProbeGridComponentController::UpdateBakedTextures()
@@ -381,12 +383,8 @@ namespace AZ
bakedTextures.m_irradianceImageRelativePath = m_configuration.m_bakedIrradianceTextureRelativePath;
bakedTextures.m_distanceImage = RPI::StreamingImage::FindOrCreate(m_configuration.m_bakedDistanceTextureAsset);
bakedTextures.m_distanceImageRelativePath = m_configuration.m_bakedDistanceTextureRelativePath;
bakedTextures.m_relocationImageDescriptor = m_configuration.m_bakedRelocationTextureAsset->GetImageDescriptor();
bakedTextures.m_relocationImageData = m_configuration.m_bakedRelocationTextureAsset->GetSubImageData(0, 0);
bakedTextures.m_relocationImageRelativePath = m_configuration.m_bakedRelocationTextureRelativePath;
bakedTextures.m_classificationImageDescriptor = m_configuration.m_bakedClassificationTextureAsset->GetImageDescriptor();
bakedTextures.m_classificationImageData = m_configuration.m_bakedClassificationTextureAsset->GetSubImageData(0, 0);
bakedTextures.m_classificationImageRelativePath = m_configuration.m_bakedClassificationTextureRelativePath;
bakedTextures.m_probeDataImage = RPI::StreamingImage::FindOrCreate(m_configuration.m_bakedProbeDataTextureAsset);
bakedTextures.m_probeDataImageRelativePath = m_configuration.m_bakedProbeDataTextureRelativePath;
m_featureProcessor->SetBakedTextures(m_handle, bakedTextures);
}
@@ -35,19 +35,18 @@ namespace AZ
float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier;
float m_viewBias = DefaultDiffuseProbeGridViewBias;
float m_normalBias = DefaultDiffuseProbeGridNormalBias;
DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DefaultDiffuseProbeGridNumRaysPerProbe;
DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime;
DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime;
AZStd::string m_bakedIrradianceTextureRelativePath;
AZStd::string m_bakedDistanceTextureRelativePath;
AZStd::string m_bakedRelocationTextureRelativePath;
AZStd::string m_bakedClassificationTextureRelativePath;
AZStd::string m_bakedProbeDataTextureRelativePath;
Data::Asset<RPI::StreamingImageAsset> m_bakedIrradianceTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedDistanceTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedRelocationTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedClassificationTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedProbeDataTextureAsset;
AZ::u64 m_entityId{ EntityId::InvalidEntityId };
};
@@ -100,6 +99,7 @@ namespace AZ
void SetAmbientMultiplier(float ambientMultiplier);
void SetViewBias(float viewBias);
void SetNormalBias(float normalBias);
void SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe);
void SetEditorMode(DiffuseProbeGridMode editorMode);
void SetRuntimeMode(DiffuseProbeGridMode runtimeMode);
@@ -14,6 +14,7 @@
#include <AzCore/Component/Entity.h>
#include <AzCore/IO/SystemFile.h>
#include <Atom/RPI.Reflect/Image/StreamingImagePoolAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/Utils/DdsFile.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
@@ -39,6 +40,7 @@ namespace AZ
->Field("ambientMultiplier", &EditorDiffuseProbeGridComponent::m_ambientMultiplier)
->Field("viewBias", &EditorDiffuseProbeGridComponent::m_viewBias)
->Field("normalBias", &EditorDiffuseProbeGridComponent::m_normalBias)
->Field("numRaysPerProbe", &EditorDiffuseProbeGridComponent::m_numRaysPerProbe)
->Field("editorMode", &EditorDiffuseProbeGridComponent::m_editorMode)
->Field("runtimeMode", &EditorDiffuseProbeGridComponent::m_runtimeMode)
;
@@ -53,6 +55,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/diffuse-probe-grid/")
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<RPI::ModelAsset>::Uuid())
->ClassElement(AZ::Edit::ClassElements::Group, "Probe Spacing")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
@@ -91,6 +94,9 @@ namespace AZ
->Attribute(Edit::Attributes::Step, 0.1f)
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_numRaysPerProbe, "Number of Rays Per Probe", "Number of rays cast by each probe to detect lighting in its surroundings")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnNumRaysPerProbeChanged)
->Attribute(AZ::Edit::Attributes::EnumValues, &EditorDiffuseProbeGridComponent::GetNumRaysPerProbeEnumList)
->ClassElement(AZ::Edit::ClassElements::EditorData, "Grid mode")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_editorMode, "Editor Mode", "Controls whether the editor uses RealTime or Baked diffuse GI. RealTime requires a ray-tracing capable GPU. Auto-Select will fallback to Baked if ray-tracing is not available")
@@ -180,8 +186,7 @@ namespace AZ
CheckTextureAssetNotification(configuration.m_bakedIrradianceTextureRelativePath, configuration.m_bakedIrradianceTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedDistanceTextureRelativePath, configuration.m_bakedDistanceTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedRelocationTextureRelativePath, configuration.m_bakedRelocationTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedClassificationTextureRelativePath, configuration.m_bakedClassificationTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedProbeDataTextureRelativePath, configuration.m_bakedProbeDataTextureAsset);
}
void EditorDiffuseProbeGridComponent::CheckTextureAssetNotification(const AZStd::string& relativePath, Data::Asset<RPI::StreamingImageAsset>& configurationAsset)
@@ -194,13 +199,12 @@ namespace AZ
{
// bake is complete, update configuration with the new baked texture asset
AzToolsFramework::ScopedUndoBatch undoBatch("DiffuseProbeGrid Texture Bake");
configurationAsset = { textureAsset.GetAs<RPI::StreamingImageAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
configurationAsset = textureAsset;
SetDirty();
if (m_controller.m_configuration.m_bakedIrradianceTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedDistanceTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedClassificationTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedRelocationTextureAsset.IsReady())
m_controller.m_configuration.m_bakedProbeDataTextureAsset.IsReady())
{
m_controller.UpdateBakedTextures();
}
@@ -216,6 +220,19 @@ namespace AZ
}
}
AZStd::vector<Edit::EnumConstant<DiffuseProbeGridNumRaysPerProbe>> EditorDiffuseProbeGridComponent::GetNumRaysPerProbeEnumList() const
{
AZStd::vector<Edit::EnumConstant<DiffuseProbeGridNumRaysPerProbe>> enumList;
for (uint32_t index = 0; index < DiffuseProbeGridNumRaysPerProbeArraySize; ++index)
{
const DiffuseProbeGridNumRaysPerProbeEntry& entry = DiffuseProbeGridNumRaysPerProbeArray[index];
enumList.push_back(Edit::EnumConstant<DiffuseProbeGridNumRaysPerProbe>(entry.m_enum, AZStd::to_string(entry.m_rayCount).c_str()));
}
return enumList;
}
AZ::Aabb EditorDiffuseProbeGridComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo)
{
return m_controller.GetAabb();
@@ -313,6 +330,12 @@ namespace AZ
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorDiffuseProbeGridComponent::OnNumRaysPerProbeChanged()
{
m_controller.SetNumRaysPerProbe(m_numRaysPerProbe);
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorDiffuseProbeGridComponent::OnEditorModeChanged()
{
// this will update the configuration and also change the DiffuseProbeGrid mode
@@ -335,8 +358,7 @@ namespace AZ
{
if (!m_controller.m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedDistanceTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedRelocationTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedClassificationTextureAsset.GetId().IsValid())
!m_controller.m_configuration.m_bakedProbeDataTextureAsset.GetId().IsValid())
{
return AZ::Failure(AZStd::string("Please bake textures before changing the Diffuse Probe Grid to Baked or Auto-Select mode."));
}
@@ -383,21 +405,18 @@ namespace AZ
// Note: we need to make sure to use the same source image for each bake
AZStd::string irradianceTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedIrradianceTextureRelativePath, DiffuseProbeGridIrradianceFileName);
AZStd::string distanceTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedDistanceTextureRelativePath, DiffuseProbeGridDistanceFileName);
AZStd::string relocationTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedRelocationTextureRelativePath, DiffuseProbeGridRelocationFileName);
AZStd::string classificationTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedClassificationTextureRelativePath, DiffuseProbeGridClassificationFileName);
AZStd::string probeDataTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedProbeDataTextureRelativePath, DiffuseProbeGridProbeDataFileName);
// create the full paths
char projectPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN);
AZStd::string irradianceTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, irradianceTextureRelativePath.c_str(), irradianceTextureFullPath, true, true);
AZStd::string distanceTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, distanceTextureRelativePath.c_str(), distanceTextureFullPath, true, true);
AZStd::string relocationTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, relocationTextureRelativePath.c_str(), relocationTextureFullPath, true, true);
AZStd::string classificationTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, classificationTextureRelativePath.c_str(), classificationTextureFullPath, true, true);
AZStd::string probeDataTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, probeDataTextureRelativePath.c_str(), probeDataTextureFullPath, true, true);
// make sure the folder is created
AZStd::string diffuseProbeGridFolder;
@@ -407,23 +426,20 @@ namespace AZ
// check out the files in source control
CheckoutSourceTextureFile(irradianceTextureFullPath);
CheckoutSourceTextureFile(distanceTextureFullPath);
CheckoutSourceTextureFile(relocationTextureFullPath);
CheckoutSourceTextureFile(classificationTextureFullPath);
CheckoutSourceTextureFile(probeDataTextureFullPath);
// update the configuration
AzToolsFramework::ScopedUndoBatch undoBatch("DiffuseProbeGrid bake");
configuration.m_bakedIrradianceTextureRelativePath = irradianceTextureRelativePath;
configuration.m_bakedDistanceTextureRelativePath = distanceTextureRelativePath;
configuration.m_bakedRelocationTextureRelativePath = relocationTextureRelativePath;
configuration.m_bakedClassificationTextureRelativePath = classificationTextureRelativePath;
configuration.m_bakedProbeDataTextureRelativePath = probeDataTextureRelativePath;
SetDirty();
// callback for the texture readback
DiffuseProbeGridBakeTexturesCallback bakeTexturesCallback = [=](
DiffuseProbeGridTexture irradianceTexture,
DiffuseProbeGridTexture distanceTexture,
DiffuseProbeGridTexture relocationTexture,
DiffuseProbeGridTexture classificationTexture)
DiffuseProbeGridTexture probeDataTexture)
{
// irradiance
{
@@ -439,18 +455,11 @@ namespace AZ
AZ_Assert(outcome.IsSuccess(), "Failed to write Distance texture .dds file [%s]", distanceTextureFullPath.c_str());
}
// relocation
// probe data
{
AZ::DdsFile::DdsFileData fileData = { relocationTexture.m_size, relocationTexture.m_format, relocationTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(relocationTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Relocation texture .dds file [%s]", relocationTextureFullPath.c_str());
}
// classification
{
AZ::DdsFile::DdsFileData fileData = { classificationTexture.m_size, classificationTexture.m_format, classificationTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(classificationTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Classification texture .dds file [%s]", classificationTextureFullPath.c_str());
AZ::DdsFile::DdsFileData fileData = { probeDataTexture.m_size, probeDataTexture.m_format, probeDataTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(probeDataTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write ProbeData texture .dds file [%s]", probeDataTextureFullPath.c_str());
}
m_bakeInProgress = false;
@@ -480,7 +489,7 @@ namespace AZ
AZStd::string fullPath;
char projectPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN);
if (!relativePath.empty())
{
@@ -56,6 +56,7 @@ namespace AZ
AZStd::string ValidateOrCreateNewTexturePath(const AZStd::string& relativePath, const char* fileSuffix);
void CheckoutSourceTextureFile(const AZStd::string& fullPath);
void CheckTextureAssetNotification(const AZStd::string& relativePath, Data::Asset<RPI::StreamingImageAsset>& configurationAsset);
AZStd::vector<Edit::EnumConstant<DiffuseProbeGridNumRaysPerProbe>> GetNumRaysPerProbeEnumList() const;
// property change notifications
AZ::Outcome<void, AZStd::string> OnProbeSpacingValidateX(void* newValue, const AZ::Uuid& valueType);
@@ -65,6 +66,7 @@ namespace AZ
AZ::u32 OnAmbientMultiplierChanged();
AZ::u32 OnViewBiasChanged();
AZ::u32 OnNormalBiasChanged();
AZ::u32 OnNumRaysPerProbeChanged();
AZ::u32 OnEditorModeChanged();
AZ::u32 OnRuntimeModeChanged();
AZ::Outcome<void, AZStd::string> OnModeChangeValidate(void* newValue, const AZ::Uuid& valueType);
@@ -80,6 +82,7 @@ namespace AZ
float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier;
float m_viewBias = DefaultDiffuseProbeGridViewBias;
float m_normalBias = DefaultDiffuseProbeGridNormalBias;
DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DefaultDiffuseProbeGridNumRaysPerProbe;
DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime;
DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime;
@@ -6,15 +6,18 @@
*
*/
#include <EditorCommonFeaturesSystemComponent.h>
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationLifecycle.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <EditorCommonFeaturesSystemComponent.h>
#include <SharedPreview/SharedThumbnail.h>
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
#include <IEditor.h>
@@ -68,7 +71,7 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
required.push_back(AZ_CRC_CE("ThumbnailerService"));
}
void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -82,24 +85,31 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::Activate()
{
m_renderer = AZStd::make_unique<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer>();
m_previewerFactory = AZStd::make_unique <LyIntegration::CommonPreviewerFactory>();
m_skinnedMeshDebugDisplay = AZStd::make_unique<SkinnedMeshDebugDisplay>();
AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect();
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect();
if (auto settingsRegistry{ AZ::SettingsRegistry::Get() }; settingsRegistry != nullptr)
{
auto LifecycleCallback = [this](AZStd::string_view, AZ::SettingsRegistryInterface::Type)
{
SetupThumbnails();
};
AZ::ComponentApplicationLifecycle::RegisterHandler(*settingsRegistry, m_criticalAssetsHandler,
AZStd::move(LifecycleCallback), "CriticalAssetsCompiled");
}
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
}
void EditorCommonFeaturesSystemComponent::Deactivate()
{
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
m_criticalAssetsHandler = {};
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect();
m_skinnedMeshDebugDisplay.reset();
m_previewerFactory.reset();
m_renderer.reset();
TeardownThumbnails();
}
void EditorCommonFeaturesSystemComponent::OnNewLevelCreated()
@@ -199,7 +209,39 @@ namespace AZ
void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop()
{
m_renderer.reset();
TeardownThumbnails();
}
void EditorCommonFeaturesSystemComponent::SetupThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache), ThumbnailContext::DefaultContext);
if (!m_thumbnailRenderer)
{
m_thumbnailRenderer = AZStd::make_unique<AZ::LyIntegration::SharedThumbnailRenderer>();
}
if (!m_previewerFactory)
{
m_previewerFactory = AZStd::make_unique<LyIntegration::SharedPreviewerFactory>();
}
}
void EditorCommonFeaturesSystemComponent::TeardownThumbnails()
{
using namespace AzToolsFramework::Thumbnailer;
using namespace LyIntegration;
ThumbnailerRequestsBus::Broadcast(
&ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName,
ThumbnailContext::DefaultContext);
m_thumbnailRenderer.reset();
m_previewerFactory.reset();
}
} // namespace Render
} // namespace AZ
@@ -11,10 +11,10 @@
#include <AzCore/Component/Component.h>
#include <AzFramework/Application/Application.h>
#include <AzToolsFramework/API/EditorLevelNotificationBus.h>
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
#include <AzToolsFramework/AssetBrowser/Previewer/PreviewerBus.h>
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
#include <Source/Thumbnails/Preview/CommonPreviewerFactory.h>
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
#include <SharedPreview/SharedPreviewerFactory.h>
#include <SharedPreview/SharedThumbnailRenderer.h>
namespace AZ
{
@@ -53,15 +53,20 @@ namespace AZ
void OnNewLevelCreated() override;
// SliceEditorEntityOwnershipServiceBus overrides ...
void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override;
void OnSliceInstantiated(
const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override;
void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override;
// AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides...
const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override;
const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(
const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override;
// AzFramework::ApplicationLifecycleEvents overrides...
void OnApplicationAboutToStop() override;
void SetupThumbnails();
void TeardownThumbnails();
private:
AZStd::unique_ptr<SkinnedMeshDebugDisplay> m_skinnedMeshDebugDisplay;
@@ -69,8 +74,9 @@ namespace AZ
AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" };
float m_envProbeHeight{ 200.0f };
AZStd::unique_ptr<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer> m_renderer;
AZStd::unique_ptr<LyIntegration::CommonPreviewerFactory> m_previewerFactory;
AZStd::unique_ptr<AZ::LyIntegration::SharedThumbnailRenderer> m_thumbnailRenderer;
AZStd::unique_ptr<LyIntegration::SharedPreviewerFactory> m_previewerFactory;
AZ::SettingsRegistryInterface::NotifyEventHandler m_criticalAssetsHandler;
};
} // namespace Render
} // namespace AZ
@@ -34,7 +34,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/")
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/grid/")
;
editContext->Class<GridComponentController>(
@@ -79,7 +79,7 @@ namespace AZ
m_entityId = entityId;
m_dirty = true;
RPI::ScenePtr scene = RPI::RPISystemInterface::Get()->GetDefaultScene();
RPI::Scene* scene = RPI::Scene::GetSceneForEntityId(m_entityId);
if (scene)
{
AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId());
@@ -175,6 +175,10 @@ namespace AZ
void GridComponentController::OnBeginPrepareRender()
{
auto* auxGeomFP = AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::RPI::AuxGeomFeatureProcessorInterface>(m_entityId);
if (!auxGeomFP)
{
return;
}
if (auto auxGeom = auxGeomFP->GetDrawQueue())
{
BuildGrid();
@@ -34,7 +34,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/")
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/global-skylight-ibl/")
;
editContext->Class<ImageBasedLightComponentController>(
@@ -7,6 +7,7 @@
*/
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConfig.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
@@ -163,8 +163,6 @@ namespace AZ
return true;
}
}
// If this asset didn't load or isn't a cubemap, release it.
configAsset.Release();
return false;
}
@@ -6,23 +6,24 @@
*
*/
#include <Material/EditorMaterialComponent.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Material/EditorMaterialComponent.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <Material/EditorMaterialComponentSerializer.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QMenu>
#include <QAction>
#include <QCursor>
#include <QMenu>
AZ_POP_DISABLE_WARNING
namespace AZ
@@ -59,7 +60,12 @@ namespace AZ
BaseClass::Reflect(context);
EditorMaterialComponentSlot::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
if (auto jsonContext = azrtti_cast<JsonRegistrationContext*>(context))
{
jsonContext->Serializer<JsonEditorMaterialComponentSerializer>()->HandlesType<EditorMaterialComponent>();
}
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->RegisterGenericType<EditorMaterialComponentSlotContainer>();
serializeContext->RegisterGenericType<EditorMaterialComponentSlotsByLodContainer>();
@@ -76,7 +82,7 @@ namespace AZ
serializeContext->RegisterGenericType<AZStd::unordered_map<MaterialAssignmentId, Data::AssetId, AZStd::hash<MaterialAssignmentId>, AZStd::equal_to<MaterialAssignmentId>, AZStd::allocator>>();
serializeContext->RegisterGenericType<AZStd::unordered_map<MaterialAssignmentId, MaterialPropertyOverrideMap, AZStd::hash<MaterialAssignmentId>, AZStd::equal_to<MaterialAssignmentId>, AZStd::allocator>>();
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorMaterialComponent>(
"Material", "The material component specifies the material to use for this entity")
@@ -86,7 +92,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/")
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/material/")
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<RPI::MaterialAsset>::Uuid())
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorMaterialComponent::m_message, "Message", "")
->Attribute(AZ_CRC("PlaceholderText", 0xa23ec278), "Component cannot be edited with multiple entities selected")
@@ -129,7 +135,7 @@ namespace AZ
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->ConstantProperty("EditorMaterialComponentTypeId", BehaviorConstant(Uuid(EditorMaterialComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
@@ -148,11 +154,13 @@ namespace AZ
BaseClass::Activate();
MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId());
MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId());
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
UpdateMaterialSlots();
}
void EditorMaterialComponent::Deactivate()
{
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
MaterialReceiverNotificationBus::Handler::BusDisconnect();
MaterialComponentNotificationBus::Handler::BusDisconnect();
BaseClass::Deactivate();
@@ -238,6 +246,19 @@ namespace AZ
UpdateMaterialSlots();
});
action->setToolTip("Repair materials that reference missing assets by assigning the default asset.");
action = menu->addAction("Apply Automatic Property Updates", [this]() {
AzToolsFramework::ScopedUndoBatch undoBatch("Applying automatic property updates.");
SetDirty();
uint32_t propertiesUpdated = 0;
MaterialComponentRequestBus::EventResult(propertiesUpdated, GetEntityId(), &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates);
AZ_Printf("EditorMaterialComponent", "Updated %u property(s).", propertiesUpdated);
UpdateMaterialSlots();
});
action->setToolTip("Repair material property overrides that reference missing properties by auto-renaming them where possible.");
}
void EditorMaterialComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
@@ -260,6 +281,18 @@ namespace AZ
}
}
void EditorMaterialComponent::OnRenderMaterialPreviewComplete(
[[maybe_unused]] const AZ::EntityId& entityId,
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
[[maybe_unused]] const QPixmap& pixmap)
{
if (entityId == GetEntityId())
{
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
}
}
AZ::u32 EditorMaterialComponent::OnConfigurationChanged()
{
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
@@ -9,6 +9,7 @@
#pragma once
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
#include <Material/EditorMaterialComponentSlot.h>
@@ -21,10 +22,13 @@ namespace AZ
//! In-editor material component for displaying and editing material assignments.
class EditorMaterialComponent final
: public EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>
, private MaterialReceiverNotificationBus::Handler
, private MaterialComponentNotificationBus::Handler
, public MaterialReceiverNotificationBus::Handler
, public MaterialComponentNotificationBus::Handler
, public EditorMaterialSystemComponentNotificationBus::Handler
{
public:
friend class JsonEditorMaterialComponentSerializer;
using BaseClass = EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>;
AZ_EDITOR_COMPONENT(EditorMaterialComponent, EditorMaterialComponentTypeId, BaseClass);
@@ -52,6 +56,10 @@ namespace AZ
//! MaterialComponentNotificationBus::Handler overrides...
void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override;
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
// Regenerates the editor component material slots based on the material and
// LOD mapping from the model or other consumer of materials.
// If any corresponding material assignments are found in the component
@@ -23,10 +23,6 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
@@ -49,29 +45,18 @@ namespace AZ
MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent)
: AtomToolsFramework::InspectorWidget(parent)
{
// Create the menu button
QToolButton* menuButton = new QToolButton(this);
menuButton->setAutoRaise(true);
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
menuButton->setVisible(true);
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
AddHeading(menuButton);
m_messageLabel = new QLabel(this);
m_messageLabel->setWordWrap(true);
m_messageLabel->setVisible(true);
m_messageLabel->setAlignment(Qt::AlignCenter);
m_messageLabel->setText(tr("Material not available"));
AddHeading(m_messageLabel);
CreateHeading();
AZ::TickBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
}
MaterialPropertyInspector::~MaterialPropertyInspector()
{
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
MaterialComponentNotificationBus::Handler::BusDisconnect();
}
@@ -88,6 +73,12 @@ namespace AZ
AZ::Data::AssetId materialAssetId = {};
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
if (!materialAssetId.IsValid())
{
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId,
m_materialAssignmentId);
}
if (!materialAssetId.IsValid())
{
@@ -134,7 +125,7 @@ namespace AZ
}
Populate();
m_messageLabel->setVisible(false);
LoadOverridesFromEntity();
return true;
}
@@ -146,8 +137,9 @@ namespace AZ
m_dirtyPropertyFlags.set();
m_editorFunctors = {};
m_internalEditNotification = {};
m_messageLabel->setVisible(true);
m_messageLabel->setText(tr("Material not available"));
m_updateUI = {};
m_updatePreview = {};
UpdateHeading();
}
bool MaterialPropertyInspector::IsLoaded() const
@@ -162,49 +154,63 @@ namespace AZ
m_dirtyPropertyFlags.set();
m_internalEditNotification = {};
AZ::TickBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset();
}
void MaterialPropertyInspector::AddDetailsGroup()
void MaterialPropertyInspector::CreateHeading()
{
const AZStd::string& groupName = "Details";
const AZStd::string& groupDisplayName = "Details";
const AZStd::string& groupDescription = "";
// Create the menu button
QToolButton* menuButton = new QToolButton(this);
menuButton->setAutoRaise(true);
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
menuButton->setVisible(true);
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
AddHeading(menuButton);
auto propertyGroupContainer = new QWidget(this);
propertyGroupContainer->setLayout(new QHBoxLayout());
m_overviewImage = new QLabel(this);
m_overviewImage->setFixedSize(QSize(120, 120));
m_overviewImage->setScaledContents(true);
m_overviewImage->setVisible(false);
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey =
MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId);
auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this);
thumbnailWidget->setFixedSize(QSize(120, 120));
thumbnailWidget->setVisible(true);
thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext);
propertyGroupContainer->layout()->addWidget(thumbnailWidget);
auto materialInfoWidget = new QLabel(this);
m_overviewText = new QLabel(this);
QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth());
materialInfoWidget->setSizePolicy(sizePolicy1);
materialInfoWidget->setMinimumSize(QSize(0, 0));
materialInfoWidget->setMaximumSize(QSize(16777215, 16777215));
materialInfoWidget->setTextFormat(Qt::AutoText);
materialInfoWidget->setScaledContents(false);
materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
materialInfoWidget->setWordWrap(true);
sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth());
m_overviewText->setSizePolicy(sizePolicy1);
m_overviewText->setMinimumSize(QSize(0, 0));
m_overviewText->setMaximumSize(QSize(16777215, 16777215));
m_overviewText->setTextFormat(Qt::AutoText);
m_overviewText->setScaledContents(false);
m_overviewText->setWordWrap(true);
m_overviewText->setVisible(true);
auto overviewContainer = new QWidget(this);
overviewContainer->setLayout(new QHBoxLayout());
overviewContainer->layout()->addWidget(m_overviewImage);
overviewContainer->layout()->addWidget(m_overviewText);
AddHeading(overviewContainer);
}
void MaterialPropertyInspector::UpdateHeading()
{
if (!IsLoaded())
{
m_overviewText->setText(tr("Material not available"));
m_overviewText->setAlignment(Qt::AlignCenter);
m_overviewImage->setVisible(false);
return;
}
QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str());
QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str());
QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str());
QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
QFileInfo materialParentSourceFileInfo(
AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(
entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
AZStd::string slotName;
MaterialComponentRequestBus::EventResult(
@@ -220,7 +226,8 @@ namespace AZ
}
if (!materialTypeSourceFileInfo.fileName().isEmpty())
{
materialInfo += tr("<tr><td><b>Material Type&emsp;</b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
materialInfo +=
tr("<tr><td><b>Material Type&emsp;</b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
}
if (!materialSourceFileInfo.fileName().isEmpty())
{
@@ -228,14 +235,21 @@ namespace AZ
}
if (!materialParentSourceFileInfo.fileName().isEmpty())
{
materialInfo += tr("<tr><td><b>Material Parent&emsp;</b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
materialInfo +=
tr("<tr><td><b>Material Parent&emsp;</b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
}
materialInfo += tr("</table>");
materialInfoWidget->setText(materialInfo);
propertyGroupContainer->layout()->addWidget(materialInfoWidget);
m_overviewText->setText(materialInfo);
m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer);
QPixmap pixmap;
EditorMaterialSystemComponentRequestBus::BroadcastResult(
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId,
m_materialAssignmentId);
m_overviewImage->setPixmap(pixmap);
m_overviewImage->setVisible(true);
m_updatePreview |= pixmap.isNull();
}
void MaterialPropertyInspector::AddUvNamesGroup()
@@ -271,17 +285,13 @@ namespace AZ
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName));
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {},
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
}
void MaterialPropertyInspector::Populate()
void MaterialPropertyInspector::AddPropertiesGroup()
{
AddGroupsBegin();
AddDetailsGroup();
AddUvNamesGroup();
// Copy all of the properties from the material asset to the source data that will be exported
// TODO: Support populating the Material Editor with nested property sets, not just the top level.
for (const AZStd::unique_ptr<AZ::RPI::MaterialTypeSourceData::PropertySet>& propertySet : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertySets)
@@ -301,24 +311,38 @@ namespace AZ
AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition.get());
const auto& propertyIndex =
m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
propertyConfig.m_groupName = groupDisplayName;
const auto& propertyIndex = m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
propertyConfig.m_showThumbnail = true;
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
// There is no explicit parent material here. Material instance property overrides replace the values from the
// assigned material asset. Its values should be treated as parent, for comparison, in this case.
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(
m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
group.m_properties.emplace_back(propertyConfig);
}
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName));
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {},
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
}
}
void MaterialPropertyInspector::Populate()
{
AddGroupsBegin();
AddUvNamesGroup();
AddPropertiesGroup();
AddGroupsEnd();
LoadOverridesFromEntity();
}
void MaterialPropertyInspector::LoadOverridesFromEntity()
@@ -333,6 +357,25 @@ namespace AZ
m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides,
m_materialAssignmentId);
// Apply any automatic property renames so that the material inspector will be properly initialized with the right values
// for properties that have new names.
{
AZStd::vector<AZStd::pair<Name, Name>> renamedProperties;
for (auto& propertyOverridePair : m_editData.m_materialPropertyOverrideMap)
{
Name name = propertyOverridePair.first;
if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(name))
{
renamedProperties.emplace_back(propertyOverridePair.first, name);
}
}
for (const auto& [oldName, newName] : renamedProperties)
{
m_editData.m_materialPropertyOverrideMap[newName] = m_editData.m_materialPropertyOverrideMap[oldName];
m_editData.m_materialPropertyOverrideMap.erase(oldName);
}
}
for (auto& group : m_groups)
{
for (auto& property : group.second.m_properties)
@@ -363,6 +406,7 @@ namespace AZ
m_dirtyPropertyFlags.set();
RunEditorMaterialFunctors();
RebuildAll();
UpdateHeading();
}
void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges)
@@ -386,6 +430,9 @@ namespace AZ
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
m_internalEditNotification = false;
}
// m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs
// throttling
}
void MaterialPropertyInspector::RunEditorMaterialFunctors()
@@ -492,25 +539,32 @@ namespace AZ
}
}
AZ::Crc32 MaterialPropertyInspector::GetSaveStateKeyForGroup(const AZStd::string& groupName) const
AZ::Crc32 MaterialPropertyInspector::GetGroupSaveStateKey(const AZStd::string& groupName) const
{
return AZ::Crc32(AZStd::string::format(
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_editData.m_materialAssetId.ToString<AZStd::string>().c_str(),
groupName.c_str()));
}
bool MaterialPropertyInspector::AreNodePropertyValuesEqual(
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target)
bool MaterialPropertyInspector::IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const
{
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(node);
return property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
}
const char* MaterialPropertyInspector::GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const
{
if (IsInstanceNodePropertyModifed(node))
{
return ":/Icons/changed_property.svg";
}
return ":/Icons/blank.png";
}
bool MaterialPropertyInspector::SaveMaterial() const
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
@@ -588,7 +642,8 @@ namespace AZ
MaterialComponentRequestBus::Event(
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
MaterialPropertyOverrideMap());
QueueUpdateUI();
m_updateUI = true;
m_updatePreview = true;
});
action->setEnabled(IsLoaded());
@@ -683,10 +738,7 @@ namespace AZ
void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId)
{
if (m_entityId == entityId)
{
QueueUpdateUI();
}
m_updateUI |= (m_entityId == entityId);
}
void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId)
@@ -700,35 +752,54 @@ namespace AZ
void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
{
AZ_UNUSED(name);
if (m_entityId == entityId)
{
QueueUpdateUI();
}
m_updateUI |= (m_entityId == entityId);
}
void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time)
{
AZ_UNUSED(time);
AZ_UNUSED(deltaTime);
UpdateUI();
AZ::TickBus::Handler::BusDisconnect();
if (m_updateUI)
{
m_updateUI = false;
UpdateUI();
}
if (m_updatePreview)
{
m_updatePreview = false;
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId);
}
}
void MaterialPropertyInspector::OnMaterialsEdited()
{
if (!m_internalEditNotification)
m_updateUI |= !m_internalEditNotification;
m_updatePreview = true;
}
void MaterialPropertyInspector::OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)
{
if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId)
{
QueueUpdateUI();
m_overviewImage->setPixmap(pixmap);
}
}
void MaterialPropertyInspector::UpdateUI()
{
AZ::Data::AssetId assetId;
AZ::Data::AssetId materialAssetId = {};
MaterialComponentRequestBus::EventResult(
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
if (!materialAssetId.IsValid())
{
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_materialAssignmentId);
}
if (IsLoaded() && m_editData.m_materialAssetId == assetId)
if (IsLoaded() && m_editData.m_materialAssetId == materialAssetId)
{
LoadOverridesFromEntity();
}
@@ -737,16 +808,6 @@ namespace AZ
LoadMaterial(m_entityId, m_materialAssignmentId);
}
}
void MaterialPropertyInspector::QueueUpdateUI()
{
if (!AZ::TickBus::Handler::BusIsConnected())
{
AZ::TickBus::Handler::BusConnect();
}
}
} // namespace EditorMaterialComponentInspector
} // namespace Render
} // namespace AZ
//#include <AtomLyIntegration/CommonFeatures/moc_EditorMaterialComponentInspector.cpp>
@@ -9,6 +9,7 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
@@ -31,14 +32,13 @@ namespace AZ
{
namespace EditorMaterialComponentInspector
{
using PropertyChangedCallback = AZStd::function<void(const MaterialPropertyOverrideMap&)>;
class MaterialPropertyInspector
: public AtomToolsFramework::InspectorWidget
, public AzToolsFramework::IPropertyEditorNotify
, public AZ::EntitySystemBus::Handler
, public AZ::TickBus::Handler
, public MaterialComponentNotificationBus::Handler
, public EditorMaterialSystemComponentNotificationBus::Handler
{
Q_OBJECT
public:
@@ -89,20 +89,28 @@ namespace AZ
//! MaterialComponentNotificationBus::Handler overrides...
void OnMaterialsEdited() override;
void UpdateUI();
void QueueUpdateUI();
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
void OnRenderMaterialPreviewComplete(
const AZ::EntityId& entityId,
const AZ::Render::MaterialAssignmentId& materialAssignmentId,
const QPixmap& pixmap) override;
void UpdateUI();
void CreateHeading();
void UpdateHeading();
void AddDetailsGroup();
void AddUvNamesGroup();
void AddPropertiesGroup();
void LoadOverridesFromEntity();
void SaveOverridesToEntity(bool commitChanges);
void RunEditorMaterialFunctors();
void UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property);
AZ::Crc32 GetSaveStateKeyForGroup(const AZStd::string& groupName) const;
static bool AreNodePropertyValuesEqual(
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target);
AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const;
bool IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const;
const char* GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const;
// Tracking the property that is actively being edited in the inspector
const AtomToolsFramework::DynamicProperty* m_activeProperty = {};
@@ -115,7 +123,10 @@ namespace AZ
AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {};
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups = {};
bool m_internalEditNotification = {};
QLabel* m_messageLabel = {};
bool m_updateUI = {};
bool m_updatePreview = {};
QLabel* m_overviewText = {};
QLabel* m_overviewImage = {};
};
} // namespace EditorMaterialComponentInspector
} // namespace Render
@@ -0,0 +1,109 @@
/*
* 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/Serialization/Json/JsonSerializationResult.h>
#include <Material/EditorMaterialComponent.h>
#include <Material/EditorMaterialComponentSerializer.h>
namespace AZ
{
namespace Render
{
AZ_CLASS_ALLOCATOR_IMPL(JsonEditorMaterialComponentSerializer, AZ::SystemAllocator, 0);
AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Load(
void* outputValue,
[[maybe_unused]] const AZ::Uuid& outputValueTypeId,
const rapidjson::Value& inputValue,
AZ::JsonDeserializerContext& context)
{
namespace JSR = AZ::JsonSerializationResult;
AZ_Assert(
azrtti_typeid<EditorMaterialComponent>() == outputValueTypeId,
"Unable to deserialize EditorMaterialComponent from json because the provided type is %s.",
outputValueTypeId.ToString<AZStd::string>().c_str());
auto componentInstance = reinterpret_cast<EditorMaterialComponent*>(outputValue);
AZ_Assert(componentInstance, "Output value for JsonEditorMaterialComponentSerializer can't be null.");
JSR::ResultCode result(JSR::Tasks::ReadField);
result.Combine(ContinueLoadingFromJsonObjectField(
&componentInstance->m_id, azrtti_typeid<decltype(componentInstance->m_id)>(), inputValue, "Id", context));
result.Combine(ContinueLoadingFromJsonObjectField(
&componentInstance->m_controller, azrtti_typeid<decltype(componentInstance->m_controller)>(), inputValue, "Controller",
context));
result.Combine(ContinueLoadingFromJsonObjectField(
&componentInstance->m_materialSlotsByLodEnabled, azrtti_typeid<decltype(componentInstance->m_materialSlotsByLodEnabled)>(),
inputValue, "materialSlotsByLodEnabled", context));
return context.Report(
result,
result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded EditorMaterialComponent information."
: "Failed to load EditorMaterialComponent information.");
}
AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Store(
rapidjson::Value& outputValue,
const void* inputValue,
const void* defaultValue,
[[maybe_unused]] const AZ::Uuid& valueTypeId,
AZ::JsonSerializerContext& context)
{
namespace JSR = AZ::JsonSerializationResult;
AZ_Assert(
azrtti_typeid<EditorMaterialComponent>() == valueTypeId,
"Unable to Serialize EditorMaterialComponent because the provided type is %s.",
valueTypeId.ToString<AZStd::string>().c_str());
auto componentInstance = reinterpret_cast<const EditorMaterialComponent*>(inputValue);
AZ_Assert(componentInstance, "Input value for JsonEditorMaterialComponentSerializer can't be null.");
auto defaultComponentInstance = reinterpret_cast<const EditorMaterialComponent*>(defaultValue);
JSR::ResultCode result(JSR::Tasks::WriteValue);
{
AZ::ScopedContextPath subPathName(context, "m_id");
const auto componentId = &componentInstance->m_id;
const auto defaultComponentId = defaultComponentInstance ? &defaultComponentInstance->m_id : nullptr;
result.Combine(ContinueStoringToJsonObjectField(
outputValue, "Id", componentId, defaultComponentId, azrtti_typeid<decltype(componentInstance->m_id)>(), context));
}
{
AZ::ScopedContextPath subPathName(context, "Controller");
const auto controller = &componentInstance->m_controller;
const auto defaultController = defaultComponentInstance ? &defaultComponentInstance->m_controller : nullptr;
result.Combine(ContinueStoringToJsonObjectField(
outputValue, "Controller", controller, defaultController, azrtti_typeid<decltype(componentInstance->m_controller)>(),
context));
}
{
AZ::ScopedContextPath subPathName(context, "materialSlotsByLodEnabled");
const auto enabled = &componentInstance->m_materialSlotsByLodEnabled;
const auto defaultEnabled = defaultComponentInstance ? &defaultComponentInstance->m_materialSlotsByLodEnabled : nullptr;
result.Combine(ContinueStoringToJsonObjectField(
outputValue, "materialSlotsByLodEnabled", enabled, defaultEnabled,
azrtti_typeid<decltype(componentInstance->m_materialSlotsByLodEnabled)>(), context));
}
return context.Report(
result,
result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored EditorMaterialComponent information."
: "Failed to store EditorMaterialComponent information.");
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,41 @@
/*
* 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/Memory.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
namespace AZ
{
namespace Render
{
// JsonEditorMaterialComponentSerializer skips serialization of EditorMaterialComponentSlot(s) which are only needed at runtime in
// the editor
class JsonEditorMaterialComponentSerializer : public AZ::BaseJsonSerializer
{
public:
AZ_RTTI(JsonEditorMaterialComponentSerializer, "{D354FE3C-34D2-4E80-B3F9-49450D252336}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
AZ::JsonSerializationResult::Result Load(
void* outputValue,
const AZ::Uuid& outputValueTypeId,
const rapidjson::Value& inputValue,
AZ::JsonDeserializerContext& context) override;
AZ::JsonSerializationResult::Result Store(
rapidjson::Value& outputValue,
const void* inputValue,
const void* defaultValue,
const AZ::Uuid& valueTypeId,
AZ::JsonSerializerContext& context) override;
};
} // namespace Render
} // namespace AZ
@@ -6,22 +6,25 @@
*
*/
#include <Material/EditorMaterialComponentSlot.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <Material/EditorMaterialComponentInspector.h>
#include <Material/EditorMaterialModelUvNameMapInspector.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Material/EditorMaterialComponentExporter.h>
#include <Material/EditorMaterialComponentInspector.h>
#include <Material/EditorMaterialComponentSlot.h>
#include <Material/EditorMaterialModelUvNameMapInspector.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QMenu>
#include <QAction>
#include <QAction>
#include <QByteArray>
#include <QCursor>
#include <QDataStream>
#include <QMenu>
AZ_POP_DISABLE_WARNING
namespace AZ
@@ -99,6 +102,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData)
;
}
}
@@ -117,10 +121,43 @@ namespace AZ
}
};
AZStd::vector<char> EditorMaterialComponentSlot::GetPreviewPixmapData() const
{
if (!GetActiveAssetId().IsValid())
{
return {};
}
QPixmap pixmap;
EditorMaterialSystemComponentRequestBus::BroadcastResult(
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id);
if (pixmap.isNull())
{
if (m_updatePreview)
{
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
m_updatePreview = false;
}
return {};
}
QByteArray pixmapBytes;
QDataStream stream(&pixmapBytes, QIODevice::WriteOnly);
stream << pixmap;
return AZStd::vector<char>(pixmapBytes.begin(), pixmapBytes.end());
}
AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const
{
return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId();
}
AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const
{
AZ::Data::AssetId assetId;
MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
MaterialComponentRequestBus::EventResult(
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
return assetId;
}
@@ -134,7 +171,7 @@ namespace AZ
bool EditorMaterialComponentSlot::HasSourceData() const
{
// The slot only has valid source data if the source path is valid and the file has the correct extension
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
}
@@ -162,14 +199,6 @@ namespace AZ
ClearOverrides();
}
void EditorMaterialComponentSlot::ClearToDefaultAsset()
{
m_materialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(GetDefaultAssetId(), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
MaterialComponentRequestBus::Event(
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
ClearOverrides();
}
void EditorMaterialComponentSlot::ClearOverrides()
{
MaterialComponentRequestBus::Event(
@@ -219,7 +248,7 @@ namespace AZ
void EditorMaterialComponentSlot::OpenMaterialEditor() const
{
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
{
EditorMaterialSystemComponentRequestBus::Broadcast(
@@ -235,7 +264,7 @@ namespace AZ
void EditorMaterialComponentSlot::OpenUvNameMapInspector()
{
if (m_materialAsset.GetId().IsValid())
if (GetActiveAssetId().IsValid())
{
AZStd::unordered_set<AZ::Name> modelUvNames;
MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames);
@@ -251,7 +280,7 @@ namespace AZ
};
if (EditorMaterialComponentInspector::OpenInspectorDialog(
m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
GetActiveAssetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
{
OnDataChanged();
}
@@ -273,10 +302,10 @@ namespace AZ
action->setEnabled(HasSourceData());
action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); });
action->setEnabled(m_materialAsset.GetId().IsValid());
action->setEnabled(GetActiveAssetId().IsValid());
action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); });
action->setEnabled(m_materialAsset.GetId().IsValid());
action->setEnabled(GetActiveAssetId().IsValid());
menu.addSeparator();
@@ -308,6 +337,10 @@ namespace AZ
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
EditorMaterialSystemComponentRequestBus::Broadcast(
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
m_updatePreview = false;
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
@@ -8,36 +8,52 @@
#pragma once
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/Feature/Material/MaterialAssignment.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <QPixmap>
namespace AZ
{
namespace Render
{
static const size_t DefaultMaterialSlotIndex = std::numeric_limits<size_t>::max();
//! Details for a single editable material assignment
struct EditorMaterialComponentSlot final
{
AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}");
AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0);
static void Reflect(ReflectContext* context);
static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
static void Reflect(ReflectContext* context);
//! Get cached preview image as a buffer to use as an RPE attribute
//! If a cached image isn't avalible then a request will be made to render one
AZStd::vector<char> GetPreviewPixmapData() const;
//! Returns the overridden asset id if it's valid, otherwise gets the default asseet id
AZ::Data::AssetId GetActiveAssetId() const;
//! Returns the default asseet id of the material provded by the model
AZ::Data::AssetId GetDefaultAssetId() const;
//! Returns the display name of the material slot
AZStd::string GetLabel() const;
//! Returns true if the active material asset has a source material
bool HasSourceData() const;
//! Assign a new material override asset
void SetAsset(const Data::AssetId& assetId);
//! Assign a new material override asset
void SetAsset(const Data::Asset<RPI::MaterialAsset>& asset);
//! Remove material and prperty overrides
void Clear();
void ClearToDefaultAsset();
//! Remove prperty overrides
void ClearOverrides();
void OpenMaterialExporter();
@@ -53,6 +69,7 @@ namespace AZ
void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
void OnMaterialChanged() const;
void OnDataChanged() const;
mutable bool m_updatePreview = true;
};
// Vector of slots for assignable or overridable material data.
@@ -61,8 +78,8 @@ namespace AZ
// Table containing all editable material data that is displayed in the edit context and inspector
// The vector represents all the LODs that can have material overrides.
// The container will be populated with every potential material slot on an associated model, using its default values.
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map
// as overrides that will be applied to material instances
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment
// map as overrides that will be applied to material instances
using EditorMaterialComponentSlotsByLodContainer = AZStd::vector<EditorMaterialComponentSlotContainer>;
} // namespace Render
} // namespace AZ
@@ -17,6 +17,7 @@
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
@@ -97,56 +98,31 @@ namespace AZ
bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData)
{
// Construct the material source data object that will be exported
AZ::RPI::MaterialSourceData exportData;
exportData.m_propertyLayoutVersion = editData.m_materialTypeSourceData.GetPropertyLayout().m_version;
// Converting absolute material paths to relative paths
bool result = false;
AZ::Data::AssetInfo info;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
editData.m_materialTypeSourcePath.c_str(), info, watchFolder);
if (!result)
if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() ||
editData.m_materialTypeSourcePath.empty())
{
AZ_Error(
"AZ::Render::EditorMaterialComponentUtil", false,
"Failed to get material type source file info while attempting to export: %s", path.c_str());
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str());
return false;
}
exportData.m_materialType = info.m_relativePath;
if (!editData.m_materialParentSourcePath.empty())
{
result = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
editData.m_materialParentSourcePath.c_str(), info, watchFolder);
if (!result)
{
AZ_Error(
"AZ::Render::EditorMaterialComponentUtil", false,
"Failed to get parent material source file info while attempting to export: %s", path.c_str());
return false;
}
exportData.m_parentMaterial = info.m_relativePath;
}
// Construct the material source data object that will be exported
AZ::RPI::MaterialSourceData exportData;
exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion();
exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath);
exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath);
// Copy all of the properties from the material asset to the source data that will be exported
result = true;
bool result = true;
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition)
{
AZ::Name propertyId(propertyIdContext + propertyDefinition->m_name);
const AZ::RPI::MaterialPropertyIndex propertyIndex =
editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId);
AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
AZ::RPI::MaterialPropertyValue propertyValue =
editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition->m_value;
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value;
if (editData.m_materialParentAsset.IsReady())
{
propertyValueDefault = editData.m_materialParentAsset->GetPropertyValues()[propertyIndex.GetIndex()];
@@ -154,12 +130,12 @@ namespace AZ
// Check for and apply any property overrides before saving property values
auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId);
if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
{
propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second);
}
if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(*propertyDefinition, propertyValue))
if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, propertyDefinition, propertyValue))
{
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str());
result = false;
@@ -171,10 +147,11 @@ namespace AZ
{
return true;
}
// TODO: Support populating the Material Editor with nested property sets, not just the top level.
const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->m_name.size() - 1);
exportData.m_properties[groupName][propertyDefinition->m_name].m_value = propertyValue;
exportData.m_properties[groupName][propertyDefinition.m_name].m_value = propertyValue;
return true;
});
@@ -290,14 +290,22 @@ namespace AZ
menuButton->setAutoRaise(true);
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
menuButton->setVisible(true);
QObject::connect(menuButton, &QToolButton::clicked, &dialog, [&]() {
QAction* action = nullptr;
QMenu menu(&dialog);
action = menu.addAction("Clear", [&] { inspector->SetUvNameMap(RPI::MaterialModelUvOverrideMap()); });
action = menu.addAction("Revert", [&] { inspector->SetUvNameMap(matModUvOverrides);; });
menu.exec(QCursor::pos());
});
QObject::connect(
menuButton, &QToolButton::clicked, &dialog, [&]()
{
QMenu menu(&dialog);
menu.addAction(
"Clear", [&]
{
inspector->SetUvNameMap(RPI::MaterialModelUvOverrideMap());
});
menu.addAction(
"Revert", [&]
{
inspector->SetUvNameMap(matModUvOverrides);
});
menu.exec(QCursor::pos());
});
QDialogButtonBox* buttonBox = new QDialogButtonBox(&dialog);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);

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