diff --git a/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass b/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass
new file mode 100644
index 0000000000..f1e8304b30
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass
@@ -0,0 +1,215 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "PassAsset",
+ "ClassData": {
+ "PassTemplate": {
+ "Name": "HDRColorGradingTemplate",
+ "PassClass": "FullScreenTriangle",
+ "Slots": [
+ {
+ "Name": "Input",
+ "SlotType": "Input",
+ "ShaderInputName": "m_framebuffer",
+ "ScopeAttachmentUsage": "Shader"
+ },
+ {
+ "Name": "Output",
+ "SlotType": "Output",
+ "ScopeAttachmentUsage": "RenderTarget",
+ "LoadStoreAction": {
+ "LoadAction": "DontCare"
+ }
+ }
+ ],
+ "ImageAttachments": [
+ {
+ "Name": "ColorGradingOutput",
+ "SizeSource": {
+ "Source": {
+ "Pass": "This",
+ "Attachment": "Input"
+ }
+ },
+ "FormatSource": {
+ "Pass": "This",
+ "Attachment": "Input"
+ }
+ }
+ ],
+ "Connections": [
+ {
+ "LocalSlot": "Output",
+ "AttachmentRef": {
+ "Pass": "This",
+ "Attachment": "ColorGradingOutput"
+ }
+ }
+ ],
+ "FallbackConnections": [
+ {
+ "Input": "Input",
+ "Output": "Output"
+ }
+ ],
+ "PassData": {
+ "$type": "FullscreenTrianglePassData",
+ "ShaderAsset": {
+ "FilePath": "Shaders/PostProcessing/HDRColorGrading.shader"
+ },
+ "ShaderDataMappings": {
+ "FloatMappings": [
+ {
+ "Name": "m_colorGradingExposure",
+ "Value": 0.0 // unconstrained, log2 stops
+ },
+ {
+ "Name": "m_colorGradingContrast",
+ "Value": 0.0 // -100 ... 100
+ },
+ {
+ "Name": "m_colorGradingHueShift",
+ "Value": 0.0 // 0 ... 1, can wrap
+ },
+ {
+ "Name": "m_colorGradingPreSaturation",
+ "Value": 1.0 // -100 ... 100
+ },
+ {
+ "Name": "m_colorFilterIntensity",
+ "Value": 1.0 // unconstrained, log2 stops
+ },
+ {
+ "Name": "m_colorFilterMultiply",
+ "Value": 0.0 // modulate, 0 ... 1
+ },
+ {
+ "Name": "m_whiteBalanceKelvin",
+ "Value": 6500.0 // 1000.0f ... 40000.0f kelvin
+ },
+ {
+ "Name": "m_whiteBalanceTint",
+ "Value": 0.0 // -100 ... 100
+ },
+ {
+ "Name": "m_splitToneBalance",
+ "Value": 0.0 // -1 ... 1
+ },
+ {
+ "Name": "m_splitToneMix",
+ "Value": 0.0 // 0 ... 1
+ },
+ {
+ "Name": "m_colorGradingPostSaturation",
+ "Value": 1.0 // -100 ... 100
+ },
+ {
+ "Name": "m_smhShadowsStart",
+ "Value": 0.0 // 0 ... 1
+ },
+ {
+ "Name": "m_smhShadowsEnd",
+ "Value": 0.3 // 0 ... 1
+ },
+ {
+ "Name": "m_smhHighlightsStart",
+ "Value": 0.55 // 0 ... 1
+ },
+ {
+ "Name": "m_smhHighlightsEnd",
+ "Value": 1.0 // 0 ... 1
+ },
+ {
+ "Name": "m_smhMix",
+ "Value": 0.0 // 0 ... 1
+ }
+ ],
+ // The colors defined here are expected to be in linear rgb color space.
+ // These are converted to ACEScg color space within the HDRColorGrading.azsl shader
+ "ColorMappings": [
+ {
+ "Name": "m_colorFilterSwatch",
+ "Value": [
+ 1.0,
+ 0.5,
+ 0.5,
+ 1.0
+ ]
+ },
+ {
+ "Name": "m_splitToneShadowsColor",
+ "Value": [
+ 1.0,
+ 0.1,
+ 0.1,
+ 1.0
+ ]
+ },
+ {
+ "Name": "m_splitToneHighlightsColor",
+ "Value": [
+ 0.1,
+ 1.0,
+ 0.1,
+ 1.0
+ ]
+ },
+ {
+ "Name": "m_smhShadowsColor",
+ "Value": [
+ 1.0,
+ 0.25,
+ 0.25,
+ 1.0
+ ]
+ },
+ {
+ "Name": "m_smhMidtonesColor",
+ "Value": [
+ 0.1,
+ 0.1,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "Name": "m_smhHighlightsColor",
+ "Value": [
+ 1.0,
+ 0.0,
+ 1.0,
+ 1.0
+ ]
+ }
+ ],
+ "Float3Mappings": [
+ {
+ "Name": "m_channelMixingRed",
+ "Value": [
+ 1.0,
+ 0.0,
+ 0.0
+ ]
+ },
+ {
+ "Name": "m_channelMixingGreen",
+ "Value": [
+ 0.0,
+ 1.0,
+ 0.0
+ ]
+ },
+ {
+ "Name": "m_channelMixingBlue",
+ "Value": [
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
index 8b7d6a8438..4e38717d31 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
+++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
@@ -499,7 +499,11 @@
{
"Name": "KawaseShadowBlurTemplate",
"Path": "Passes/KawaseShadowBlur.pass"
- }
+ },
+ {
+ "Name": "HDRColorGradingTemplate",
+ "Path": "Passes/HDRColorGrading.pass"
+ }
]
}
}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli
new file mode 100644
index 0000000000..aa57f0f4a1
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: (Apache-2.0 OR MIT) AND Creative Commons 3.0
+ *
+ */
+
+// Ref: https://www.shadertoy.com/view/lsSXW1
+// ported by Renaud Bédard (@renaudbedard) from original code from Tanner Helland
+// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
+
+// color space functions translated from HLSL versions on Chilli Ant (by Ian Taylor)
+// http://www.chilliant.com/rgb2hsv.html
+
+// licensed and released under Creative Commons 3.0 Attribution
+// https://creativecommons.org/licenses/by/3.0/
+
+float3 HueToRgb(float hue)
+{
+ return saturate(float3(abs(hue * 6.0f - 3.0f) - 1.0f,
+ 2.0f - abs(hue * 6.0f - 2.0f),
+ 2.0f - abs(hue * 6.0f - 4.0f)));
+}
+
+float3 RgbToHcv(float3 rgb)
+{
+ // Based on work by Sam Hocevar and Emil Persson
+ const float4 p = (rgb.g < rgb.b) ? float4(rgb.bg, -1.0f, 2.0f/3.0f) : float4(rgb.gb, 0.0f, -1.0f/3.0f);
+ const float4 q1 = (rgb.r < p.x) ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
+ const float c = q1.x - min(q1.w, q1.y);
+ const float h = abs((q1.w - q1.y) / (6.0f * c + 0.000001f ) + q1.z);
+ return float3(h, c, q1.x);
+}
+
+float3 RgbToHsl(float3 rgb)
+{
+ rgb.xyz = max(rgb.xyz, 0.000001f);
+ const float3 hcv = RgbToHcv(rgb);
+ const float L = hcv.z - hcv.y * 0.5f;
+ const float S = hcv.y / (1.0f - abs(L * 2.0f - 1.0f) + 0.000001f);
+ return float3(hcv.x, S, L);
+}
+
+float3 HslToRgb(float3 hsl)
+{
+ const float3 rgb = HueToRgb(hsl.x);
+ const float c = (1.0f - abs(2.0f * hsl.z - 1.0f)) * hsl.y;
+ return (rgb - 0.5f) * c + hsl.z;
+}
+
+// Color temperature
+float3 KelvinToRgb(float kelvin)
+{
+ float3 ret;
+ kelvin = clamp(kelvin, 1000.0f, 40000.0f) / 100.0f;
+ if(kelvin <= 66.0f)
+ {
+ ret.r = 1.0f;
+ ret.g = saturate(0.39008157876901960784f * log(kelvin) - 0.63184144378862745098f);
+ }
+ else
+ {
+ float t = max(kelvin - 60.0f, 0.0f);
+ ret.r = saturate(1.29293618606274509804f * pow(t, -0.1332047592f));
+ ret.g = saturate(1.12989086089529411765f * pow(t, -0.0755148492f));
+ }
+ if(kelvin >= 66.0f)
+ ret.b = 1.0f;
+ else if(kelvin < 19.0f)
+ ret.b = 0.0f;
+ else
+ ret.b = saturate(0.54320678911019607843f * log(kelvin - 10.0f) - 1.19625408914f);
+ return ret;
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli
new file mode 100644
index 0000000000..9c2a5bc306
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli
@@ -0,0 +1,177 @@
+/*
+ * 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
+ *
+ */
+
+/*
+------------------------------------------------------------------------------
+ Public Domain
+------------------------------------------------------------------------------
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
+
+Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
+*/
+//******************************************************************************
+//******************************************************************************
+float Color_GetLuminosity(float3 c)
+{
+ return 0.3*c.r + 0.59*c.g + 0.11*c.b;
+}
+
+//******************************************************************************
+//******************************************************************************
+float3 Color_SetLuminosity(float3 c, float lum)
+{
+ float d = lum - Color_GetLuminosity(c);
+ c.rgb += float3(d,d,d);
+
+ // clip back into legal range
+ lum = Color_GetLuminosity(c);
+ float cMin = min(c.r, min(c.g, c.b));
+ float cMax = max(c.r, max(c.g, c.b));
+
+ if(cMin < 0)
+ c = lerp(float3(lum,lum,lum), c, lum / (lum - cMin));
+
+ if(cMax > 1)
+ c = lerp(float3(lum,lum,lum), c, (1 - lum) / (cMax - lum));
+
+ return c;
+}
+
+//******************************************************************************
+//******************************************************************************
+float Color_GetSaturation(float3 c)
+{
+ return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
+}
+
+//******************************************************************************
+// Set saturation if color components are sorted in ascending order.
+//******************************************************************************
+float3 Color_SetSaturation_MinMidMax(float3 cSorted, float s)
+{
+ if(cSorted.z > cSorted.x)
+ {
+ cSorted.y = (((cSorted.y - cSorted.x) * s) / (cSorted.z - cSorted.x));
+ cSorted.z = s;
+ }
+ else
+ {
+ cSorted.y = 0;
+ cSorted.z = 0;
+ }
+
+ cSorted.x = 0;
+
+ return cSorted;
+}
+
+//******************************************************************************
+//******************************************************************************
+float3 Color_SetSaturation(float3 c, float s)
+{
+ if (c.r <= c.g && c.r <= c.b)
+ {
+ if (c.g <= c.b)
+ c.rgb = Color_SetSaturation_MinMidMax(c.rgb, s);
+ else
+ c.rbg = Color_SetSaturation_MinMidMax(c.rbg, s);
+ }
+ else if (c.g <= c.r && c.g <= c.b)
+ {
+ if (c.r <= c.b)
+ c.grb = Color_SetSaturation_MinMidMax(c.grb, s);
+ else
+ c.gbr = Color_SetSaturation_MinMidMax(c.gbr, s);
+ }
+ else
+ {
+ if (c.r <= c.g)
+ c.brg = Color_SetSaturation_MinMidMax(c.brg, s);
+ else
+ c.bgr = Color_SetSaturation_MinMidMax(c.bgr, s);
+ }
+
+ return c;
+}
+
+//******************************************************************************
+// Creates a color with the hue of the blend color and the saturation and
+// luminosity of the base color.
+//******************************************************************************
+float3 BlendMode_Hue(float3 base, float3 blend)
+{
+ return Color_SetLuminosity(Color_SetSaturation(blend, Color_GetSaturation(base)), Color_GetLuminosity(base));
+}
+
+//******************************************************************************
+// Creates a color with the saturation of the blend color and the hue and
+// luminosity of the base color.
+//******************************************************************************
+float3 BlendMode_Saturation(float3 base, float3 blend)
+{
+ return Color_SetLuminosity(Color_SetSaturation(base, Color_GetSaturation(blend)), Color_GetLuminosity(base));
+}
+
+//******************************************************************************
+// Creates a color with the hue and saturation of the blend color and the
+// luminosity of the base color.
+//******************************************************************************
+float3 BlendMode_Color(float3 base, float3 blend)
+{
+ return Color_SetLuminosity(blend, Color_GetLuminosity(base));
+}
+
+//******************************************************************************
+// Creates a color with the luminosity of the blend color and the hue and
+// saturation of the base color.
+//******************************************************************************
+float3 BlendMode_Luminosity(float3 base, float3 blend)
+{
+ return Color_SetLuminosity(base, Color_GetLuminosity(blend));
+}
+
+//******************************************************************************
+// Compares the total of all channel values for the blend and base color and
+// displays the lower value color.
+//******************************************************************************
+float3 BlendMode_DarkerColor(float3 base, float3 blend)
+{
+ return Color_GetLuminosity(base) <= Color_GetLuminosity(blend) ? base : blend;
+}
+
+//******************************************************************************
+// Compares the total of all channel values for the blend and base color and
+// displays the higher value color.
+//******************************************************************************
+float3 BlendMode_LighterColor(float3 base, float3 blend)
+{
+ return Color_GetLuminosity(base) > Color_GetLuminosity(blend) ? base : blend;
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli
new file mode 100644
index 0000000000..f64df30231
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli
@@ -0,0 +1,306 @@
+/*
+ * 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
+ *
+ */
+
+/*
+------------------------------------------------------------------------------
+ Public Domain
+------------------------------------------------------------------------------
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
+
+Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
+*/
+//******************************************************************************
+// Selects the blend color, ignoring the base.
+//******************************************************************************
+float3 BlendMode_Normal(float3 base, float3 blend)
+{
+ return blend;
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and selects the base or blend
+// color—whichever is darker—as the result color.
+//******************************************************************************
+float3 BlendMode_Darken(float3 base, float3 blend)
+{
+ return min(base, blend);
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and multiplies the base color
+// by the blend color.
+//******************************************************************************
+float3 BlendMode_Multiply(float3 base, float3 blend)
+{
+ return base*blend;
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and darkens the base color to
+// reflect the blend color by increasing the contrast between the two.
+//******************************************************************************
+float BlendMode_ColorBurn(float base, float blend)
+{
+ return blend > 0 ? 1 - min(1, (1-base) / blend) : 0;
+}
+
+float3 BlendMode_ColorBurn(float3 base, float3 blend)
+{
+ return float3( BlendMode_ColorBurn(base.r, blend.r),
+ BlendMode_ColorBurn(base.g, blend.g),
+ BlendMode_ColorBurn(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and darkens the base color to
+// reflect the blend color by decreasing the brightness.
+//******************************************************************************
+float BlendMode_LinearBurn(float base, float blend)
+{
+ return max(0, base + blend - 1);
+}
+
+float3 BlendMode_LinearBurn(float3 base, float3 blend)
+{
+ return float3( BlendMode_LinearBurn(base.r, blend.r),
+ BlendMode_LinearBurn(base.g, blend.g),
+ BlendMode_LinearBurn(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and selects the base or blend
+// color—whichever is lighter—as the result color.
+//******************************************************************************
+float3 BlendMode_Lighten(float3 base, float3 blend)
+{
+ return max(base, blend);
+}
+
+//******************************************************************************
+// Looks at each channel’s color information and multiplies the inverse of the
+// blend and base colors.
+//******************************************************************************
+float3 BlendMode_Screen(float3 base, float3 blend)
+{
+ return base + blend - base*blend;
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and brightens the base color
+// to reflect the blend color by decreasing contrast between the two.
+//******************************************************************************
+float BlendMode_ColorDodge(float base, float blend)
+{
+ return blend < 1 ? min(1, base / (1-blend)) : 1;
+}
+
+float3 BlendMode_ColorDodge(float3 base, float3 blend)
+{
+ return float3( BlendMode_ColorDodge(base.r, blend.r),
+ BlendMode_ColorDodge(base.g, blend.g),
+ BlendMode_ColorDodge(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and brightens the base color
+// to reflect the blend color by decreasing contrast between the two.
+//******************************************************************************
+float BlendMode_LinearDodge(float base, float blend)
+{
+ return min(1, base + blend);
+}
+
+float3 BlendMode_LinearDodge(float3 base, float3 blend)
+{
+ return float3( BlendMode_LinearDodge(base.r, blend.r),
+ BlendMode_LinearDodge(base.g, blend.g),
+ BlendMode_LinearDodge(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Multiplies or screens the colors, depending on the base color.
+//******************************************************************************
+float BlendMode_Overlay(float base, float blend)
+{
+ return (base <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
+}
+
+float3 BlendMode_Overlay(float3 base, float3 blend)
+{
+ return float3( BlendMode_Overlay(base.r, blend.r),
+ BlendMode_Overlay(base.g, blend.g),
+ BlendMode_Overlay(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Darkens or lightens the colors, depending on the blend color.
+//******************************************************************************
+float BlendMode_SoftLight(float base, float blend)
+{
+ if (blend <= 0.5)
+ {
+ return base - (1-2*blend)*base*(1-base);
+ }
+ else
+ {
+ float d = (base <= 0.25) ? ((16*base-12)*base+4)*base : sqrt(base);
+ return base + (2*blend-1)*(d-base);
+ }
+}
+
+float3 BlendMode_SoftLight(float3 base, float3 blend)
+{
+ return float3( BlendMode_SoftLight(base.r, blend.r),
+ BlendMode_SoftLight(base.g, blend.g),
+ BlendMode_SoftLight(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Multiplies or screens the colors, depending on the blend color.
+//******************************************************************************
+float BlendMode_HardLight(float base, float blend)
+{
+ return (blend <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
+}
+
+float3 BlendMode_HardLight(float3 base, float3 blend)
+{
+ return float3( BlendMode_HardLight(base.r, blend.r),
+ BlendMode_HardLight(base.g, blend.g),
+ BlendMode_HardLight(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Burns or dodges the colors by increasing or decreasing the contrast,
+// depending on the blend color.
+//******************************************************************************
+float BlendMode_VividLight(float base, float blend)
+{
+ return (blend <= 0.5) ? BlendMode_ColorBurn(base,2*blend) : BlendMode_ColorDodge(base,2*(blend-0.5));
+}
+
+float3 BlendMode_VividLight(float3 base, float3 blend)
+{
+ return float3( BlendMode_VividLight(base.r, blend.r),
+ BlendMode_VividLight(base.g, blend.g),
+ BlendMode_VividLight(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Burns or dodges the colors by decreasing or increasing the brightness,
+// depending on the blend color.
+//******************************************************************************
+float BlendMode_LinearLight(float base, float blend)
+{
+ return (blend <= 0.5) ? BlendMode_LinearBurn(base,2*blend) : BlendMode_LinearDodge(base,2*(blend-0.5));
+}
+
+float3 BlendMode_LinearLight(float3 base, float3 blend)
+{
+ return float3( BlendMode_LinearLight(base.r, blend.r),
+ BlendMode_LinearLight(base.g, blend.g),
+ BlendMode_LinearLight(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Replaces the colors, depending on the blend color.
+//******************************************************************************
+float BlendMode_PinLight(float base, float blend)
+{
+ return (blend <= 0.5) ? min(base,2*blend) : max(base,2*(blend-0.5));
+}
+
+float3 BlendMode_PinLight(float3 base, float3 blend)
+{
+ return float3( BlendMode_PinLight(base.r, blend.r),
+ BlendMode_PinLight(base.g, blend.g),
+ BlendMode_PinLight(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Adds the red, green and blue channel values of the blend color to the RGB
+// values of the base color. If the resulting sum for a channel is 255 or
+// greater, it receives a value of 255; if less than 255, a value of 0.
+//******************************************************************************
+float BlendMode_HardMix(float base, float blend)
+{
+ return (base + blend >= 1.0) ? 1.0 : 0.0;
+}
+
+float3 BlendMode_HardMix(float3 base, float3 blend)
+{
+ return float3( BlendMode_HardMix(base.r, blend.r),
+ BlendMode_HardMix(base.g, blend.g),
+ BlendMode_HardMix(base.b, blend.b) );
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and subtracts either the
+// blend color from the base color or the base color from the blend color,
+// depending on which has the greater brightness value.
+//******************************************************************************
+float3 BlendMode_Difference(float3 base, float3 blend)
+{
+ return abs(base-blend);
+}
+
+//******************************************************************************
+// Creates an effect similar to but lower in contrast than the Difference mode.
+//******************************************************************************
+float3 BlendMode_Exclusion(float3 base, float3 blend)
+{
+ return base + blend - 2*base*blend;
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and subtracts the blend color
+// from the base color.
+//******************************************************************************
+float3 BlendMode_Subtract(float3 base, float3 blend)
+{
+ return max(0, base - blend);
+}
+
+//******************************************************************************
+// Looks at the color information in each channel and divides the blend color
+// from the base color.
+//******************************************************************************
+float BlendMode_Divide(float base, float blend)
+{
+ return blend > 0 ? min(1, base / blend) : 1;
+}
+
+float3 BlendMode_Divide(float3 base, float3 blend)
+{
+ return float3( BlendMode_Divide(base.r, blend.r),
+ BlendMode_Divide(base.g, blend.g),
+ BlendMode_Divide(base.b, blend.b) );
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli
new file mode 100644
index 0000000000..e84b18c550
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli
@@ -0,0 +1,80 @@
+/*
+ * 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: (MIT OR Apache-2.0) AND LicenseRef-ACES
+ *
+ */
+
+/*
+License Terms for Academy Color Encoding System Components
+
+Academy Color Encoding System (ACES) software and tools are provided by the
+ Academy under the following terms and conditions: A worldwide, royalty-free,
+ non-exclusive right to copy, modify, create derivatives, and use, in source and
+ binary forms, is hereby granted, subject to acceptance of this license.
+
+Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
+Portions contributed by others as indicated. All rights reserved.
+
+Performance of any of the aforementioned acts indicates acceptance to be bound
+ by the following terms and conditions:
+
+* Copies of source code, in whole or in part, must retain the above copyright
+ notice, this list of conditions and the Disclaimer of Warranty.
+* Use in binary form must retain the above copyright notice, this list of
+ conditions and the Disclaimer of Warranty in the documentation and/or other
+ materials provided with the distribution.
+* Nothing in this license shall be deemed to grant any rights to trademarks,
+ copyrights, patents, trade secrets or any other intellectual property of
+ A.M.P.A.S. or any contributors, except as expressly stated herein.
+* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
+ software may be used to endorse or promote products derivative of or based on
+ this software without express prior written permission of A.M.P.A.S. or the
+ contributors, as appropriate.
+
+This license shall be construed pursuant to the laws of the State of California,
+and any disputes related thereto shall be subject to the jurisdiction of the
+ courts therein.
+
+Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
+CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
+DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
+OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
+APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
+UNDISCLOSED.
+*/
+
+#pragma once
+
+static const float HALF_MAX = 65504.0f;
+
+float AcesCcToLinear(float value)
+{
+ if (value < -0.3013698630) // (9.72-15)/17.52
+ return (pow( 2., value*17.52-9.72) - pow( 2.,-16.))*2.0;
+ else if (value < (log2(HALF_MAX)+9.72)/17.52)
+ return pow( 2., value*17.52-9.72);
+ else // (value >= (log2(HALF_MAX)+9.72)/17.52)
+ return HALF_MAX;
+}
+
+float3 AcesCcToAcesCg(float3 color)
+{
+ return float3(
+ AcesCcToLinear(color.r),
+ AcesCcToLinear(color.g),
+ AcesCcToLinear(color.b));
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli
new file mode 100644
index 0000000000..f784a76990
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: (MIT OR Apache-2.0) AND LicenseRef-ACES
+ *
+ */
+
+/*
+License Terms for Academy Color Encoding System Components
+
+Academy Color Encoding System (ACES) software and tools are provided by the
+ Academy under the following terms and conditions: A worldwide, royalty-free,
+ non-exclusive right to copy, modify, create derivatives, and use, in source and
+ binary forms, is hereby granted, subject to acceptance of this license.
+
+Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
+Portions contributed by others as indicated. All rights reserved.
+
+Performance of any of the aforementioned acts indicates acceptance to be bound
+ by the following terms and conditions:
+
+* Copies of source code, in whole or in part, must retain the above copyright
+ notice, this list of conditions and the Disclaimer of Warranty.
+* Use in binary form must retain the above copyright notice, this list of
+ conditions and the Disclaimer of Warranty in the documentation and/or other
+ materials provided with the distribution.
+* Nothing in this license shall be deemed to grant any rights to trademarks,
+ copyrights, patents, trade secrets or any other intellectual property of
+ A.M.P.A.S. or any contributors, except as expressly stated herein.
+* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
+ software may be used to endorse or promote products derivative of or based on
+ this software without express prior written permission of A.M.P.A.S. or the
+ contributors, as appropriate.
+
+This license shall be construed pursuant to the laws of the State of California,
+and any disputes related thereto shall be subject to the jurisdiction of the
+ courts therein.
+
+Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
+CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
+DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
+OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
+APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
+UNDISCLOSED.
+*/
+
+#pragma once
+
+float LinearToAcesCc(float value)
+{
+ if (value <= 0)
+ return -0.3584474886; // =(log2( pow(2.,-16.))+9.72)/17.52
+ else if (value < pow(2.,-15.))
+ return (log2( pow(2.,-16.) + value * 0.5) + 9.72) / 17.52;
+ else // (value >= pow(2.,-15))
+ return (log2(value) + 9.72) / 17.52;
+}
+
+float3 AcesCgToAcesCc(float3 color)
+{
+ return float3(
+ LinearToAcesCc(color.r),
+ LinearToAcesCc(color.g),
+ LinearToAcesCc(color.b)
+ );
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli
index e298445c7c..c9d1b7d979 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli
@@ -8,11 +8,14 @@
#pragma once
+#include
#include "GeneratedTransforms/LinearSrgb_To_AcesCg.azsli"
#include "GeneratedTransforms/AcesCg_To_LinearSrgb.azsli"
#include "GeneratedTransforms/LinearSrgb_To_Srgb.azsli"
#include "GeneratedTransforms/Srgb_To_LinearSrgb.azsli"
#include "GeneratedTransforms/Aces_To_AcesCg.azsli"
+#include "GeneratedTransforms/AcesCcToAcesCg.azsli"
+#include "GeneratedTransforms/AcesCgToAcesCc.azsli"
#include "GeneratedTransforms/CalculateLuminance_LinearSrgb.azsli"
#include "GeneratedTransforms/CalculateLuminance_AcesCg.azsli"
@@ -20,6 +23,7 @@ enum class ColorSpaceId
{
SRGB = 0,
LinearSRGB,
+ ACEScc,
ACEScg,
ACES2065,
XYZ,
@@ -51,15 +55,27 @@ float3 TransformColor(in float3 color, ColorSpaceId fromColorSpace, ColorSpaceId
color = AcesCg_To_LinearSrgb(color);
color = LinearSrgb_To_Srgb(color);
}
+ else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::LinearSRGB)
+ {
+ color = AcesCg_To_LinearSrgb(color);
+ }
+ else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::ACEScc)
+ {
+ color = AcesCgToAcesCc(color);
+ }
else if (fromColorSpace == ColorSpaceId::ACES2065 && toColorSpace == ColorSpaceId::ACEScg)
{
color = Aces_To_AcesCg(color);
}
+ else if (fromColorSpace == ColorSpaceId::ACEScc && toColorSpace == ColorSpaceId::ACEScg)
+ {
+ color = AcesCcToAcesCg(color);
+ }
else
{
color = float3(1, 0, 1);
}
-
+
return color;
}
@@ -75,6 +91,7 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
luminance = CalculateLuminance_AcesCg(color);
break;
case ColorSpaceId::SRGB:
+ case ColorSpaceId::ACEScc:
case ColorSpaceId::ACES2065:
case ColorSpaceId::XYZ:
case ColorSpaceId::Invalid:
@@ -83,3 +100,29 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
return luminance;
}
+
+float RotateHue(float hue, float low, float hi)
+{
+ return (hue < low)
+ ? hue + hi
+ : (hue > hi)
+ ? hue - hi
+ : hue;
+}
+
+float3 RgbToHsv(float3 color)
+{
+ const float4 k = float4(0.0f, -1.0f / 3.0f, 2.0f / 3.0f, -1.0f);
+ const float4 p = lerp(float4(color.bg, k.wz), float4(color.gb, k.xy), step(color.b, color.g));
+ const float4 q = lerp(float4(p.xyw, color.r), float4(color.r, p.yzx), step(p.x, color.r));
+ const float d = q.x - min(q.w, q.y);
+ const float e = EPSILON;
+ return float3(abs(q.z + (q.w - q.y) / (6.0f * d + e)), d / (q.x + e), q.x);
+}
+
+float3 HsvToRgb(float3 color)
+{
+ const float4 k = float4(1.0f, 2.0f / 3.0f, 1.0f / 3.0f, 3.0f);
+ const float3 p = abs(frac(color.xxx + k.xyz) * 6.0f - k.www);
+ return color.z * lerp(k.xxx, saturate(p - k.xxx), color.y);
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl
new file mode 100644
index 0000000000..9ae4a2bd68
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli>
+#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli>
+#include <3rdParty/Features/PostProcessing/KelvinToRgb.azsli>
+
+static const float FloatEpsilon = 1.192092896e-07; // 1.0 + FloatEpsilon != 1.0, smallest positive float
+static const float FloatMin = FLOAT_32_MIN; // Min float number that is positive
+static const float FloatMax = FLOAT_32_MAX; // Max float number representable
+
+static const float AcesCcMidGrey = 0.4135884;
+
+ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
+{
+ // get the framebuffer
+ Texture2D m_framebuffer;
+
+ // framebuffer sampler
+ Sampler LinearSampler
+ {
+ MinFilter = Linear;
+ MagFilter = Linear;
+ MipFilter = Linear;
+ AddressU = Clamp;
+ AddressV = Clamp;
+ AddressW = Clamp;
+ };
+
+ float m_colorGradingExposure;
+ float m_colorGradingContrast;
+ float m_colorGradingHueShift;
+ float m_colorGradingPreSaturation;
+ float m_colorFilterIntensity;
+ float m_colorFilterMultiply;
+ float m_whiteBalanceKelvin;
+ float m_whiteBalanceTint;
+ float m_splitToneBalance;
+ float m_splitToneMix;
+ float m_colorGradingPostSaturation;
+ float m_smhShadowsStart;
+ float m_smhShadowsEnd;
+ float m_smhHighlightsStart;
+ float m_smhHighlightsEnd;
+ float m_smhMix;
+
+ float3 m_channelMixingRed;
+ float3 m_channelMixingGreen;
+ float3 m_channelMixingBlue;
+
+ float4 m_colorFilterSwatch;
+ float4 m_splitToneShadowsColor;
+ float4 m_splitToneHighlightsColor;
+
+ float4 m_smhShadowsColor;
+ float4 m_smhMidtonesColor;
+ float4 m_smhHighlightsColor;
+
+ // my color grading output
+ float4 m_color;
+}
+
+float SaturateWithEpsilon(float value)
+{
+ return clamp(value, FloatEpsilon, 1.0f);
+}
+
+// Below are the color grading functions. These expect the frame color to be in ACEScg space.
+// Note that some functions may have some quirks in their implementation and is subject to change.
+float3 ColorGradePostExposure (float3 frameColor, float exposure)
+{
+ frameColor *= pow(2.0f, exposure);
+ return frameColor;
+}
+
+// The contrast equation is performed in ACEScc (logarithmic) color space.
+float3 ColorGradingContrast (float3 frameColor, float midgrey, float amount)
+{
+ const float contrastAdjustment = amount * 0.01f + 1.0f;
+ frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScg, ColorSpaceId::ACEScc);
+ frameColor = (frameColor - midgrey) * contrastAdjustment + midgrey;
+ return frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScc, ColorSpaceId::ACEScg);
+}
+
+// The swatchColor param expects a linear RGB value.
+float3 ColorGradeColorFilter (float3 frameColor, float3 swatchColor, float alpha)
+{
+ swatchColor = TransformColor(swatchColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
+ swatchColor *= pow(2.0f, PassSrg::m_colorFilterIntensity);
+ const float3 frameAdjust = frameColor * swatchColor;
+ return frameColor = lerp(frameColor, frameAdjust, alpha);
+}
+
+float3 ColorGradeHueShift (float3 frameColor, float amount)
+{
+ float3 frameHsv = RgbToHsv(frameColor);
+ const float hue = frameHsv.x + amount;
+ frameHsv.x = RotateHue(hue, 0.0, 1.0);
+ return HsvToRgb(frameHsv);
+}
+
+float3 ColorGradeSaturation (float3 frameColor, float control)
+{
+ const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
+ return (frameColor - vLuminance) * control + vLuminance;
+}
+
+float3 ColorGradeKelvinColorTemp(float3 frameColor, float kelvin)
+{
+ const float3 kColor = TransformColor(KelvinToRgb(kelvin), ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
+ const float luminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
+ const float3 resHsl = RgbToHsl(frameColor.rgb * kColor.rgb); // Apply Kelvin color and convert to HSL
+ return HslToRgb(float3(resHsl.xy, luminance)); // Preserve luminance
+}
+
+// pow(f, e) won't work if f is negative, or may cause inf/NAN.
+float3 NoNanPow(float3 base, float3 power)
+{
+ return pow(max(abs(base), float3(FloatEpsilon, FloatEpsilon, FloatEpsilon)), power);
+}
+
+float3 ColorGradeSplitTone (float3 frameColor, float balance, float mix)
+{
+ float3 frameSplitTone = NoNanPow(frameColor, 1.0 / 2.2);
+ const float t = SaturateWithEpsilon(CalculateLuminance(SaturateWithEpsilon(frameSplitTone), ColorSpaceId::ACEScg) + balance);
+ const float3 shadows = lerp(0.5, PassSrg::m_splitToneShadowsColor.rgb, 1.0 - t);
+ const float3 highlights = lerp(0.5, PassSrg::m_splitToneHighlightsColor.rgb, t);
+ frameSplitTone = BlendMode_SoftLight(frameSplitTone, shadows);
+ frameSplitTone = BlendMode_SoftLight(frameSplitTone, highlights);
+ frameSplitTone = NoNanPow(frameSplitTone, 2.2);
+ return lerp(frameColor.rgb, frameSplitTone.rgb, mix);
+}
+
+float3 ColorGradeChannelMixer (float3 frameColor)
+{
+ return mul(float3x3(PassSrg::m_channelMixingRed.rgb,
+ PassSrg::m_channelMixingGreen.rgb,
+ PassSrg::m_channelMixingBlue.rgb),
+ frameColor);
+}
+
+float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStart, float shadowsEnd,
+ float highlightsStart, float highlightsEnd, float mix,
+ float4 shadowsColor, float4 midtonesColor, float4 highlightsColor)
+{
+ const float3 shadowsColorACEScg = TransformColor(shadowsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
+ const float3 midtonesColorACEScg = TransformColor(midtonesColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
+ const float3 highlightsColorACEScg = TransformColor(highlightsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
+
+ const float cLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
+ const float shadowsWeight = 1.0 - smoothstep(shadowsStart, shadowsEnd, cLuminance);
+ const float highlightsWeight = smoothstep(highlightsStart, highlightsEnd, cLuminance);
+ const float midtonesWeight = 1.0 - shadowsWeight - highlightsWeight;
+
+ const float3 frameSmh = frameColor * shadowsColorACEScg * shadowsWeight +
+ frameColor * midtonesColorACEScg * midtonesWeight +
+ frameColor * highlightsColorACEScg * highlightsWeight;
+ return lerp(frameColor.rgb, frameSmh.rgb, mix);
+}
+
+float3 ColorGrade (float3 frameColor)
+{
+ frameColor = ColorGradePostExposure(frameColor, PassSrg::m_colorGradingExposure);
+ frameColor = ColorGradeKelvinColorTemp(frameColor, PassSrg::m_whiteBalanceKelvin);
+ frameColor = ColorGradingContrast(frameColor, AcesCcMidGrey, PassSrg::m_colorGradingContrast);
+ frameColor = ColorGradeColorFilter(frameColor, PassSrg::m_colorFilterSwatch.rgb,
+ PassSrg::m_colorFilterMultiply);
+ frameColor = max(frameColor, 0.0);
+ frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPreSaturation);
+ frameColor = ColorGradeSplitTone(frameColor, PassSrg::m_splitToneBalance, PassSrg::m_splitToneMix);
+ frameColor = ColorGradeChannelMixer(frameColor);
+ frameColor = max(frameColor, 0.0);
+ frameColor = ColorGradeShadowsMidtonesHighlights(frameColor, PassSrg::m_smhShadowsStart, PassSrg::m_smhShadowsEnd,
+ PassSrg::m_smhHighlightsStart, PassSrg::m_smhHighlightsEnd, PassSrg::m_smhMix,
+ PassSrg::m_smhShadowsColor, PassSrg::m_smhMidtonesColor, PassSrg::m_smhHighlightsColor);
+ frameColor = ColorGradeHueShift(frameColor, PassSrg::m_colorGradingHueShift);
+ frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPostSaturation);
+ return frameColor.rgb;
+}
+
+PSOutput MainPS(VSOutput IN)
+{
+ PSOutput OUT;
+
+ // Fetch the pixel color from the input texture
+ float3 frameColor = PassSrg::m_framebuffer.Sample(PassSrg::LinearSampler, IN.m_texCoord).rgb;
+
+ OUT.m_color.rgb = ColorGrade(frameColor);
+ OUT.m_color.w = 1;
+
+ return OUT;
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.shader
new file mode 100644
index 0000000000..f76f6708b7
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.shader
@@ -0,0 +1,22 @@
+{
+ "Source" : "HDRColorGrading",
+
+ "DepthStencilState" : {
+ "Depth" : { "Enable" : false }
+ },
+
+ "ProgramSettings":
+ {
+ "EntryPoints":
+ [
+ {
+ "name": "MainVS",
+ "type": "Vertex"
+ },
+ {
+ "name": "MainPS",
+ "type": "Fragment"
+ }
+ ]
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
index 8435625833..c8f99cdb24 100644
--- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
+++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
@@ -86,6 +86,7 @@ set(FILES
Passes/CascadedShadowmaps.pass
Passes/CheckerboardResolveColor.pass
Passes/CheckerboardResolveDepth.pass
+ Passes/HDRColorGrading.pass
Passes/ContrastAdaptiveSharpening.pass
Passes/ConvertToAcescg.pass
Passes/DebugOverlayParent.pass
@@ -221,6 +222,8 @@ set(FILES
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_AcesCg.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_Srgb.azsli
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/Srgb_To_LinearSrgb.azsli
+ ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli
+ ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli
ShaderLib/Atom/Features/CoreLights/PhotometricValue.azsli
ShaderLib/Atom/Features/Decals/DecalTextureUtil.azsli
ShaderLib/Atom/Features/LightCulling/LightCullingShared.azsli
@@ -286,6 +289,9 @@ set(FILES
ShaderLib/Atom/Features/Shadow/Shadow.azsli
ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli
ShaderLib/Atom/Features/Vertex/VertexHelper.azsli
+ ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli
+ ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli
+ ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli
ShaderResourceGroups/SceneSrg.azsli
ShaderResourceGroups/SceneSrgAll.azsli
ShaderResourceGroups/ViewSrg.azsli
@@ -392,6 +398,8 @@ set(FILES
Shaders/PostProcessing/FastDepthAwareBlurVer.shader
Shaders/PostProcessing/FullscreenCopy.azsl
Shaders/PostProcessing/FullscreenCopy.shader
+ Shaders/PostProcessing/HDRColorGrading.azsl
+ Shaders/PostProcessing/HDRColorGrading.shader
Shaders/PostProcessing/LookModificationTransform.azsl
Shaders/PostProcessing/LookModificationTransform.shader
Shaders/PostProcessing/LuminanceHeatmap.azsl