Add color grading pass into main pipeline (#4005)

* Add HDR color grading pass and shaders.

Signed-off-by: Robin <rbarrand@amazon.com>

* Improve code quality.

Signed-off-by: Robin <rbarrand@amazon.com>

* Code refactor.

Signed-off-by: Robin <rbarrand@amazon.com>

* Remove color grading pass from light adaptation parent pass due to failing ASV tests. This will be added back later on.

Signed-off-by: Robin <rbarrand@amazon.com>

* Add newline.

Signed-off-by: Robin <rbarrand@amazon.com>

* Correct case for file.

Signed-off-by: Robin <rbarrand@amazon.com>

* Update comment.

Signed-off-by: Robin <rbarrand@amazon.com>

Co-authored-by: Robin <rbarrand@amazon.com>
monroegm-disable-blank-issue-2
hershey5045 4 years ago committed by GitHub
parent bbe437819b
commit b2445ebe0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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
]
}
]
}
}
}
}
}

@ -499,7 +499,11 @@
{
"Name": "KawaseShadowBlurTemplate",
"Path": "Passes/KawaseShadowBlur.pass"
}
},
{
"Name": "HDRColorGradingTemplate",
"Path": "Passes/HDRColorGrading.pass"
}
]
}
}

@ -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;
}

@ -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 <http://unlicense.org/>
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;
}

@ -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 <http://unlicense.org/>
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 channels 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) );
}

@ -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));
}

@ -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)
);
}

@ -8,11 +8,14 @@
#pragma once
#include <Atom/RPI/Math.azsli>
#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);
}

@ -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 <Atom/RPI/Math.azsli>
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PostProcessing/AcesColorSpaceConversion.azsli>
#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<float4> 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;
}

@ -0,0 +1,22 @@
{
"Source" : "HDRColorGrading",
"DepthStencilState" : {
"Depth" : { "Enable" : false }
},
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}

@ -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

Loading…
Cancel
Save