Merge branch 'main' into pruiksma/ATOM-15561

This commit is contained in:
pruiksma
2021-05-19 14:26:30 -05:00
144 changed files with 7583 additions and 741 deletions
@@ -101,7 +101,7 @@ struct VSOutput
float2 m_uv[UvSetCount] : UV1;
float2 m_detailUv : UV3;
float4 m_blendMask : UV8;
float4 m_wrinkleBlendFactors : UV8;
};
#include <Atom/Features/Vertex/VertexHelper.azsli>
@@ -132,11 +132,11 @@ VSOutput SkinVS(VSInput IN)
if(o_blendMask_isBound)
{
OUT.m_blendMask = IN.m_optional_blendMask;
OUT.m_wrinkleBlendFactors = IN.m_optional_blendMask;
}
else
{
OUT.m_blendMask = float4(0,1,0,0);
OUT.m_wrinkleBlendFactors = float4(0,0,0,0);
}
VertexHelper(IN, OUT, worldPosition, false);
@@ -214,7 +214,22 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
// ------- Wrinkle Map Setup -------
// Combine the optional per-morph target wrinkle masks
float4 wrinkleBlendFactors = float4(0.0, 0.0, 0.0, 0.0);
for(uint wrinkleMaskIndex = 0; wrinkleMaskIndex < ObjectSrg::m_wrinkle_mask_count; ++wrinkleMaskIndex)
{
wrinkleBlendFactors += ObjectSrg::m_wrinkle_masks[wrinkleMaskIndex].Sample(MaterialSrg::m_sampler, normalUv) * ObjectSrg::GetWrinkleMaskWeight(wrinkleMaskIndex);
}
// If texture based morph target driven masks are being used, use those values instead of the per-vertex colors
if(ObjectSrg::m_wrinkle_mask_count)
{
IN.m_wrinkleBlendFactors = saturate(wrinkleBlendFactors);
}
// Since the wrinkle normal maps should all be in the same tangent space as the main normal map, we should be able to blend the raw normal map
// texture values before doing all the tangent space transforms, so we only have to do the transforms once, for better performance.
@@ -223,12 +238,12 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
{
normalMapSample = SampleNormalXY(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY);
}
if(o_wrinkleLayers_enabled && o_blendMask_isBound && o_wrinkleLayers_normal_enabled)
if(o_wrinkleLayers_enabled && o_wrinkleLayers_normal_enabled)
{
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture1, normalMapSample, MaterialSrg::m_wrinkle_normal_texture1, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.r);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture2, normalMapSample, MaterialSrg::m_wrinkle_normal_texture2, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.g);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture3, normalMapSample, MaterialSrg::m_wrinkle_normal_texture3, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.b);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.a);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture1, normalMapSample, MaterialSrg::m_wrinkle_normal_texture1, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.r);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture2, normalMapSample, MaterialSrg::m_wrinkle_normal_texture2, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.g);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture3, normalMapSample, MaterialSrg::m_wrinkle_normal_texture3, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.b);
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.a);
}
if(o_detail_normal_useTexture)
@@ -255,7 +270,7 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float3 baseColor = GetBaseColorInput(MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, baseColorUv, MaterialSrg::m_baseColor, o_baseColor_useTexture);
bool useSampledBaseColor = o_baseColor_useTexture;
if(o_wrinkleLayers_enabled && o_blendMask_isBound && o_wrinkleLayers_baseColor_enabled)
if(o_wrinkleLayers_enabled && o_wrinkleLayers_baseColor_enabled)
{
// If any of the wrinkle maps are applied, we will use the Base Color blend settings to apply the MaterialSrg::m_baseColor tint to the wrinkle maps,
// even if the main base color map is not used.
@@ -272,10 +287,10 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
baseColor = float3(1,1,1);
}
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture1, baseColor, MaterialSrg::m_wrinkle_baseColor_texture1, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.r);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture2, baseColor, MaterialSrg::m_wrinkle_baseColor_texture2, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.g);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture3, baseColor, MaterialSrg::m_wrinkle_baseColor_texture3, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.b);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture4, baseColor, MaterialSrg::m_wrinkle_baseColor_texture4, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.a);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture1, baseColor, MaterialSrg::m_wrinkle_baseColor_texture1, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.r);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture2, baseColor, MaterialSrg::m_wrinkle_baseColor_texture2, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.g);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture3, baseColor, MaterialSrg::m_wrinkle_baseColor_texture3, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.b);
baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture4, baseColor, MaterialSrg::m_wrinkle_baseColor_texture4, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.a);
}
@@ -283,13 +298,13 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
baseColor = ApplyTextureOverlay(o_detail_baseColor_useTexture, baseColor, MaterialSrg::m_detail_baseColor_texture, MaterialSrg::m_sampler, IN.m_detailUv, detailLayerBaseColorFactor);
if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues && o_blendMask_isBound)
if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues)
{
// Overlay debug colors to highlight the different blend weights coming from the vertex color stream.
if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_blendMask.r); }
if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_blendMask.g); }
if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_blendMask.b); }
if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_blendMask.a); }
if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_wrinkleBlendFactors.r); }
if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_wrinkleBlendFactors.g); }
if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_wrinkleBlendFactors.b); }
if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_wrinkleBlendFactors.a); }
}
// ------- Specular -------
@@ -987,15 +987,6 @@
{
"file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
"tag": "SkinnedMeshMotionVector"
},
// Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency
{
"file": "Shaders/Depth/DepthPassTransparentMin.shader",
"tag": "DepthPassTransparentMin"
},
{
"file": "Shaders/Depth/DepthPassTransparentMax.shader",
"tag": "DepthPassTransparentMax"
}
],
"functors": [
@@ -1199,6 +1199,14 @@
"file": "./StandardPBR_ForwardPass_EDS.shader",
"tag": "ForwardPass_EDS"
},
{
"file": "./StandardPBR_LowEndForward.shader",
"tag": "LowEndForward"
},
{
"file": "./StandardPBR_LowEndForward_EDS.shader",
"tag": "LowEndForward_EDS"
},
{
"file": "Shaders/Shadow/Shadowmap.shader",
"tag": "Shadowmap"
@@ -1289,10 +1297,6 @@
"textureProperty": "baseColor.textureMap",
"useTextureProperty": "baseColor.useTexture",
"dependentProperties": ["baseColor.textureMapUv", "baseColor.textureBlendMode"],
"shaderTags": [
"ForwardPass",
"ForwardPass_EDS"
],
"shaderOption": "o_baseColor_useTexture"
}
},
@@ -1302,10 +1306,6 @@
"textureProperty": "metallic.textureMap",
"useTextureProperty": "metallic.useTexture",
"dependentProperties": ["metallic.textureMapUv"],
"shaderTags": [
"ForwardPass",
"ForwardPass_EDS"
],
"shaderOption": "o_metallic_useTexture"
}
},
@@ -1315,10 +1315,6 @@
"textureProperty": "specularF0.textureMap",
"useTextureProperty": "specularF0.useTexture",
"dependentProperties": ["specularF0.textureMapUv"],
"shaderTags": [
"ForwardPass",
"ForwardPass_EDS"
],
"shaderOption": "o_specularF0_useTexture"
}
},
@@ -1328,10 +1324,6 @@
"textureProperty": "normal.textureMap",
"useTextureProperty": "normal.useTexture",
"dependentProperties": ["normal.textureMapUv", "normal.factor", "normal.flipX", "normal.flipY"],
"shaderTags": [
"ForwardPass",
"ForwardPass_EDS"
],
"shaderOption": "o_normal_useTexture"
}
},
@@ -10,6 +10,8 @@
*
*/
#include "Atom/Features/ShaderQualityOptions.azsli"
#include "StandardPBR_Common.azsli"
// SRGs
@@ -317,13 +319,18 @@ ForwardPassOutputWithDepth StandardPbr_ForwardPassPS(VSOutput IN, bool isFrontFa
PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth);
#ifdef UNIFIED_FORWARD_OUTPUT
OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb;
OUT.m_color.a = lightingOutput.m_diffuseColor.a;
OUT.m_depth = depth;
#else
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_specularColor = lightingOutput.m_specularColor;
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_depth = depth;
#endif
return OUT;
}
@@ -335,12 +342,16 @@ ForwardPassOutput StandardPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace :
PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth);
#ifdef UNIFIED_FORWARD_OUTPUT
OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb;
OUT.m_color.a = lightingOutput.m_diffuseColor.a;
#else
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_specularColor = lightingOutput.m_specularColor;
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
#endif
return OUT;
}
@@ -0,0 +1,17 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// NOTE: This file is a temporary workaround until .shader files can #define macros for their .azsl files
#define QUALITY_LOW_END 1
#include "StandardPBR_ForwardPass.azsl"
@@ -0,0 +1,59 @@
{
// Note: "LowEnd" shaders are for supporting the low end pipeline
// These shaders can be safely added to materials without incurring additional runtime draw
// items as draw items for shaders are only created if the scene has a pass with a matching
// DrawListTag. If your pipeline doesn't have a "lowEndForward" DrawListTag, no draw items
// for this shader will be created.
"Source" : "./StandardPBR_LowEndForward.azsl",
"DepthStencilState" :
{
"Depth" :
{
"Enable" : true,
"CompareFunc" : "GreaterEqual"
},
"Stencil" :
{
"Enable" : true,
"ReadMask" : "0x00",
"WriteMask" : "0xFF",
"FrontFace" :
{
"Func" : "Always",
"DepthFailOp" : "Keep",
"FailOp" : "Keep",
"PassOp" : "Replace"
},
"BackFace" :
{
"Func" : "Always",
"DepthFailOp" : "Keep",
"FailOp" : "Keep",
"PassOp" : "Replace"
}
}
},
"CompilerHints" : {
"DisableOptimizations" : false
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "StandardPbr_ForwardPassVS",
"type": "Vertex"
},
{
"name": "StandardPbr_ForwardPassPS",
"type": "Fragment"
}
]
},
"DrawList" : "lowEndForward"
}
@@ -0,0 +1,59 @@
{
// Note: "LowEnd" shaders are for supporting the low end pipeline
// These shaders can be safely added to materials without incurring additional runtime draw
// items as draw items for shaders are only created if the scene has a pass with a matching
// DrawListTag. If your pipeline doesn't have a "lowEndForward" DrawListTag, no draw items
// for this shader will be created.
"Source" : "./StandardPBR_LowEndForward.azsl",
"DepthStencilState" :
{
"Depth" :
{
"Enable" : true,
"CompareFunc" : "GreaterEqual"
},
"Stencil" :
{
"Enable" : true,
"ReadMask" : "0x00",
"WriteMask" : "0xFF",
"FrontFace" :
{
"Func" : "Always",
"DepthFailOp" : "Keep",
"FailOp" : "Keep",
"PassOp" : "Replace"
},
"BackFace" :
{
"Func" : "Always",
"DepthFailOp" : "Keep",
"FailOp" : "Keep",
"PassOp" : "Replace"
}
}
},
"CompilerHints" : {
"DisableOptimizations" : false
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "StandardPbr_ForwardPassVS",
"type": "Vertex"
},
{
"name": "StandardPbr_ForwardPassPS_EDS",
"type": "Fragment"
}
]
},
"DrawList" : "lowEndForward"
}
@@ -29,26 +29,33 @@ function Process(context)
local depthPass = context:GetShaderByTag("DepthPass")
local shadowMap = context:GetShaderByTag("Shadowmap")
local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS")
local lowEndForwardEDS = context:GetShaderByTag("LowEndForward_EDS")
local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS")
local shadowMapWitPS = context:GetShaderByTag("Shadowmap_WithPS")
local forwardPass = context:GetShaderByTag("ForwardPass")
local lowEndForward = context:GetShaderByTag("LowEndForward")
if parallaxEnabled and parallaxPdoEnabled then
depthPass:SetEnabled(false)
shadowMap:SetEnabled(false)
forwardPassEDS:SetEnabled(false)
lowEndForwardEDS:SetEnabled(false)
depthPassWithPS:SetEnabled(true)
shadowMapWitPS:SetEnabled(true)
forwardPass:SetEnabled(true)
lowEndForward:SetEnabled(true)
else
depthPass:SetEnabled(opacityMode == OpacityMode_Opaque)
shadowMap:SetEnabled(opacityMode == OpacityMode_Opaque)
forwardPassEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
lowEndForwardEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
depthPassWithPS:SetEnabled(opacityMode == OpacityMode_Cutout)
shadowMapWitPS:SetEnabled(opacityMode == OpacityMode_Cutout)
forwardPass:SetEnabled(opacityMode == OpacityMode_Cutout)
lowEndForward:SetEnabled(opacityMode == OpacityMode_Cutout)
end
context:GetShaderByTag("DepthPassTransparentMin"):SetEnabled((opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
@@ -148,22 +148,6 @@
},
"LoadAction": "Clear"
}
},
{
"Name": "ScatterDistanceOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
@@ -238,19 +222,6 @@
"AssetRef": {
"FilePath": "Textures/BRDFTexture.attimage"
}
},
{
"Name": "ScatterDistanceImage",
"SizeSource": {
"Source": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
},
"ImageDescriptor": {
"Format": "R11G11B10_FLOAT",
"SharedQueueMask": "Graphics"
}
}
],
"Connections": [
@@ -295,13 +266,6 @@
"Pass": "This",
"Attachment": "BRDFTexture"
}
},
{
"LocalSlot": "ScatterDistanceOutput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "ScatterDistanceImage"
}
}
]
}
@@ -0,0 +1,146 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "LightAdaptationParentTemplate",
"PassClass": "ParentPass",
"Slots": [
// Inputs...
{
"Name": "LightingInput",
"SlotType": "Input"
},
// SwapChain here is only used to reference the frame height and format
{
"Name": "SwapChainOutput",
"SlotType": "InputOutput"
},
// Outputs...
{
"Name": "Output",
"SlotType": "Output"
},
// Debug Outputs...
{
"Name": "LuminanceMipChainOutput",
"SlotType": "Output"
}
],
"Connections": [
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "DisplayMapperPass",
"Attachment": "Output"
}
},
{
"LocalSlot": "LuminanceMipChainOutput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMipChain",
"Attachment": "MipChainInputOutput"
}
}
],
"PassRequests": [
{
"Name": "DownsampleLuminanceMinAvgMax",
"TemplateName": "DownsampleLuminanceMinAvgMaxCS",
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "LightingInput"
}
}
]
},
{
"Name": "DownsampleLuminanceMipChain",
"TemplateName": "DownsampleMipChainTemplate",
"Connections": [
{
"LocalSlot": "MipChainInputOutput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMinAvgMax",
"Attachment": "Output"
}
}
],
"PassData": {
"$type": "DownsampleMipChainPassData",
"ShaderAsset": {
"FilePath": "Shaders/PostProcessing/DownsampleMinAvgMaxCS.shader"
}
}
},
{
"Name": "EyeAdaptationPass",
"TemplateName": "EyeAdaptationTemplate",
"Enabled": false,
"Connections": [
{
"LocalSlot": "SceneLuminanceInput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMipChain",
"Attachment": "MipChainInputOutput"
}
}
]
},
{
"Name": "LookModificationTransformPass",
"TemplateName": "LookModificationTransformTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "LightingInput"
}
},
{
"LocalSlot": "EyeAdaptationDataInput",
"AttachmentRef": {
"Pass": "EyeAdaptationPass",
"Attachment": "EyeAdaptationDataInputOutput"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "DisplayMapperPass",
"TemplateName": "DisplayMapperTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "LookModificationTransformPass",
"Attachment": "Output"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
}
]
}
}
}
@@ -0,0 +1,133 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "LowEndForwardPassTemplate",
"PassClass": "RasterPass",
"Slots": [
// Inputs...
{
"Name": "BRDFTextureInput",
"ShaderInputName": "m_brdfMap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "DirectionalLightShadowmap",
"ShaderInputName": "m_directionalLightShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ExponentialShadowmapDirectional",
"ShaderInputName": "m_directionalLightExponentialShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ProjectedShadowmap",
"ShaderInputName": "m_projectedShadowmaps",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ExponentialShadowmapProjected",
"ShaderInputName": "m_projectedExponentialShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "TileLightData",
"SlotType": "Input",
"ShaderInputName": "m_tileLightData",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "LightListRemapped",
"SlotType": "Input",
"ShaderInputName": "m_lightListRemapped",
"ScopeAttachmentUsage": "Shader"
},
// Input/Outputs...
{
"Name": "DepthStencilInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "DepthStencil"
},
// Outputs...
{
"Name": "LightingOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
{
"Name": "LightingAttachment",
"SizeSource": {
"Source": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
},
"MultisampleSource": {
"Pass": "This",
"Attachment": "DepthStencilInputOutput"
},
"ImageDescriptor": {
"Format": "R16G16B16A16_FLOAT",
"SharedQueueMask": "Graphics"
}
},
{
"Name": "BRDFTexture",
"Lifetime": "Imported",
"AssetRef": {
"FilePath": "Textures/BRDFTexture.attimage"
}
}
],
"Connections": [
{
"LocalSlot": "LightingOutput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "LightingAttachment"
}
},
{
"LocalSlot": "BRDFTextureInput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "BRDFTexture"
}
}
]
}
}
}
@@ -0,0 +1,344 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "LowEndPipelineTemplate",
"PassClass": "ParentPass",
"Slots": [
{
"Name": "SwapChainOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
}
],
"PassRequests": [
{
"Name": "MorphTargetPass",
"TemplateName": "MorphTargetPassTemplate"
},
{
"Name": "SkinningPass",
"TemplateName": "SkinningPassTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshOutputStream",
"AttachmentRef": {
"Pass": "MorphTargetPass",
"Attachment": "MorphTargetDeltaOutput"
}
}
]
},
{
"Name": "DepthPrePass",
"TemplateName": "DepthMSAAParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "LightCullingPass",
"TemplateName": "LightCullingParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "DepthMSAA",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthMSAA"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "ShadowPass",
"TemplateName": "ShadowParentTemplate",
"Connections": [
{
"LocalSlot": "SkinnedMeshes",
"AttachmentRef": {
"Pass": "SkinningPass",
"Attachment": "SkinnedMeshOutputStream"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "ForwardPass",
"TemplateName": "LowEndForwardPassTemplate",
"Connections": [
// Inputs...
{
"LocalSlot": "DirectionalLightShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "ExponentialShadowmapDirectional",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ExponentialShadowmapProjected",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
},
// Input/Outputs...
{
"LocalSlot": "DepthStencilInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "DepthMSAA"
}
}
],
"PassData": {
"$type": "RasterPassData",
"DrawListTag": "lowEndForward",
"PipelineViewTag": "MainCamera",
"PassSrgAsset": {
"FilePath": "shaderlib/atom/features/pbr/forwardpasssrg.azsli:PassSrg"
}
}
},
{
"Name": "SkyBoxPass",
"TemplateName": "SkyBoxTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "SpecularInputOutput",
"AttachmentRef": {
"Pass": "ForwardPass",
"Attachment": "LightingOutput"
}
},
{
"LocalSlot": "SkyBoxDepth",
"AttachmentRef": {
"Pass": "ForwardPass",
"Attachment": "DepthStencilInputOutput"
}
}
]
},
{
"Name": "MSAAResolvePass",
"TemplateName": "MSAAResolveColorTemplate",
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "SkyBoxPass",
"Attachment": "SpecularInputOutput"
}
}
]
},
{
"Name": "TransparentPass",
"TemplateName": "TransparentParentTemplate",
"Connections": [
{
"LocalSlot": "DirectionalShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "DirectionalESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ProjectedESM",
"AttachmentRef": {
"Pass": "ShadowPass",
"Attachment": "ProjectedESM"
}
},
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "LightCullingPass",
"Attachment": "LightListRemapped"
}
},
{
"LocalSlot": "DepthStencil",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "MSAAResolvePass",
"Attachment": "Output"
}
}
]
},
{
"Name": "LightAdaptation",
"TemplateName": "LightAdaptationParentTemplate",
"Connections": [
{
"LocalSlot": "LightingInput",
"AttachmentRef": {
"Pass": "TransparentPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "AuxGeomPass",
"TemplateName": "AuxGeomPassTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "ColorInputOutput",
"AttachmentRef": {
"Pass": "LightAdaptation",
"Attachment": "Output"
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
],
"PassData": {
"$type": "RasterPassData",
"DrawListTag": "auxgeom",
"PipelineViewTag": "MainCamera"
}
},
{
"Name": "UIPass",
"TemplateName": "UIParentTemplate",
"Connections": [
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
"Pass": "AuxGeomPass",
"Attachment": "ColorInputOutput"
}
}
]
},
{
"Name": "CopyToSwapChain",
"TemplateName": "FullscreenCopyTemplate",
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "UIPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
}
]
}
}
}
@@ -305,7 +305,7 @@
},
{
"Name": "SkyBoxPass",
"TemplateName": "SkyBoxTemplate",
"TemplateName": "SkyBoxTwoOutputsTemplate",
"Enabled": true,
"Connections": [
{
@@ -92,6 +92,10 @@
"Name": "SkyBoxTemplate",
"Path": "Passes/SkyBox.pass"
},
{
"Name": "SkyBoxTwoOutputsTemplate",
"Path": "Passes/SkyBox_TwoOutputs.pass"
},
{
"Name": "UIPassTemplate",
"Path": "Passes/UI.pass"
@@ -483,6 +487,18 @@
{
"Name": "UIParentTemplate",
"Path": "Passes/UIParent.pass"
},
{
"Name": "LightAdaptationParentTemplate",
"Path": "Passes/LightAdaptationParent.pass"
},
{
"Name": "LowEndForwardPassTemplate",
"Path": "Passes/LowEndForward.pass"
},
{
"Name": "LowEndPipelineTemplate",
"Path": "Passes/LowEndPipeline.pass"
}
]
}
@@ -40,7 +40,7 @@
{
"LocalSlot": "Output",
"AttachmentRef": {
"Pass": "DisplayMapperPass",
"Pass": "LightAdaptation",
"Attachment": "Output"
}
},
@@ -54,8 +54,8 @@
{
"LocalSlot": "LuminanceMipChainOutput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMipChain",
"Attachment": "MipChainInputOutput"
"Pass": "LightAdaptation",
"Attachment": "LuminanceMipChainOutput"
}
}
],
@@ -115,94 +115,16 @@
}
]
},
// Everything before this point deals in raw lighting values
// ---------------------------------------------------------
// Everything after starts to map to values we see on screen
{
"Name": "DownsampleLuminanceMinAvgMax",
"TemplateName": "DownsampleLuminanceMinAvgMaxCS",
"Name": "LightAdaptation",
"TemplateName": "LightAdaptationParentTemplate",
"Connections": [
{
"LocalSlot": "Input",
"LocalSlot": "LightingInput",
"AttachmentRef": {
"Pass": "BloomPass",
"Attachment": "InputOutput"
}
}
]
},
{
"Name": "DownsampleLuminanceMipChain",
"TemplateName": "DownsampleMipChainTemplate",
"Connections": [
{
"LocalSlot": "MipChainInputOutput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMinAvgMax",
"Attachment": "Output"
}
}
],
"PassData": {
"$type": "DownsampleMipChainPassData",
"ShaderAsset": {
"FilePath": "Shaders/PostProcessing/DownsampleMinAvgMaxCS.shader"
}
}
},
{
"Name": "EyeAdaptationPass",
"TemplateName": "EyeAdaptationTemplate",
"Enabled": false,
"Connections": [
{
"LocalSlot": "SceneLuminanceInput",
"AttachmentRef": {
"Pass": "DownsampleLuminanceMipChain",
"Attachment": "MipChainInputOutput"
}
}
]
},
{
"Name": "LookModificationTransformPass",
"TemplateName": "LookModificationTransformTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "BloomPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "EyeAdaptationDataInput",
"AttachmentRef": {
"Pass": "EyeAdaptationPass",
"Attachment": "EyeAdaptationDataInputOutput"
}
},
{
"LocalSlot": "SwapChainOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
}
]
},
{
"Name": "DisplayMapperPass",
"TemplateName": "DisplayMapperTemplate",
"Enabled": true,
"Connections": [
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "LookModificationTransformPass",
"Attachment": "Output"
}
},
{
"LocalSlot": "SwapChainOutput",
@@ -12,11 +12,6 @@
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "ReflectionInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "SkyBoxDepth",
"SlotType": "InputOutput",
@@ -0,0 +1,43 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "SkyBoxTwoOutputsTemplate",
"PassClass": "FullScreenTriangle",
"Slots": [
{
"Name": "SpecularInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "ReflectionInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "SkyBoxDepth",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "DepthStencil"
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "shaders/skybox/skybox_twooutputs.shader"
},
"PipelineViewTag": "MainCamera",
"ShaderDataMappings": {
"FloatMappings": [
{
"Name": "m_sunIntensityMultiplier",
"Value": 1.0
}
]
}
}
}
}
}
@@ -31,6 +31,16 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId);
}
//[GFX TODO][ATOM-15280] Move wrinkle mask data from the default object srg into something specific to the Skin shader
uint m_wrinkle_mask_count;
float4 m_wrinkle_mask_weights[4];
Texture2D m_wrinkle_masks[16];
float GetWrinkleMaskWeight(uint index)
{
return m_wrinkle_mask_weights[index / 4][index % 4];
}
//! Reflection Probe (smallest probe volume that overlaps the object position)
struct ReflectionProbeData
{
@@ -10,6 +10,21 @@
*
*/
#ifdef UNIFIED_FORWARD_OUTPUT
struct ForwardPassOutput
{
float4 m_color : SV_Target0;
};
struct ForwardPassOutputWithDepth
{
float4 m_color : SV_Target0;
float m_depth : SV_Depth;
};
#else
struct ForwardPassOutput
{
float4 m_diffuseColor : SV_Target0; //!< RGB = Diffuse Lighting, A = Blend Alpha (for blended surfaces) OR A = special encoding of surfaceScatteringFactor, m_subsurfaceScatteringQuality, o_enableSubsurfaceScattering
@@ -30,3 +45,5 @@ struct ForwardPassOutputWithDepth
float4 m_normal : SV_Target4;
float m_depth : SV_Depth;
};
#endif
@@ -12,38 +12,39 @@
#pragma once
// --- Static Options Available ---
// FORCE_IBL_IN_FORWARD_PASS - forces IBL lighting to be run in the forward pass, used in pipelines that don't have a reflection pass
#include <Atom/Features/PBR/LightingOptions.azsli>
#include <Atom/RPI/Math.azsli>
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
void ApplyIblDiffuse(
float3 GetIblDiffuse(
float3 normal,
float3 albedo,
float3 diffuseResponse,
out float3 outDiffuse)
float3 diffuseResponse)
{
float3 irradianceDir = MultiplyVectorQuaternion(normal, SceneSrg::m_iblOrientation);
float3 diffuseSample = SceneSrg::m_diffuseEnvMap.Sample(SceneSrg::m_samplerEnv, GetCubemapCoords(irradianceDir)).rgb;
outDiffuse = diffuseResponse * albedo * diffuseSample;
return diffuseResponse * albedo * diffuseSample;
}
void ApplyIblSpecular(
float3 GetIblSpecular(
float3 position,
float3 normal,
float3 specularF0,
float roughnessLinear,
float3 dirToCamera,
float2 brdf,
out float3 outSpecular)
float2 brdf)
{
float3 reflectDir = reflect(-dirToCamera, normal);
reflectDir = MultiplyVectorQuaternion(reflectDir, SceneSrg::m_iblOrientation);
// global
outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
float3 outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
outSpecular *= (specularF0 * brdf.x + brdf.y);
// reflection probe
@@ -72,86 +73,55 @@ void ApplyIblSpecular(
outSpecular = lerp(outSpecular, probeSpecular, blendAmount);
}
return outSpecular;
}
void ApplyIBL(Surface surface, inout LightingData lightingData)
{
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
#ifdef FORCE_IBL_IN_FORWARD_PASS
bool useDiffuseIbl = true;
bool useSpecularIbl = true;
bool useIbl = o_enableIBL;
#else
bool isTransparent = (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent);
bool useDiffuseIbl = isTransparent;
bool useSpecularIbl = (isTransparent || o_meshUseForwardPassIBLSpecular || o_materialUseForwardPassIBLSpecular);
bool useIbl = o_enableIBL && (useDiffuseIbl || useSpecularIbl);
#endif
if(useIbl)
{
// transparencies currently require IBL in the forward pass
if (o_enableIBL)
float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
if(useDiffuseIbl)
{
float3 iblDiffuse = 0.0f;
ApplyIblDiffuse(
surface.normal,
surface.albedo,
lightingData.diffuseResponse,
iblDiffuse);
float3 iblSpecular = 0.0f;
ApplyIblSpecular(
surface.position,
surface.normal,
surface.specularF0,
surface.roughnessLinear,
lightingData.dirToCamera,
lightingData.brdf,
iblSpecular);
// Adjust IBL lighting by exposure.
float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse);
lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.diffuseAmbientOcclusion);
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
}
}
else if (o_meshUseForwardPassIBLSpecular || o_materialUseForwardPassIBLSpecular)
{
if (o_enableIBL)
{
float3 iblSpecular = 0.0f;
ApplyIblSpecular(
surface.position,
surface.normal,
surface.specularF0,
surface.roughnessLinear,
lightingData.dirToCamera,
lightingData.brdf,
iblSpecular);
if(useSpecularIbl)
{
float3 iblSpecular = GetIblSpecular(surface.position, surface.normal, surface.specularF0, surface.roughnessLinear, lightingData.dirToCamera, lightingData.brdf);
iblSpecular *= lightingData.multiScatterCompensation;
if (o_clearCoat_feature_enabled)
if (o_clearCoat_feature_enabled && surface.clearCoat.factor > 0.0f)
{
if (surface.clearCoat.factor > 0.0f)
{
float clearCoatNdotV = saturate(dot(surface.clearCoat.normal, lightingData.dirToCamera));
clearCoatNdotV = max(clearCoatNdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
float2 clearCoatBrdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(surface.clearCoat.roughness, clearCoatNdotV)).rg;
float clearCoatNdotV = saturate(dot(surface.clearCoat.normal, lightingData.dirToCamera));
clearCoatNdotV = max(clearCoatNdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
float2 clearCoatBrdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(surface.clearCoat.roughness, clearCoatNdotV)).rg;
// clear coat uses fixed IOR = 1.5 represents polyurethane which is the most common material for gloss clear coat
// coat layer assumed to be dielectric thus don't need multiple scattering compensation
float3 clearCoatSpecularF0 = float3(0.04f, 0.04f, 0.04f);
float3 clearCoatIblSpecular = 0.0f;
// clear coat uses fixed IOR = 1.5 represents polyurethane which is the most common material for gloss clear coat
// coat layer assumed to be dielectric thus don't need multiple scattering compensation
float3 clearCoatSpecularF0 = float3(0.04f, 0.04f, 0.04f);
float3 clearCoatIblSpecular = GetIblSpecular(surface.position, surface.clearCoat.normal, clearCoatSpecularF0, surface.clearCoat.roughness, lightingData.dirToCamera, clearCoatBrdf);
ApplyIblSpecular(
surface.position,
surface.clearCoat.normal,
clearCoatSpecularF0,
surface.clearCoat.roughness,
lightingData.dirToCamera,
clearCoatBrdf,
clearCoatIblSpecular);
clearCoatIblSpecular *= surface.clearCoat.factor;
clearCoatIblSpecular *= surface.clearCoat.factor;
// attenuate base layer energy
float3 clearCoatResponse = FresnelSchlickWithRoughness(clearCoatNdotV, clearCoatSpecularF0, surface.clearCoat.roughness) * surface.clearCoat.factor;
iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular;
}
// attenuate base layer energy
float3 clearCoatResponse = FresnelSchlickWithRoughness(clearCoatNdotV, clearCoatSpecularF0, surface.clearCoat.roughness) * surface.clearCoat.factor;
iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular;
}
float iblExposureFactor = pow(2.0f, SceneSrg::m_iblExposure);
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
}
}
@@ -0,0 +1,26 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
// This file translates quality option macros like QUALITY_LOW_END to their relevant settings
#ifdef QUALITY_LOW_END
// Unifies the forward output into a single lighting buffer instead of splitting it into a GBuffer
#define UNIFIED_FORWARD_OUTPUT 1
// Forces IBL lighting to be executed in the forward pass instead of subsequent refleciton passes
#define FORCE_IBL_IN_FORWARD_PASS 1
#endif
@@ -10,6 +10,9 @@
*
*/
// --- Static Options Available ---
// SKYBOX_TWO_OUTPUTS - Skybox renders to two rendertargets instead of one (SkyBox_TwoOutputs.pass writes to specular and reflection targets)
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertexUtil.azsli>
#include <Atom/Features/MatrixUtility.azsli>
@@ -102,7 +105,9 @@ float3 GetCubemapCoords(float3 original)
struct PSOutput
{
float4 m_specular : SV_Target0;
#ifdef SKYBOX_TWO_OUTPUTS
float4 m_reflection : SV_Target1;
#endif
};
PSOutput MainPS(VSOutput input)
@@ -163,6 +168,8 @@ PSOutput MainPS(VSOutput input)
PSOutput OUT;
OUT.m_specular = float4(color, 1.0);
#ifdef SKYBOX_TWO_OUTPUTS
OUT.m_reflection = float4(color, 1.0);
#endif
return OUT;
}
@@ -0,0 +1,17 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// NOTE: This file is a temporary workaround until .shader files can #define macros for their .azsl files
#define SKYBOX_TWO_OUTPUTS
#include "SkyBox.azsl"
@@ -0,0 +1,22 @@
{
"Source" : "SkyBox_TwoOutputs",
"DepthStencilState" : {
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -38,6 +38,7 @@ set(FILES
Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader
Materials/Types/StandardMultilayerPBR_Parallax.lua
Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua
Materials/Types/StandardMultilayerPBR_ShaderEnable.lua
Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl
Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.shader
Materials/Types/StandardPBR.materialtype
@@ -52,6 +53,9 @@ set(FILES
Materials/Types/StandardPBR_ForwardPass_EDS.shader
Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua
Materials/Types/StandardPBR_HandleOpacityMode.lua
Materials/Types/StandardPBR_LowEndForward.azsl
Materials/Types/StandardPBR_LowEndForward.shader
Materials/Types/StandardPBR_LowEndForward_EDS.shader
Materials/Types/StandardPBR_ParallaxState.lua
Materials/Types/StandardPBR_Roughness.lua
Materials/Types/StandardPBR_ShaderEnable.lua
@@ -116,6 +120,7 @@ set(FILES
Passes/DiffuseProbeGridBlendDistance.pass
Passes/DiffuseProbeGridBlendIrradiance.pass
Passes/DiffuseProbeGridBorderUpdate.pass
Passes/DiffuseProbeGridClassification.pass
Passes/DiffuseProbeGridDownsample.pass
Passes/DiffuseProbeGridRayTracing.pass
Passes/DiffuseProbeGridRelocation.pass
@@ -144,6 +149,7 @@ set(FILES
Passes/FullscreenCopy.pass
Passes/FullscreenOutputOnly.pass
Passes/ImGui.pass
Passes/LightAdaptationParent.pass
Passes/LightCulling.pass
Passes/LightCullingHeatmap.pass
Passes/LightCullingParent.pass
@@ -152,6 +158,8 @@ set(FILES
Passes/LightCullingTilePrepareMSAA.pass
Passes/LookModificationComposite.pass
Passes/LookModificationTransform.pass
Passes/LowEndForward.pass
Passes/LowEndPipeline.pass
Passes/LuminanceHeatmap.pass
Passes/LuminanceHistogramGenerator.pass
Passes/MainPipeline.pass
@@ -179,13 +187,16 @@ set(FILES
Passes/ReflectionScreenSpace.pass
Passes/ReflectionScreenSpaceBlur.pass
Passes/ReflectionScreenSpaceBlurHorizontal.pass
Passes/ReflectionScreenSpaceBlurMobile.pass
Passes/ReflectionScreenSpaceBlurVertical.pass
Passes/ReflectionScreenSpaceComposite.pass
Passes/ReflectionScreenSpaceMobile.pass
Passes/ReflectionScreenSpaceTrace.pass
Passes/Reflections_nomsaa.pass
Passes/ShadowParent.pass
Passes/Skinning.pass
Passes/SkyBox.pass
Passes/SkyBox_TwoOutputs.pass
Passes/SMAA1xApplyLinearHDRColor.pass
Passes/SMAA1xApplyPerceptualColor.pass
Passes/SMAABlendingWeightCalculation.pass
@@ -205,6 +216,7 @@ set(FILES
ShaderLib/Atom/Features/IndirectRendering.azsli
ShaderLib/Atom/Features/MatrixUtility.azsli
ShaderLib/Atom/Features/ParallaxMapping.azsli
ShaderLib/Atom/Features/ShaderQualityOptions.azsli
ShaderLib/Atom/Features/SphericalHarmonicsUtility.azsli
ShaderLib/Atom/Features/SrgSemantics.azsli
ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli
@@ -272,6 +284,7 @@ set(FILES
ShaderLib/Atom/Features/PostProcessing/GlyphData.azsli
ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli
ShaderLib/Atom/Features/PostProcessing/PostProcessUtil.azsli
ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli
ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli
ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli
ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
@@ -471,4 +484,6 @@ set(FILES
Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli
Shaders/SkyBox/SkyBox.azsl
Shaders/SkyBox/SkyBox.shader
Shaders/SkyBox/SkyBox_TwoOutputs.azsl
Shaders/SkyBox/SkyBox_TwoOutputs.shader
)
@@ -148,6 +148,8 @@ namespace AZ
Data::Instance<RPI::Model> GetModel(const MeshHandle& meshHandle) const override;
Data::Asset<RPI::ModelAsset> GetModelAsset(const MeshHandle& meshHandle) const override;
Data::Instance<RPI::ShaderResourceGroup> GetObjectSrg(const MeshHandle& meshHandle) const override;
void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material) override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override;
const MaterialAssignmentMap& GetMaterialAssignmentMap(const MeshHandle& meshHandle) const override;
@@ -61,6 +61,14 @@ namespace AZ
virtual Data::Instance<RPI::Model> GetModel(const MeshHandle& meshHandle) const = 0;
//! Gets the underlying RPI::ModelAsset for a meshHandle.
virtual Data::Asset<RPI::ModelAsset> GetModelAsset(const MeshHandle& meshHandle) const = 0;
//! Gets the ObjectSrg for a meshHandle.
//! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile,
//! instead of compiling the srg directly. This way, if the srg has already been queued for compile,
//! it will not be queued twice in the same frame. The ObjectSrg should not be updated during
//! Simulate, or it will create a race between updating the data and the call to Compile
virtual Data::Instance<RPI::ShaderResourceGroup> GetObjectSrg(const MeshHandle& meshHandle) const = 0;
//! Queues the object srg for compile.
virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0;
//! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId.
//! Note if there is already a material assignment map, this will replace the entire map with just a single material.
virtual void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material) = 0;
@@ -23,6 +23,8 @@ namespace UnitTest
MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&));
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr<AZ::RPI::Model>(const MeshHandle&));
MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset<AZ::RPI::ModelAsset>(const MeshHandle&));
MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr<AZ::RPI::ShaderResourceGroup>(const MeshHandle&));
MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
MOCK_METHOD3(SetTransform, void(const MeshHandle&, const AZ::Transform&, const AZ::Vector3&));
@@ -231,6 +231,19 @@ namespace AZ
return {};
}
Data::Instance<RPI::ShaderResourceGroup> MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const
{
return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr;
}
void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
{
if (meshHandle.IsValid())
{
meshHandle->m_objectSrgNeedsUpdate = true;
}
}
void MeshFeatureProcessor::SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material)
{
Render::MaterialAssignmentMap materials;
@@ -12,6 +12,7 @@
#include <MorphTargets/MorphTargetComputePass.h>
#include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
#include <Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@@ -38,6 +39,11 @@ namespace AZ
return m_shader;
}
void MorphTargetComputePass::SetFeatureProcessor(SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor)
{
m_skinnedMeshFeatureProcessor = skinnedMeshFeatureProcessor;
}
void MorphTargetComputePass::BuildAttachmentsInternal()
{
// The same buffer that skinning writes to is used to manage the computed vertex deltas that are passed from the
@@ -45,30 +51,16 @@ namespace AZ
AttachBufferToSlot(Name{ "MorphTargetDeltaOutput" }, SkinnedMeshOutputStreamManagerInterface::Get()->GetBuffer());
}
void MorphTargetComputePass::AddDispatchItem(const RHI::DispatchItem* dispatchItem)
{
AZ_Assert(dispatchItem != nullptr, "invalid dispatchItem");
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
//using an unordered_set here to prevent redundantly adding the same dispatchItem to the submission queue
//(i.e. if the same morph target exists in multiple views, it can call AddDispatchItem multiple times with the same item)
m_dispatches.insert(dispatchItem);
}
void MorphTargetComputePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
RHI::CommandList* commandList = context.GetCommandList();
SetSrgsForDispatch(commandList);
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
for (const RHI::DispatchItem* dispatchItem : m_dispatches)
if (m_skinnedMeshFeatureProcessor)
{
commandList->Submit(*dispatchItem);
}
RHI::CommandList* commandList = context.GetCommandList();
// Clear the dispatch items. They will need to be re-populated next frame
m_dispatches.clear();
SetSrgsForDispatch(commandList);
m_skinnedMeshFeatureProcessor->SubmitMorphTargetDispatchItems(commandList);
}
}
} // namespace Render
} // namespace AZ
@@ -18,6 +18,8 @@ namespace AZ
{
namespace Render
{
class SkinnedMeshFeatureProcessor;
//! The morph target compute pass submits dispatch items for morph targets. The dispatch items are cleared every frame, so it needs to be re-populated.
class MorphTargetComputePass
: public RPI::ComputePass
@@ -31,16 +33,14 @@ namespace AZ
static RPI::Ptr<MorphTargetComputePass> Create(const RPI::PassDescriptor& descriptor);
//! Thread-safe function for adding a dispatch item to the current frame.
void AddDispatchItem(const RHI::DispatchItem* dispatchItem);
Data::Instance<RPI::Shader> GetShader() const;
void SetFeatureProcessor(SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor);
private:
void BuildAttachmentsInternal() override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
AZStd::mutex m_mutex;
AZStd::unordered_set<const RHI::DispatchItem*> m_dispatches;
SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor = nullptr;
};
}
}
@@ -11,7 +11,7 @@
*/
#include <MorphTargets/MorphTargetDispatchItem.h>
#include <MorphTargets/MorphTargetComputePass.h>
#include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@@ -30,7 +30,7 @@ namespace AZ
MorphTargetDispatchItem::MorphTargetDispatchItem(
const AZStd::intrusive_ptr<MorphTargetInputBuffers> inputBuffers,
const MorphTargetMetaData& morphTargetMetaData,
RPI::Ptr<MorphTargetComputePass> morphTargetComputePass,
SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
MorphTargetInstanceMetaData morphInstanceMetaData,
float morphDeltaIntegerEncoding)
: m_inputBuffers(inputBuffers)
@@ -38,7 +38,7 @@ namespace AZ
, m_morphInstanceMetaData(morphInstanceMetaData)
, m_accumulatedDeltaIntegerEncoding(morphDeltaIntegerEncoding)
{
m_morphTargetShader = morphTargetComputePass->GetShader();
m_morphTargetShader = skinnedMeshFeatureProcessor->GetMorphTargetShader();
RPI::ShaderReloadNotificationBus::Handler::BusConnect(m_morphTargetShader->GetAssetId());
}
@@ -37,7 +37,7 @@ namespace AZ
namespace Render
{
class MorphTargetComputePass;
class SkinnedMeshFeatureProcessor;
//! Holds and manages an RHI DispatchItem for a specific morph target, and the resources that are needed to build and maintain it.
class MorphTargetDispatchItem
@@ -51,7 +51,7 @@ namespace AZ
explicit MorphTargetDispatchItem(
const AZStd::intrusive_ptr<MorphTargetInputBuffers> inputBuffers,
const MorphTargetMetaData& morphTargetMetaData,
RPI::Ptr<MorphTargetComputePass> morphTargetComputePass,
SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
MorphTargetInstanceMetaData morphInstanceMetaData,
float accumulatedDeltaRange
);
@@ -12,6 +12,7 @@
#include <SkinnedMesh/SkinnedMeshComputePass.h>
#include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
#include <Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@@ -22,11 +23,9 @@ namespace AZ
{
namespace Render
{
SkinnedMeshComputePass::SkinnedMeshComputePass(const RPI::PassDescriptor& descriptor)
: RPI::ComputePass(descriptor)
{
m_cachedShaderOptions.SetShader(m_shader);
}
RPI::Ptr<SkinnedMeshComputePass> SkinnedMeshComputePass::Create(const RPI::PassDescriptor& descriptor)
@@ -40,42 +39,30 @@ namespace AZ
return m_shader;
}
RPI::ShaderOptionGroup SkinnedMeshComputePass::CreateShaderOptionGroup(const SkinnedMeshShaderOptions shaderOptions, SkinnedMeshShaderOptionNotificationBus::Handler& shaderReinitializedHandler)
void SkinnedMeshComputePass::SetFeatureProcessor(SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor)
{
m_cachedShaderOptions.ConnectToShaderReinitializedEvent(shaderReinitializedHandler);
return m_cachedShaderOptions.CreateShaderOptionGroup(shaderOptions);
}
void SkinnedMeshComputePass::AddDispatchItem(const RHI::DispatchItem* dispatchItem)
{
AZ_Assert(dispatchItem != nullptr, "invalid dispatchItem");
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
//using an unordered_set here to prevent redundantly adding the same dispatchItem to the submission queue
//(i.e. if the same skinnedMesh exists in multiple views, it can call AddDispatchItem multiple times with the same item)
m_dispatches.insert(dispatchItem);
m_skinnedMeshFeatureProcessor = skinnedMeshFeatureProcessor;
}
void SkinnedMeshComputePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
RHI::CommandList* commandList = context.GetCommandList();
SetSrgsForDispatch(commandList);
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
for (const RHI::DispatchItem* dispatchItem : m_dispatches)
if (m_skinnedMeshFeatureProcessor)
{
commandList->Submit(*dispatchItem);
}
RHI::CommandList* commandList = context.GetCommandList();
// Clear the dispatch items. They will need to be re-populated next frame
m_dispatches.clear();
SetSrgsForDispatch(commandList);
m_skinnedMeshFeatureProcessor->SubmitSkinningDispatchItems(commandList);
}
}
void SkinnedMeshComputePass::OnShaderReinitialized(const RPI::Shader& shader)
{
ComputePass::OnShaderReinitialized(shader);
m_cachedShaderOptions.SetShader(m_shader);
if (m_skinnedMeshFeatureProcessor)
{
m_skinnedMeshFeatureProcessor->OnSkinningShaderReinitialized(m_shader);
}
}
void SkinnedMeshComputePass::OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId&, RPI::ShaderVariantStableId)
@@ -20,6 +20,8 @@ namespace AZ
{
namespace Render
{
class SkinnedMeshFeatureProcessor;
//! The skinned mesh compute pass submits dispatch items for skinning. The dispatch items are cleared every frame, so it needs to be re-populated.
class SkinnedMeshComputePass
: public RPI::ComputePass
@@ -33,10 +35,9 @@ namespace AZ
static RPI::Ptr<SkinnedMeshComputePass> Create(const RPI::PassDescriptor& descriptor);
//! Thread-safe function for adding a dispatch item to the current frame.
void AddDispatchItem(const RHI::DispatchItem* dispatchItem);
Data::Instance<RPI::Shader> GetShader() const;
RPI::ShaderOptionGroup CreateShaderOptionGroup(const SkinnedMeshShaderOptions shaderOptions, SkinnedMeshShaderOptionNotificationBus::Handler& shaderReinitializedHandler);
void SetFeatureProcessor(SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor);
private:
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
@@ -45,9 +46,7 @@ namespace AZ
void OnShaderReinitialized(const RPI::Shader& shader) override;
void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override;
AZStd::mutex m_mutex;
AZStd::unordered_set<const RHI::DispatchItem*> m_dispatches;
CachedSkinnedMeshShaderOptions m_cachedShaderOptions;
SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor = nullptr;
};
}
}
@@ -12,7 +12,7 @@
#include <SkinnedMesh/SkinnedMeshDispatchItem.h>
#include <SkinnedMesh/SkinnedMeshOutputStreamManager.h>
#include <SkinnedMesh/SkinnedMeshComputePass.h>
#include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@@ -34,7 +34,7 @@ namespace AZ
size_t lodIndex,
Data::Instance<RPI::Buffer> boneTransforms,
const SkinnedMeshShaderOptions& shaderOptions,
RPI::Ptr<SkinnedMeshComputePass> skinnedMeshComputePass,
SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
MorphTargetInstanceMetaData morphTargetInstanceMetaData,
float morphTargetDeltaIntegerEncoding)
: m_inputBuffers(inputBuffers)
@@ -45,7 +45,7 @@ namespace AZ
, m_morphTargetInstanceMetaData(morphTargetInstanceMetaData)
, m_morphTargetDeltaIntegerEncoding(morphTargetDeltaIntegerEncoding)
{
m_skinningShader = skinnedMeshComputePass->GetShader();
m_skinningShader = skinnedMeshFeatureProcessor->GetSkinningShader();
// Shader options are generally set per-skinned mesh instance, but morph targets may only exist on some lods. Override the option for applying morph targets here
if (m_morphTargetInstanceMetaData.m_accumulatedPositionDeltaOffsetInBytes != MorphTargetConstants::s_invalidDeltaOffset)
@@ -58,7 +58,7 @@ namespace AZ
}
// CreateShaderOptionGroup will also connect to the SkinnedMeshShaderOptionNotificationBus
m_shaderOptionGroup = skinnedMeshComputePass->CreateShaderOptionGroup(m_shaderOptions, *this);
m_shaderOptionGroup = skinnedMeshFeatureProcessor->CreateSkinningShaderOptionGroup(m_shaderOptions, *this);
}
SkinnedMeshDispatchItem::~SkinnedMeshDispatchItem()
@@ -38,7 +38,7 @@ namespace AZ
namespace Render
{
class SkinnedMeshComputePass;
class SkinnedMeshFeatureProcessor;
//! Holds and manages an RHI DispatchItem for a specific skinned mesh, and the resources that are needed to build and maintain it.
class SkinnedMeshDispatchItem
@@ -55,7 +55,7 @@ namespace AZ
size_t lodIndex,
Data::Instance<RPI::Buffer> skinningMatrices,
const SkinnedMeshShaderOptions& shaderOptions,
RPI::Ptr<SkinnedMeshComputePass> skinnedMeshComputePass,
SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
MorphTargetInstanceMetaData morphTargetInstanceMetaData,
float morphTargetDeltaIntegerEncoding
);
@@ -24,8 +24,10 @@
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RHI/CpuProfiler.h>
#include <Atom/RHI/CommandList.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Jobs/JobCompletion.h>
@@ -69,26 +71,11 @@ namespace AZ
}
void SkinnedMeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
AZ_ATOM_PROFILE_FUNCTION("SkinnedMesh", "SkinnedMeshFeatureProcessor: Simulate");
AZ_UNUSED(packet);
SkinnedMeshFeatureProcessorNotificationBus::Broadcast(&SkinnedMeshFeatureProcessorNotificationBus::Events::OnUpdateSkinningMatrices);
}
void SkinnedMeshFeatureProcessor::Render(const FeatureProcessor::RenderPacket& packet)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
AZ_ATOM_PROFILE_FUNCTION("SkinnedMesh", "SkinnedMeshFeatureProcessor: Render");
if (!m_skinningPass)
{
return;
}
#if 0 //[GFX_TODO][ATOM-13564] Temporarily disable skinning culling until we figure out how to hook up visibility & lod selection with skinning:
//Setup the culling workgroup (it will be re-used for each view)
{
@@ -132,7 +119,7 @@ namespace AZ
//Dispatch the workgroup to each view
for (const RPI::ViewPtr& viewPtr : packet.m_views)
{
Job *processWorkgroupJob = AZ::CreateJobFunction(
Job* processWorkgroupJob = AZ::CreateJobFunction(
[this, cullingSystem, viewPtr](AZ::Job& thisJob)
{
AZ_PROFILE_SCOPE_DYNAMIC(Debug::ProfileCategory::AzRender, "skinningMeshFP processWorkgroupJob - View: %s", viewPtr->GetName().GetCStr());
@@ -167,7 +154,16 @@ namespace AZ
float maxScreenPercentage(lod.m_range.m_max);
if (approxScreenPercentage >= minScreenPercentage && approxScreenPercentage <= maxScreenPercentage)
{
m_skinningPass->AddDispatchItem(&renderProxy->m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
AZStd::lock_guard lock(m_dispatchItemMutex);
m_skinningDispatches.insert(&renderProxy->m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy->m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++)
{
const MorphTargetDispatchItem* dispatchItem = renderProxy->m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get();
if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon)
{
m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem());
}
}
}
}
}
@@ -232,13 +228,14 @@ namespace AZ
//Note that this supports overlapping lod ranges (to support cross-fading lods, for example)
if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax)
{
m_skinningPass->AddDispatchItem(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
AZStd::lock_guard lock(m_dispatchItemMutex);
m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++)
{
const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get();
if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon)
{
m_morphTargetPass->AddDispatchItem(&dispatchItem->GetRHIDispatchItem());
m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem());
}
}
}
@@ -248,29 +245,32 @@ namespace AZ
#endif
}
void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded([[maybe_unused]] RPI::RenderPipelinePtr pipeline)
void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
{
InitSkinningAndMorphPass();
InitSkinningAndMorphPass(pipeline->GetRootPass());
}
void SkinnedMeshFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* pipeline)
void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
{
InitSkinningAndMorphPass();
}
void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline)
{
InitSkinningAndMorphPass();
InitSkinningAndMorphPass(renderPipeline->GetRootPass());
}
void SkinnedMeshFeatureProcessor::OnBeginPrepareRender()
{
m_renderProxiesChecker.soft_lock();
SkinnedMeshFeatureProcessorNotificationBus::Broadcast(&SkinnedMeshFeatureProcessorNotificationBus::Events::OnUpdateSkinningMatrices);
}
void SkinnedMeshFeatureProcessor::OnEndPrepareRender()
void SkinnedMeshFeatureProcessor::OnRenderEnd()
{
m_renderProxiesChecker.soft_unlock();
// Clear any dispatch items that were added but never submitted
// in case there were no passes that submitted this frame
// because they execute at a lower frequency
m_skinningDispatches.clear();
m_morphTargetDispatches.clear();
}
SkinnedMeshRenderProxyHandle SkinnedMeshFeatureProcessor::AcquireRenderProxy(const SkinnedMeshRenderProxyDesc& desc)
@@ -295,61 +295,73 @@ namespace AZ
return false;
}
void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass()
void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass)
{
m_skinningPass = nullptr; //reset it to null, just in case it fails to load the assets properly
m_morphTargetPass = nullptr;
RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get();
if (passSystem->HasPassesForTemplateName(AZ::Name{ "SkinningPassTemplate" }))
RPI::Ptr<RPI::Pass> skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" });
if (skinningPass)
{
auto& skinningPasses = passSystem->GetPassesForTemplateName(AZ::Name{ "SkinningPassTemplate" });
SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast<SkinnedMeshComputePass*>(skinningPass.get());
skinnedMeshComputePass->SetFeatureProcessor(this);
// For now, assume one skinning pass
if (!skinningPasses.empty() && skinningPasses[0])
// There may be multiple skinning passes in the scene due to multiple pipelines, but there is only one skinning shader
m_skinningShader = skinnedMeshComputePass->GetShader();
if (!m_skinningShader)
{
m_skinningPass = static_cast<SkinnedMeshComputePass*>(skinningPasses[0]);
const Data::Instance<RPI::Shader> shader = m_skinningPass->GetShader();
if (!shader)
{
AZ_Error(s_featureProcessorName, false, "Failed to get skinning pass shader. It may need to finish processing.");
}
AZ_Error(s_featureProcessorName, false, "Failed to get skinning pass shader. It may need to finish processing.");
}
else
{
AZ_Error(s_featureProcessorName, false, "\"SkinningPassTemplate\" does not have any valid passes. Check your game project's .pass assets.");
m_cachedSkinningShaderOptions.SetShader(m_skinningShader);
}
}
else
{
AZ_Error(s_featureProcessorName, false, "Failed to find passes for \"SkinningPassTemplate\". Check your game project's .pass assets.");
}
if (passSystem->HasPassesForTemplateName(AZ::Name{ "MorphTargetPassTemplate" }))
RPI::Ptr<RPI::Pass> morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" });
if (morphTargetPass)
{
auto& morphTargetPasses = passSystem->GetPassesForTemplateName(AZ::Name{ "MorphTargetPassTemplate" });
MorphTargetComputePass* morphTargetComputePass = azdynamic_cast<MorphTargetComputePass*>(morphTargetPass.get());
morphTargetComputePass->SetFeatureProcessor(this);
// For now, assume one skinning pass
if (!morphTargetPasses.empty() && morphTargetPasses[0])
// There may be multiple morph target passes in the scene due to multiple pipelines, but there is only one morph target shader
m_morphTargetShader = morphTargetComputePass->GetShader();
if (!m_morphTargetShader)
{
m_morphTargetPass = static_cast<MorphTargetComputePass*>(morphTargetPasses[0]);
const Data::Instance<RPI::Shader> shader = m_morphTargetPass->GetShader();
AZ_Error(s_featureProcessorName, false, "Failed to get morph target pass shader. It may need to finish processing.");
}
}
}
if (!shader)
{
AZ_Error(s_featureProcessorName, false, "Failed to get morph target pass shader. It may need to finish processing.");
}
}
else
{
AZ_Error(s_featureProcessorName, false, "\"MorphTargetPassTemplate\" does not have any valid passes. Check your game project's .pass assets.");
}
}
else
RPI::ShaderOptionGroup SkinnedMeshFeatureProcessor::CreateSkinningShaderOptionGroup(const SkinnedMeshShaderOptions shaderOptions, SkinnedMeshShaderOptionNotificationBus::Handler& shaderReinitializedHandler)
{
m_cachedSkinningShaderOptions.ConnectToShaderReinitializedEvent(shaderReinitializedHandler);
return m_cachedSkinningShaderOptions.CreateShaderOptionGroup(shaderOptions);
}
void SkinnedMeshFeatureProcessor::OnSkinningShaderReinitialized(const Data::Instance<RPI::Shader> skinningShader)
{
m_skinningShader = skinningShader;
m_cachedSkinningShaderOptions.SetShader(m_skinningShader);
}
void SkinnedMeshFeatureProcessor::SubmitSkinningDispatchItems(RHI::CommandList* commandList)
{
AZStd::lock_guard lock(m_dispatchItemMutex);
for (const RHI::DispatchItem* dispatchItem : m_skinningDispatches)
{
AZ_Error(s_featureProcessorName, false, "Failed to find passes for \"MorphTargetPassTemplate\". Check your game project's .pass assets.");
commandList->Submit(*dispatchItem);
}
m_skinningDispatches.clear();
}
void SkinnedMeshFeatureProcessor::SubmitMorphTargetDispatchItems(RHI::CommandList* commandList)
{
AZStd::lock_guard lock(m_dispatchItemMutex);
for (const RHI::DispatchItem* dispatchItem : m_morphTargetDispatches)
{
commandList->Submit(*dispatchItem);
}
m_morphTargetDispatches.clear();
}
SkinnedMeshRenderProxyInterfaceHandle SkinnedMeshFeatureProcessor::AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc)
@@ -363,14 +375,14 @@ namespace AZ
return ReleaseRenderProxy(handle);
}
RPI::Ptr<SkinnedMeshComputePass> SkinnedMeshFeatureProcessor::GetSkinningPass() const
Data::Instance<RPI::Shader> SkinnedMeshFeatureProcessor::GetSkinningShader() const
{
return m_skinningPass;
return m_skinningShader;
}
RPI::Ptr<MorphTargetComputePass> SkinnedMeshFeatureProcessor::GetMorphTargetPass() const
Data::Instance<RPI::Shader> SkinnedMeshFeatureProcessor::GetMorphTargetShader() const
{
return m_morphTargetPass;
return m_morphTargetShader;
}
} // namespace Render
} // namespace AZ
@@ -49,37 +49,47 @@ namespace AZ
// FeatureProcessor overrides ...
void Activate() override;
void Deactivate() override;
void Simulate(const FeatureProcessor::SimulatePacket& packet) override;
void Render(const FeatureProcessor::RenderPacket& packet) override;
void OnRenderEnd() override;
// RPI::SceneNotificationBus overrides ...
void OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) override;
void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override;
void OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) override;
void OnBeginPrepareRender() override;
void OnEndPrepareRender() override;
SkinnedMeshRenderProxyHandle AcquireRenderProxy(const SkinnedMeshRenderProxyDesc& desc);
bool ReleaseRenderProxy(SkinnedMeshRenderProxyHandle& handle);
RPI::Ptr<SkinnedMeshComputePass> GetSkinningPass() const;
RPI::Ptr<MorphTargetComputePass> GetMorphTargetPass() const;
Data::Instance<RPI::Shader> GetSkinningShader() const;
RPI::ShaderOptionGroup CreateSkinningShaderOptionGroup(const SkinnedMeshShaderOptions shaderOptions, SkinnedMeshShaderOptionNotificationBus::Handler& shaderReinitializedHandler);
void OnSkinningShaderReinitialized(const Data::Instance<RPI::Shader> skinningShader);
void SubmitSkinningDispatchItems(RHI::CommandList* commandList);
Data::Instance<RPI::Shader> GetMorphTargetShader() const;
void SubmitMorphTargetDispatchItems(RHI::CommandList* commandList);
private:
AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor);
void InitSkinningAndMorphPass();
void InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass);
SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override;
bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override;
static const char* s_featureProcessorName;
RPI::Ptr<SkinnedMeshComputePass> m_skinningPass;
RPI::Ptr<MorphTargetComputePass> m_morphTargetPass;
Data::Instance<RPI::Shader> m_skinningShader;
CachedSkinnedMeshShaderOptions m_cachedSkinningShaderOptions;
Data::Instance<RPI::Shader> m_morphTargetShader;
AZStd::concurrency_checker m_renderProxiesChecker;
StableDynamicArray<SkinnedMeshRenderProxy> m_renderProxies;
AZStd::unique_ptr<SkinnedMeshStatsCollector> m_statsCollector;
MeshFeatureProcessor* m_meshFeatureProcessor = nullptr;
AZStd::unordered_set<const RHI::DispatchItem*> m_skinningDispatches;
AZStd::unordered_set<const RHI::DispatchItem*> m_morphTargetDispatches;
AZStd::mutex m_dispatchItemMutex;
};
} // namespace Render
@@ -60,13 +60,7 @@ namespace AZ
bool SkinnedMeshRenderProxy::BuildDispatchItem([[maybe_unused]] const RPI::Scene& scene, size_t modelLodIndex, [[maybe_unused]] const SkinnedMeshShaderOptions& shaderOptions)
{
if (!m_featureProcessor->GetSkinningPass())
{
AZ_Error("Skinned Mesh Feature Processor", false, "Failed to get Skinning Pass. Make sure the project has a skinning pass.");
return false;
}
Data::Instance<RPI::Shader> skinningShader = m_featureProcessor->GetSkinningPass()->GetShader();
Data::Instance<RPI::Shader> skinningShader = m_featureProcessor->GetSkinningShader();
if (!skinningShader)
{
AZ_Error("Skinned Mesh Feature Processor", false, "Failed to get skinning shader from skinning pass");
@@ -89,7 +83,7 @@ namespace AZ
m_instance->m_outputStreamOffsetsInBytes[modelLodIndex],
modelLodIndex, m_boneTransforms,
m_shaderOptions,
m_featureProcessor->GetSkinningPass(),
m_featureProcessor,
m_instance->m_morphTargetInstanceMetaData[modelLodIndex],
morphDeltaIntegerEncoding });
@@ -100,7 +94,7 @@ namespace AZ
}
// Get the data needed to create a morph target dispatch item
Data::Instance<RPI::Shader> morphTargetShader = m_featureProcessor->GetMorphTargetPass()->GetShader();
Data::Instance<RPI::Shader> morphTargetShader = m_featureProcessor->GetMorphTargetShader();
const AZStd::vector<AZStd::intrusive_ptr<MorphTargetInputBuffers>>& morphTargetInputBuffersVector = m_inputBuffers->GetMorphTargetInputBuffers(modelLodIndex);
AZ_Assert(morphTargetMetaDatas.size() == morphTargetInputBuffersVector.size(), "Skinned Mesh Feature Processor - Mismatch in morph target metadata count and morph target input buffer count");
@@ -118,7 +112,7 @@ namespace AZ
aznew MorphTargetDispatchItem{
morphTargetInputBuffersVector[morphTargetIndex],
morphTargetMetaDatas[morphTargetIndex],
m_featureProcessor->GetMorphTargetPass(),
m_featureProcessor,
m_instance->m_morphTargetInstanceMetaData[modelLodIndex],
morphDeltaIntegerEncoding });
@@ -381,6 +381,7 @@ namespace AZ
uint64_t m_createdByPassRequest : 1;
uint64_t m_initialized : 1;
uint64_t m_enabled : 1;
uint64_t m_parentEnabled : 1;
uint64_t m_alreadyCreated : 1;
uint64_t m_alreadyReset : 1;
uint64_t m_alreadyPrepared : 1;
@@ -15,6 +15,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/std/containers/unordered_map.h>
#include <Atom/RPI.Reflect/Asset/AssetHandler.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
namespace AZ::RPI
{
@@ -56,6 +57,9 @@ namespace AZ::RPI
float m_minPositionDelta;
float m_maxPositionDelta;
//! Reference to the wrinkle mask, if it exists
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> m_wrinkleMask;
//! Boolean to indicate the presence or absence of color deltas
bool m_hasColorDeltas = false;
@@ -18,6 +18,9 @@
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/Asset/AssetManagerBus.h>
namespace AZ::RPI
{
using namespace AZ::SceneAPI;
@@ -114,7 +117,7 @@ namespace AZ::RPI
meshNodeName, sourceMesh.m_name.GetCStr());
const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex);
BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter);
BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename());
}
}
}
@@ -157,7 +160,8 @@ namespace AZ::RPI
const AZStd::string& blendShapeName,
const AZStd::shared_ptr<const DataTypes::IBlendShapeData>& blendShapeData,
const DataTypes::MatrixType& globalTransform,
const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter)
const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter,
const AZStd::string& sourceSceneFilename)
{
const float tolerance = CalcPositionDeltaTolerance(sourceMesh);
AZ::Aabb deltaPositionAabb = AZ::Aabb::CreateNull();
@@ -288,6 +292,8 @@ namespace AZ::RPI
metaData.m_maxPositionDelta = maxValue;
}
metaData.m_wrinkleMask = GetWrinkleMask(sourceSceneFilename, blendShapeName);
metaAssetCreator.AddMorphTarget(metaData);
AZ_Assert(uncompressedPositionDeltas.size() == compressedDeltas.size(), "Number of uncompressed (%d) and compressed position delta components (%d) do not match.",
@@ -312,4 +318,47 @@ namespace AZ::RPI
AZ_Assert((packedCompressedMorphTargetVertexData.size() - metaData.m_startIndex) == numMorphedVertices, "Vertex index range (%d) in morph target meta data does not match number of morphed vertices (%d).",
packedCompressedMorphTargetVertexData.size() - metaData.m_startIndex, numMorphedVertices);
}
Data::Asset<RPI::StreamingImageAsset> MorphTargetExporter::GetWrinkleMask(const AZStd::string& sourceSceneFullFilePath, const AZStd::string& blendShapeName) const
{
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset;
// See if there is a wrinkle map mask for this mesh
AZStd::string sceneRelativeFilePath;
bool relativePathFound = true;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(relativePathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetRelativeProductPathFromFullSourceOrProductPath, sourceSceneFullFilePath, sceneRelativeFilePath);
if (relativePathFound)
{
AZ::StringFunc::Path::StripFullName(sceneRelativeFilePath);
// Get the folder the masks are supposed to be in
AZStd::string folderName;
AZ::StringFunc::Path::GetFileName(sourceSceneFullFilePath.c_str(), folderName);
folderName += "_wrinklemasks";
// Note: for now, we're assuming the mask is always authored as a .tif
AZStd::string blendMaskFileName = blendShapeName + "_wrinklemask.tif.streamingimage";
AZStd::string maskFolderAndFile;
AZ::StringFunc::Path::Join(folderName.c_str(), blendMaskFileName.c_str(), maskFolderAndFile);
AZStd::string maskRelativePath;
AZ::StringFunc::Path::Join(sceneRelativeFilePath.c_str(), maskFolderAndFile.c_str(), maskRelativePath);
AZ::StringFunc::Path::Normalize(maskRelativePath);
// Now see if the file exists
AZ::Data::AssetId maskAssetId;
Data::AssetCatalogRequestBus::BroadcastResult(maskAssetId, &Data::AssetCatalogRequests::GetAssetIdByPath, maskRelativePath.c_str(), AZ::Data::s_invalidAssetType, false);
if (maskAssetId.IsValid())
{
// Flush asset manager events to ensure no asset references are held by closures queued on Ebuses.
AZ::Data::AssetManager::Instance().DispatchEvents();
imageAsset.Create(maskAssetId, AZ::Data::AssetLoadBehavior::PreLoad, false);
}
}
return imageAsset;
}
} // namespace AZ::RPI
@@ -64,7 +64,11 @@ namespace AZ
const AZStd::string& blendShapeName,
const AZStd::shared_ptr<const AZ::SceneAPI::DataTypes::IBlendShapeData>& blendShapeData,
const AZ::SceneAPI::DataTypes::MatrixType& globalTransform,
const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter);
const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter,
const AZStd::string& sourceSceneFilename);
// Find a wrinkle mask for this morph target, if it exists
Data::Asset<RPI::StreamingImageAsset> GetWrinkleMask(const AZStd::string& sourceSceneFullFilePath, const AZStd::string& blendShapeName) const;
};
} // namespace RPI
} // namespace AZ
@@ -422,7 +422,7 @@ namespace AZ
const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex);
AZ::Name enumName = AZ::Name(property.m_value.GetValue<AZStd::string>());
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
uint32_t enumValue = propertyDescriptor ? propertyDescriptor->GetEnumValue(enumName) : MaterialPropertyDescriptor::InvalidEnumValue;
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
{
materialTypeAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
@@ -93,11 +93,12 @@ namespace AZ
void Pass::SetEnabled(bool enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
}
bool Pass::IsEnabled() const
{
return m_flags.m_enabled;
return m_flags.m_enabled && (m_flags.m_parentEnabled || m_parent == nullptr);
}
// --- Error Logging ---
@@ -140,6 +141,7 @@ namespace AZ
}
// Set new tree depth and path
m_flags.m_parentEnabled = m_parent->m_flags.m_enabled && (m_parent->m_flags.m_parentEnabled || m_parent->m_parent == nullptr);
m_treeDepth = m_parent->m_treeDepth + 1;
m_path = ConcatPassName(m_parent->m_path, m_name);
m_flags.m_partOfHierarchy = m_parent->m_flags.m_partOfHierarchy;
@@ -28,6 +28,7 @@ namespace AZ::RPI
->Field("numVertices", &MorphTargetMetaAsset::MorphTarget::m_numVertices)
->Field("minPositionDelta", &MorphTargetMetaAsset::MorphTarget::m_minPositionDelta)
->Field("maxPositionDelta", &MorphTargetMetaAsset::MorphTarget::m_maxPositionDelta)
->Field("wrinkleMask", &MorphTargetMetaAsset::MorphTarget::m_wrinkleMask)
->Field("hasColorDeltas", &MorphTargetMetaAsset::MorphTarget::m_hasColorDeltas)
;
}
@@ -11,7 +11,7 @@
0.29372090101242068,
1.0
],
"textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png",
"useTexture": false
},
"detailLayerGroup": {
@@ -30,7 +30,7 @@
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_normal.tif"
"textureMap": "Objects/Lucy/Lucy_normal.png"
},
"subsurfaceScattering": {
"enableSubsurfaceScattering": true,
@@ -29,7 +29,7 @@
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_normal.tif"
"textureMap": "Objects/Lucy/Lucy_normal.png"
},
"subsurfaceScattering": {
"enableSubsurfaceScattering": true,
@@ -5,20 +5,20 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
"textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png",
"textureMapUv": "Unwrapped"
},
"metallic": {
"textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_normal.tif",
"textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
"textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
"textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png",
"textureMapUv": "Unwrapped"
},
"detailLayerGroup": {
@@ -22,16 +22,16 @@
"scale": 10.0
},
"metallic": {
"textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_normal.tif",
"textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
"textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
"textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png",
"textureMapUv": "Unwrapped"
},
"detailLayerGroup": {
@@ -21,16 +21,16 @@
"scale": 10.0
},
"metallic": {
"textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
"textureMap": "Objects/Lucy/Lucy_normal.tif",
"textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
"textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
"textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}