Merge pull request #4618 from aws-lumberyard-dev/Atom/EditorColorGrading

Implement LUT Generation Pass and hook up into Editor
monroegm-disable-blank-issue-2
Guthrie Adams 4 years ago committed by GitHub
commit fa3f3e4285
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -73,7 +73,7 @@
},
{
"Name": "m_colorGradingPreSaturation",
"Value": 1.0 // -100 ... 100
"Value": 1.0 // 0 ... 2
},
{
"Name": "m_colorFilterIntensity",
@ -101,7 +101,7 @@
},
{
"Name": "m_colorGradingPostSaturation",
"Value": 1.0 // -100 ... 100
"Value": 1.0 // 0 ... 2
},
{
"Name": "m_smhShadowsStart",

@ -105,6 +105,11 @@
}
]
},
{
"Name": "LutGenerationPass",
"TemplateName": "LutGenerationTemplate",
"Enabled": true
},
{
"Name": "LookModificationTransformPass",
"TemplateName": "LookModificationTransformTemplate",

@ -0,0 +1,47 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "LutGenerationTemplate",
"PassClass": "LutGenerationPass",
"Slots": [
{
"Name": "LutOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"LoadAction": "DontCare"
}
}
],
"ImageAttachments": [
{
"Name": "ColorGradingLut",
"ImageDescriptor": {
"Format": "R32G32B32A32_FLOAT",
"BindFlags": [
"ShaderWrite"
]
}
}
],
"Connections": [
{
"LocalSlot": "LutOutput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "ColorGradingLut"
}
}
],
"PassData": {
"$type": "FullscreenTrianglePassData",
"ShaderAsset": {
"FilePath": "Shaders/ColorGrading/LutGeneration.shader"
}
}
}
}
}

@ -511,7 +511,11 @@
{
"Name": "HDRColorGradingTemplate",
"Path": "Passes/HDRColorGrading.pass"
}
},
{
"Name": "LutGenerationTemplate",
"Path": "Passes/LutGeneration.pass"
}
]
}
}

@ -59,7 +59,7 @@ UNDISCLOSED.
#pragma once
static const float HALF_MAX = 65504.0f;
#include <Atom/Features/PostProcessing/Aces.azsli>
float AcesCcToLinear(float value)
{

@ -0,0 +1,154 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI/Math.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;
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, float colorFilterIntensity)
{
swatchColor = TransformColor(swatchColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
swatchColor *= pow(2.0f, 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 weight,
float3 splitToneShadowsColor,
float3 splitToneHighlightsColor)
{
float3 frameSplitTone = NoNanPow(frameColor, 1.0 / 2.2);
const float t = SaturateWithEpsilon(CalculateLuminance(SaturateWithEpsilon(frameSplitTone), ColorSpaceId::ACEScg) + balance);
const float3 shadows = lerp(0.5, splitToneShadowsColor, 1.0 - t);
const float3 highlights = lerp(0.5, splitToneHighlightsColor, t);
frameSplitTone = BlendMode_SoftLight(frameSplitTone, shadows);
frameSplitTone = BlendMode_SoftLight(frameSplitTone, highlights);
frameSplitTone = NoNanPow(frameSplitTone, 2.2);
return lerp(frameColor.rgb, frameSplitTone.rgb, weight);
}
float3 ColorGradeChannelMixer (
float3 frameColor,
float3 channelMixingRed,
float3 channelMixingGreen,
float3 channelMixingBlue)
{
return mul(float3x3(channelMixingRed,
channelMixingGreen,
channelMixingBlue),
frameColor);
}
float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStart, float shadowsEnd,
float highlightsStart, float highlightsEnd, float weight,
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, weight);
}
// perform color grading in ACEScg space
float3 ColorGrade(float3 frameColor)
{
frameColor = lerp(frameColor, ColorGradePostExposure(frameColor, PassSrg::m_colorGradingExposure), PassSrg::m_colorAdjustmentWeight);
frameColor = lerp(frameColor, ColorGradeKelvinColorTemp(frameColor, PassSrg::m_whiteBalanceKelvin), PassSrg::m_whiteBalanceWeight);
frameColor = lerp(frameColor, ColorGradingContrast(frameColor, AcesCcMidGrey, PassSrg::m_colorGradingContrast), PassSrg::m_colorAdjustmentWeight);
frameColor = lerp(frameColor, ColorGradeColorFilter(frameColor, PassSrg::m_colorFilterSwatch.rgb,
PassSrg::m_colorFilterMultiply, PassSrg::m_colorFilterIntensity), PassSrg::m_colorAdjustmentWeight);
frameColor = max(frameColor, 0.0);
frameColor = lerp(frameColor, ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPreSaturation), PassSrg::m_colorAdjustmentWeight);
frameColor = ColorGradeSplitTone(frameColor, PassSrg::m_splitToneBalance, PassSrg::m_splitToneWeight,
PassSrg::m_splitToneShadowsColor, PassSrg::m_splitToneHighlightsColor);
frameColor = ColorGradeChannelMixer(frameColor, PassSrg::m_channelMixingRed, PassSrg::m_channelMixingGreen, PassSrg::m_channelMixingBlue);
frameColor = max(frameColor, 0.0);
frameColor = ColorGradeShadowsMidtonesHighlights(frameColor, PassSrg::m_smhShadowsStart, PassSrg::m_smhShadowsEnd,
PassSrg::m_smhHighlightsStart, PassSrg::m_smhHighlightsEnd, PassSrg::m_smhWeight,
PassSrg::m_smhShadowsColor, PassSrg::m_smhMidtonesColor, PassSrg::m_smhHighlightsColor);
frameColor = lerp(frameColor, ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPostSaturation), PassSrg::m_finalAdjustmentWeight);
frameColor = lerp(frameColor, ColorGradeHueShift(frameColor, PassSrg::m_colorGradingHueShift), PassSrg::m_finalAdjustmentWeight);
return max(frameColor.rgb, 0.0);
}

@ -0,0 +1,113 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI/Math.azsli>
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/Features/PostProcessing/Aces.azsli>
#include <Atom/Features/PostProcessing/Shapers.azsli>
float3 convert2Dto3DLutCoords(float2 uv, float width, float height)
{
// convert from center pixel uvs to [0,1]
float offset = 1.0/height/2.0;
float scale = 1.0 - offset*2.0;
float2 adjustedUv = float2(uv.x * width, uv.y * height);
float3 coords = float3(adjustedUv.x%height, 0.5 + int(adjustedUv.x/height), adjustedUv.y)/height;
return (coords - offset)/scale;
}
ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
{
// framebuffer sampler
Sampler PointSampler
{
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
int m_lutResolution;
int m_shaperType;
float m_shaperBias;
float m_shaperScale;
float m_colorAdjustmentWeight;
float m_colorGradingExposure;
float m_colorGradingContrast;
float m_colorGradingPreSaturation;
float m_colorFilterIntensity;
float m_colorFilterMultiply;
float4 m_colorFilterSwatch;
float m_whiteBalanceWeight;
float m_whiteBalanceKelvin;
float m_whiteBalanceTint;
float m_splitToneBalance;
float m_splitToneWeight;
float4 m_splitToneShadowsColor;
float4 m_splitToneHighlightsColor;
float m_smhShadowsStart;
float m_smhShadowsEnd;
float m_smhHighlightsStart;
float m_smhHighlightsEnd;
float m_smhWeight;
float4 m_smhShadowsColor;
float4 m_smhMidtonesColor;
float4 m_smhHighlightsColor;
float3 m_channelMixingRed;
float3 m_channelMixingGreen;
float3 m_channelMixingBlue;
float m_finalAdjustmentWeight;
float m_colorGradingPostSaturation;
float m_colorGradingHueShift;
}
#include <Atom/Features/PostProcessing/HDRColorGradingCommon.azsl>
struct PSOutput
{
float4 m_lutOutput : SV_Target0;
};
PSOutput MainPS(VSOutput IN)
{
ShaperType shaperType = (ShaperType)PassSrg::m_shaperType;
int lutResolution = PassSrg::m_lutResolution;
PSOutput OUT;
// baseCoords are from 0-1
float3 baseCoords = convert2Dto3DLutCoords(IN.m_texCoord, lutResolution*lutResolution, lutResolution);
float3 linearColor = ShaperToLinear(baseCoords, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
linearColor = TransformColor(linearColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
float3 gradedColor = ColorGrade(linearColor);
gradedColor = TransformColor(gradedColor, ColorSpaceId::ACEScg, ColorSpaceId::LinearSRGB);
// Bring back coordinates into 0-1
float3 shapedColor = LinearToShaper(gradedColor, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
shapedColor = saturate(shapedColor);
OUT.m_lutOutput = float4(shapedColor, 1.0);
return OUT;
}

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

@ -13,18 +13,6 @@
#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
@ -41,153 +29,42 @@ ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
AddressW = Clamp;
};
float m_colorAdjustmentWeight;
float m_colorGradingExposure;
float m_colorGradingContrast;
float m_colorGradingHueShift;
float m_colorGradingPreSaturation;
float m_colorFilterIntensity;
float m_colorFilterMultiply;
float4 m_colorFilterSwatch;
float m_whiteBalanceWeight;
float m_whiteBalanceKelvin;
float m_whiteBalanceTint;
float m_splitToneBalance;
float m_splitToneWeight;
float m_colorGradingPostSaturation;
float4 m_splitToneShadowsColor;
float4 m_splitToneHighlightsColor;
float m_smhShadowsStart;
float m_smhShadowsEnd;
float m_smhHighlightsStart;
float m_smhHighlightsEnd;
float m_smhWeight;
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;
}
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 weight)
{
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, weight);
}
float3 ColorGradeChannelMixer (float3 frameColor)
{
return mul(float3x3(PassSrg::m_channelMixingRed.rgb,
PassSrg::m_channelMixingGreen.rgb,
PassSrg::m_channelMixingBlue.rgb),
frameColor);
}
float3 m_channelMixingRed;
float3 m_channelMixingGreen;
float3 m_channelMixingBlue;
float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStart, float shadowsEnd,
float highlightsStart, float highlightsEnd, float weight,
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, weight);
float m_finalAdjustmentWeight;
float m_colorGradingPostSaturation;
float m_colorGradingHueShift;
}
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_splitToneWeight);
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_smhWeight,
PassSrg::m_smhShadowsColor, PassSrg::m_smhMidtonesColor, PassSrg::m_smhHighlightsColor);
frameColor = ColorGradeHueShift(frameColor, PassSrg::m_colorGradingHueShift);
frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPostSaturation);
return frameColor.rgb;
}
#include <Atom/Features/PostProcessing/HDRColorGradingCommon.azsl>
PSOutput MainPS(VSOutput IN)
{

@ -86,7 +86,6 @@ set(FILES
Passes/CascadedShadowmaps.pass
Passes/CheckerboardResolveColor.pass
Passes/CheckerboardResolveDepth.pass
Passes/HDRColorGrading.pass
Passes/ContrastAdaptiveSharpening.pass
Passes/ConvertToAcescg.pass
Passes/DebugOverlayParent.pass
@ -144,6 +143,7 @@ set(FILES
Passes/ForwardSubsurfaceMSAA.pass
Passes/FullscreenCopy.pass
Passes/FullscreenOutputOnly.pass
Passes/HDRColorGrading.pass
Passes/ImGui.pass
Passes/KawaseShadowBlur.pass
Passes/LightAdaptationParent.pass
@ -158,6 +158,7 @@ set(FILES
Passes/LowEndPipeline.pass
Passes/LuminanceHeatmap.pass
Passes/LuminanceHistogramGenerator.pass
Passes/LutGeneration.pass
Passes/MainPipeline.pass
Passes/MainPipelineRenderToTexture.pass
Passes/ThumbnailPipeline.pass
@ -281,6 +282,7 @@ set(FILES
ShaderLib/Atom/Features/PostProcessing/FullscreenVertexUtil.azsli
ShaderLib/Atom/Features/PostProcessing/GlyphData.azsli
ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli
ShaderLib/Atom/Features/PostProcessing/HDRColorGradingCommon.azsl
ShaderLib/Atom/Features/PostProcessing/PostProcessUtil.azsli
ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli
ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli
@ -315,6 +317,8 @@ set(FILES
Shaders/BRDFTexture/BRDFTextureCS.shader
Shaders/Checkerboard/CheckerboardColorResolveCS.azsl
Shaders/Checkerboard/CheckerboardColorResolveCS.shader
Shaders/ColorGrading/LutGeneration.azsl
Shaders/ColorGrading/LutGeneration.shader
Shaders/Depth/DepthPass.azsl
Shaders/Depth/DepthPass.shader
Shaders/Depth/DepthPassTransparentMax.shader

@ -39,6 +39,7 @@ ly_add_target(
Gem::Atom_Utils.Static
Gem::Atom_Feature_Common.Public
Gem::ImGui.imguilib
3rdParty::TIFF
#3rdParty::lux_core # AZ_TRAIT_LUXCORE_SUPPORTED is disabled in every platform, Issue #3915 will remove
RUNTIME_DEPENDENCIES
Gem::ImGui.imguilib
@ -75,6 +76,7 @@ ly_add_target(
FILES_CMAKE
atom_feature_common_shared_files.cmake
../Assets/atom_feature_common_asset_files.cmake
../Editor/atom_feature_common_editor_script_files.cmake
PLATFORM_INCLUDE_FILES
${pal_source_dir}/runtime_dependencies_clients.cmake
INCLUDE_DIRECTORIES

@ -0,0 +1,22 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZ
{
namespace Render
{
enum class LutResolution
{
Lut16x16x16 = 16,
Lut32x32x32 = 32,
Lut64x64x64 = 64
};
}
}

@ -10,28 +10,42 @@
// PARAM(NAME, MEMBER_NAME, DEFAULT_VALUE, ...)
AZ_GFX_BOOL_PARAM(Enabled, m_enabled, false)
AZ_GFX_BOOL_PARAM(GenerateLut, m_generateLut, false)
AZ_GFX_FLOAT_PARAM(ColorAdjustmentWeight, m_colorAdjustmentWeight, 1.0)
AZ_GFX_FLOAT_PARAM(ColorGradingExposure, m_colorGradingExposure, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingContrast, m_colorGradingContrast, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingHueShift, m_colorGradingHueShift, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingPreSaturation, m_colorGradingPreSaturation, 1.0)
AZ_GFX_FLOAT_PARAM(ColorGradingPreSaturation, m_colorGradingPreSaturation, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingFilterIntensity, m_colorGradingFilterIntensity, 1.0)
AZ_GFX_FLOAT_PARAM(ColorGradingFilterMultiply, m_colorGradingFilterMultiply, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingPostSaturation, m_colorGradingPostSaturation, 1.0)
AZ_GFX_VEC3_PARAM(ColorFilterSwatch, m_colorFilterSwatch, AZ::Vector3(1.0f, 0.5f, 0.5f))
AZ_GFX_FLOAT_PARAM(WhiteBalanceWeight, m_whiteBalanceWeight, 0.0)
AZ_GFX_FLOAT_PARAM(WhiteBalanceKelvin, m_whiteBalanceKelvin, 6600.0)
AZ_GFX_FLOAT_PARAM(WhiteBalanceTint, m_whiteBalanceTint, 0.0)
AZ_GFX_FLOAT_PARAM(SplitToneBalance, m_splitToneBalance, 0.0)
AZ_GFX_FLOAT_PARAM(SplitToneWeight, m_splitToneWeight, 0.0)
AZ_GFX_FLOAT_PARAM(SplitToneBalance, m_splitToneBalance, 0.0)
AZ_GFX_VEC3_PARAM(SplitToneShadowsColor, m_splitToneShadowsColor, AZ::Vector3(1.0f, 0.5f, 0.5f))
AZ_GFX_VEC3_PARAM(SplitToneHighlightsColor, m_splitToneHighlightsColor, AZ::Vector3(0.1f, 1.0f, 0.1f))
AZ_GFX_FLOAT_PARAM(SmhWeight, m_smhWeight, 0.0)
AZ_GFX_FLOAT_PARAM(SmhShadowsStart, m_smhShadowsStart, 0.0)
AZ_GFX_FLOAT_PARAM(SmhShadowsEnd, m_smhShadowsEnd, 0.3)
AZ_GFX_FLOAT_PARAM(SmhHighlightsStart, m_smhHighlightsStart, 0.55)
AZ_GFX_FLOAT_PARAM(SmhHighlightsEnd, m_smhHighlightsEnd, 1.0)
AZ_GFX_FLOAT_PARAM(SmhWeight, m_smhWeight, 0.0)
AZ_GFX_VEC3_PARAM(ChannelMixingRed, m_channelMixingRed, AZ::Vector3(1.0f, 0.0f, 0.0f))
AZ_GFX_VEC3_PARAM(ChannelMixingGreen, m_channelMixingGreen, AZ::Vector3(0.0f, 1.0f, 0.0f))
AZ_GFX_VEC3_PARAM(ChannelMixingBlue, m_channelMixingBlue, AZ::Vector3(0.0f, 0.f, 1.0f))
AZ_GFX_VEC3_PARAM(ColorFilterSwatch, m_colorFilterSwatch, AZ::Vector3(1.0f, 0.5f, 0.5f))
AZ_GFX_VEC3_PARAM(SplitToneShadowsColor, m_splitToneShadowsColor, AZ::Vector3(1.0f, 0.5f, 0.5f))
AZ_GFX_VEC3_PARAM(SplitToneHighlightsColor, m_splitToneHighlightsColor, AZ::Vector3(0.1f, 1.0f, 0.1f))
AZ_GFX_VEC3_PARAM(SmhShadowsColor, m_smhShadowsColor, AZ::Vector3(1.0f, 0.25f, 0.25f))
AZ_GFX_VEC3_PARAM(SmhMidtonesColor, m_smhMidtonesColor, AZ::Vector3(0.1f, 0.1f, 1.0f))
AZ_GFX_VEC3_PARAM(SmhHighlightsColor, m_smhHighlightsColor, AZ::Vector3(1.0f, 0.0f, 1.0f))
AZ_GFX_VEC3_PARAM(ChannelMixingRed, m_channelMixingRed, AZ::Vector3(1.0f, 0.0f, 0.0f))
AZ_GFX_VEC3_PARAM(ChannelMixingGreen, m_channelMixingGreen, AZ::Vector3(0.0f, 1.0f, 0.0f))
AZ_GFX_VEC3_PARAM(ChannelMixingBlue, m_channelMixingBlue, AZ::Vector3(0.0f, 0.f, 1.0f))
AZ_GFX_COMMON_PARAM(AZ::Render::LutResolution, LutResolution, m_lutResolution, AZ::Render::LutResolution::Lut16x16x16)
AZ_GFX_COMMON_PARAM(AZ::Render::ShaperPresetType, ShaperPresetType, m_shaperPresetType, AZ::Render::ShaperPresetType::None)
AZ_GFX_COMMON_PARAM(float, CustomMinExposure, m_customMinExposure, -6.5)
AZ_GFX_COMMON_PARAM(float, CustomMaxExposure, m_customMaxExposure, 6.5)
AZ_GFX_FLOAT_PARAM(FinalAdjustmentWeight, m_finalAdjustmentWeight, 1.0)
AZ_GFX_FLOAT_PARAM(ColorGradingPostSaturation, m_colorGradingPostSaturation, 0.0)
AZ_GFX_FLOAT_PARAM(ColorGradingHueShift, m_colorGradingHueShift, 0.0)

@ -12,6 +12,8 @@
#include <AzCore/Math/Vector4.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Component/EntityId.h>
#include <Atom/Feature/ColorGrading/LutResolution.h>
#include <ACES/Aces.h>
namespace AZ
{

@ -0,0 +1,90 @@
/*
* 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 <ColorGrading/LutGenerationPass.h>
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<LutGenerationPass> LutGenerationPass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<LutGenerationPass> pass = aznew LutGenerationPass(descriptor);
return AZStd::move(pass);
}
LutGenerationPass::LutGenerationPass(const RPI::PassDescriptor& descriptor)
: HDRColorGradingPass(descriptor)
{
}
void LutGenerationPass::InitializeInternal()
{
HDRColorGradingPass::InitializeInternal();
m_lutResolutionIndex.Reset();
m_lutShaperTypeIndex.Reset();
m_lutShaperScaleIndex.Reset();
}
void LutGenerationPass::FrameBeginInternal(FramePrepareParams params)
{
const auto* colorGradingSettings = GetHDRColorGradingSettings();
if (colorGradingSettings)
{
m_shaderResourceGroup->SetConstant(m_lutResolutionIndex, colorGradingSettings->GetLutResolution());
auto shaperParams = AcesDisplayMapperFeatureProcessor::GetShaperParameters(
colorGradingSettings->GetShaperPresetType(),
colorGradingSettings->GetCustomMinExposure(),
colorGradingSettings->GetCustomMaxExposure());
m_shaderResourceGroup->SetConstant(m_lutShaperTypeIndex, shaperParams.m_type);
m_shaderResourceGroup->SetConstant(m_lutShaperBiasIndex, shaperParams.m_bias);
m_shaderResourceGroup->SetConstant(m_lutShaperScaleIndex, shaperParams.m_scale);
}
HDRColorGradingPass::FrameBeginInternal(params);
}
void LutGenerationPass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
{
const auto* colorGradingSettings = GetHDRColorGradingSettings();
if (colorGradingSettings)
{
uint32_t lutResolution = aznumeric_cast<uint32_t>(colorGradingSettings->GetLutResolution());
RHI::Size lutSize{ lutResolution * lutResolution, lutResolution, 1 };
RPI::Ptr<RPI::PassAttachment> attachment = FindOwnedAttachment(Name{ "ColorGradingLut" });
RHI::ImageDescriptor& imageDescriptor = attachment->m_descriptor.m_image;
imageDescriptor.m_size = lutSize;
SetViewportScissorFromImageSize(lutSize);
}
HDRColorGradingPass::BuildCommandListInternal(context);
}
bool LutGenerationPass::IsEnabled() const
{
const auto* colorGradingSettings = GetHDRColorGradingSettings();
return colorGradingSettings ? colorGradingSettings->GetGenerateLut() : false;
}
void LutGenerationPass::SetViewportScissorFromImageSize(const RHI::Size& imageSize)
{
const RHI::Viewport viewport(0.f, imageSize.m_width * 1.f, 0.f, imageSize.m_height * 1.f);
const RHI::Scissor scissor(0, 0, imageSize.m_width, imageSize.m_height);
m_viewportState = viewport;
m_scissorState = scissor;
}
} // namespace Render
} // namespace AZ

@ -0,0 +1,54 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <PostProcessing/HDRColorGradingPass.h>
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Reflect/Shader/ShaderVariantKey.h>
#include <PostProcess/ColorGrading/HDRColorGradingSettings.h>
#include <Atom/Feature/DisplayMapper/DisplayMapperFeatureProcessorInterface.h>
namespace AZ
{
namespace Render
{
// Performs color grading on an identity LUT strip
class LutGenerationPass
: public AZ::Render::HDRColorGradingPass
{
public:
AZ_RTTI(LutGenerationPass, "{C21DABA8-B538-4C80-BA18-5B97CC9259E5}", AZ::RPI::FullscreenTrianglePass);
AZ_CLASS_ALLOCATOR(LutGenerationPass, SystemAllocator, 0);
virtual ~LutGenerationPass() = default;
//! Creates a ColorGradingPass
static RPI::Ptr<LutGenerationPass> Create(const RPI::PassDescriptor& descriptor);
protected:
LutGenerationPass(const RPI::PassDescriptor& descriptor);
void InitializeInternal() override;
void FrameBeginInternal(FramePrepareParams params) override;
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
bool IsEnabled() const override;
private:
// Set viewport scissor based on output LUT resolution
void SetViewportScissorFromImageSize(const RHI::Size& imageSize);
RHI::ShaderInputNameIndex m_lutResolutionIndex = "m_lutResolution";
RHI::ShaderInputNameIndex m_lutShaperTypeIndex = "m_shaperType";
RHI::ShaderInputNameIndex m_lutShaperBiasIndex = "m_shaperBias";
RHI::ShaderInputNameIndex m_lutShaperScaleIndex = "m_shaperScale";
};
} // namespace Render
} // namespace AZ

@ -39,6 +39,7 @@
#include <Atom/Feature/AuxGeom/AuxGeomFeatureProcessor.h>
#include <Atom/Feature/Utils/LightingPreset.h>
#include <Atom/Feature/Utils/ModelPreset.h>
#include <ColorGrading/LutGenerationPass.h>
#include <PostProcess/PostProcessFeatureProcessor.h>
#include <PostProcessing/BlendColorGradingLutsPass.h>
#include <PostProcessing/BloomParentPass.h>
@ -230,6 +231,7 @@ namespace AZ
passSystem->AddPassCreator(Name("HDRColorGradingPass"), &HDRColorGradingPass::Create);
passSystem->AddPassCreator(Name("LookModificationCompositePass"), &LookModificationCompositePass::Create);
passSystem->AddPassCreator(Name("LookModificationTransformPass"), &LookModificationPass::Create);
passSystem->AddPassCreator(Name("LutGenerationPass"), &LutGenerationPass::Create);
passSystem->AddPassCreator(Name("SMAAEdgeDetectionPass"), &SMAAEdgeDetectionPass::Create);
passSystem->AddPassCreator(Name("SMAABlendingWeightCalculationPass"), &SMAABlendingWeightCalculationPass::Create);
passSystem->AddPassCreator(Name("SMAANeighborhoodBlendingPass"), &SMAANeighborhoodBlendingPass::Create);

@ -35,6 +35,7 @@
#include <AzCore/Preprocessor/EnumReflectUtils.h>
#include <AzCore/Console/Console.h>
#include <tiffio.h>
namespace AZ
{
namespace Render
@ -110,6 +111,48 @@ namespace AZ
return FrameCaptureOutputResult{FrameCaptureResult::InternalError, "Unable to save frame capture output to '" + outputFilePath + "'"};
}
FrameCaptureOutputResult TiffFrameCaptureOutput(
const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
AZStd::shared_ptr<AZStd::vector<uint8_t>> buffer = readbackResult.m_dataBuffer;
const uint32_t width = readbackResult.m_imageDescriptor.m_size.m_width;
const uint32_t height = readbackResult.m_imageDescriptor.m_size.m_height;
const uint32_t numChannels = AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format);
const uint32_t bytesPerChannel = AZ::RHI::GetFormatSize(readbackResult.m_imageDescriptor.m_format) / numChannels;
const uint32_t bitsPerChannel = bytesPerChannel * 8;
TIFF* out = TIFFOpen(outputFilePath.c_str(), "w");
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, numChannels);
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bitsPerChannel);
TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); // interpret each pixel as a float
size_t pitch = width * numChannels * bytesPerChannel;
AZ_Assert((pitch * height) == buffer->size(), "Image buffer does not match allocated bytes for tiff saving.")
unsigned char* raster = (unsigned char*)_TIFFmalloc((tsize_t)(pitch * height));
memcpy(raster, buffer->data(), pitch * height);
bool success = true;
for (uint32_t h = 0; h < height; ++h)
{
size_t offset = h * pitch;
int err = TIFFWriteScanline(out, raster + offset, h, 0);
if (err < 0)
{
success = false;
break;
}
}
_TIFFfree(raster);
TIFFClose(out);
return success ? FrameCaptureOutputResult{ FrameCaptureResult::Success, AZStd::nullopt }
: FrameCaptureOutputResult{ FrameCaptureResult::InternalError, "Unable to save tif frame capture output to " + outputFilePath };
}
FrameCaptureOutputResult DdsFrameCaptureOutput(
const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
@ -492,6 +535,12 @@ namespace AZ
m_result = ddsFrameCapture.m_result;
m_latestCaptureInfo = ddsFrameCapture.m_errorMessage.value_or("");
}
else if (extension == "tiff" || extension == "tif")
{
const auto tifFrameCapture = TiffFrameCaptureOutput(m_outputFilePath, readbackResult);
m_result = tifFrameCapture.m_result;
m_latestCaptureInfo = tifFrameCapture.m_errorMessage.value_or("");
}
else if (extension == "png")
{
if (readbackResult.m_imageDescriptor.m_format == RHI::Format::R8G8B8A8_UNORM ||

@ -33,6 +33,7 @@ namespace AZ
target->m_enabled = m_enabled;
#define AZ_GFX_BOOL_PARAM(NAME, MEMBER_NAME, DefaultValue) ;
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue) ;
#define AZ_GFX_FLOAT_PARAM(NAME, MEMBER_NAME, DefaultValue) \
{ \
target->Set##NAME(AZ::Lerp(target->MEMBER_NAME, MEMBER_NAME, alpha)); \

@ -13,6 +13,7 @@
#include <Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h>
#include <PostProcess/PostProcessBase.h>
#include <ACES/Aces.h>
namespace AZ
{

@ -32,33 +32,39 @@
{
FullscreenTrianglePass::InitializeInternal();
m_colorAdjustmentWeightIndex.Reset();
m_colorGradingExposureIndex.Reset();
m_colorGradingContrastIndex.Reset();
m_colorGradingHueShiftIndex.Reset();
m_colorGradingPreSaturationIndex.Reset();
m_colorFilterIntensityIndex.Reset();
m_colorFilterMultiplyIndex.Reset();
m_colorFilterSwatchIndex.Reset();
m_whiteBalanceWeightIndex.Reset();
m_whiteBalanceKelvinIndex.Reset();
m_whiteBalanceTintIndex.Reset();
m_splitToneBalanceIndex.Reset();
m_splitToneWeightIndex.Reset();
m_colorGradingPostSaturationIndex.Reset();
m_splitToneShadowsColorIndex.Reset();
m_splitToneHighlightsColorIndex.Reset();
m_smhShadowsStartIndex.Reset();
m_smhShadowsEndIndex.Reset();
m_smhHighlightsStartIndex.Reset();
m_smhHighlightsEndIndex.Reset();
m_smhWeightIndex.Reset();
m_smhShadowsColorIndex.Reset();
m_smhMidtonesColorIndex.Reset();
m_smhHighlightsColorIndex.Reset();
m_channelMixingRedIndex.Reset();
m_channelMixingGreenIndex.Reset();
m_channelMixingBlueIndex.Reset();
m_colorFilterSwatchIndex.Reset();
m_splitToneShadowsColorIndex.Reset();
m_splitToneHighlightsColorIndex.Reset();
m_smhShadowsColorIndex.Reset();
m_smhMidtonesColorIndex.Reset();
m_smhHighlightsColorIndex.Reset();
m_finalAdjustmentWeightIndex.Reset();
m_colorGradingPostSaturationIndex.Reset();
m_colorGradingHueShiftIndex.Reset();
}
void HDRColorGradingPass::FrameBeginInternal(FramePrepareParams params)
@ -79,33 +85,39 @@
const HDRColorGradingSettings* settings = GetHDRColorGradingSettings();
if (settings)
{
m_shaderResourceGroup->SetConstant(m_colorAdjustmentWeightIndex, settings->GetColorAdjustmentWeight());
m_shaderResourceGroup->SetConstant(m_colorGradingExposureIndex, settings->GetColorGradingExposure());
m_shaderResourceGroup->SetConstant(m_colorGradingContrastIndex, settings->GetColorGradingContrast());
m_shaderResourceGroup->SetConstant(m_colorGradingHueShiftIndex, settings->GetColorGradingHueShift());
m_shaderResourceGroup->SetConstant(m_colorGradingPreSaturationIndex, settings->GetColorGradingPreSaturation());
m_shaderResourceGroup->SetConstant(m_colorGradingPreSaturationIndex, settings->GetColorGradingPreSaturation() * 0.01f + 1.0f);
m_shaderResourceGroup->SetConstant(m_colorFilterIntensityIndex, settings->GetColorGradingFilterIntensity());
m_shaderResourceGroup->SetConstant(m_colorFilterMultiplyIndex, settings->GetColorGradingFilterMultiply());
m_shaderResourceGroup->SetConstant(m_colorFilterSwatchIndex, AZ::Vector4(settings->GetColorFilterSwatch()));
m_shaderResourceGroup->SetConstant(m_whiteBalanceWeightIndex, settings->GetWhiteBalanceWeight());
m_shaderResourceGroup->SetConstant(m_whiteBalanceKelvinIndex, settings->GetWhiteBalanceKelvin());
m_shaderResourceGroup->SetConstant(m_whiteBalanceTintIndex, settings->GetWhiteBalanceTint());
m_shaderResourceGroup->SetConstant(m_splitToneBalanceIndex, settings->GetSplitToneBalance());
m_shaderResourceGroup->SetConstant(m_splitToneWeightIndex, settings->GetSplitToneWeight());
m_shaderResourceGroup->SetConstant(m_colorGradingPostSaturationIndex, settings->GetColorGradingPostSaturation());
m_shaderResourceGroup->SetConstant(m_splitToneShadowsColorIndex, AZ::Vector4(settings->GetSplitToneShadowsColor()));
m_shaderResourceGroup->SetConstant(m_splitToneHighlightsColorIndex, AZ::Vector4(settings->GetSplitToneHighlightsColor()));
m_shaderResourceGroup->SetConstant(m_smhShadowsStartIndex, settings->GetSmhShadowsStart());
m_shaderResourceGroup->SetConstant(m_smhShadowsEndIndex, settings->GetSmhShadowsEnd());
m_shaderResourceGroup->SetConstant(m_smhHighlightsStartIndex, settings->GetSmhHighlightsStart());
m_shaderResourceGroup->SetConstant(m_smhHighlightsEndIndex, settings->GetSmhHighlightsEnd());
m_shaderResourceGroup->SetConstant(m_smhWeightIndex, settings->GetSmhWeight());
m_shaderResourceGroup->SetConstant(m_smhShadowsColorIndex, AZ::Vector4(settings->GetSmhShadowsColor()));
m_shaderResourceGroup->SetConstant(m_smhMidtonesColorIndex, AZ::Vector4(settings->GetSmhMidtonesColor()));
m_shaderResourceGroup->SetConstant(m_smhHighlightsColorIndex, AZ::Vector4(settings->GetSmhHighlightsColor()));
m_shaderResourceGroup->SetConstant(m_channelMixingRedIndex, settings->GetChannelMixingRed());
m_shaderResourceGroup->SetConstant(m_channelMixingGreenIndex, settings->GetChannelMixingGreen());
m_shaderResourceGroup->SetConstant(m_channelMixingBlueIndex, settings->GetChannelMixingBlue());
m_shaderResourceGroup->SetConstant(m_colorFilterSwatchIndex, AZ::Vector4(settings->GetColorFilterSwatch()));
m_shaderResourceGroup->SetConstant(m_splitToneShadowsColorIndex, AZ::Vector4(settings->GetSplitToneShadowsColor()));
m_shaderResourceGroup->SetConstant(m_splitToneHighlightsColorIndex, AZ::Vector4(settings->GetSplitToneHighlightsColor()));
m_shaderResourceGroup->SetConstant(m_smhShadowsColorIndex, AZ::Vector4(settings->GetSmhShadowsColor()));
m_shaderResourceGroup->SetConstant(m_smhMidtonesColorIndex, AZ::Vector4(settings->GetSmhMidtonesColor()));
m_shaderResourceGroup->SetConstant(m_smhHighlightsColorIndex, AZ::Vector4(settings->GetSmhHighlightsColor()));
m_shaderResourceGroup->SetConstant(m_finalAdjustmentWeightIndex, settings->GetFinalAdjustmentWeight());
m_shaderResourceGroup->SetConstant(m_colorGradingPostSaturationIndex, settings->GetColorGradingPostSaturation() * 0.01f + 1.0f);
m_shaderResourceGroup->SetConstant(m_colorGradingHueShiftIndex, settings->GetColorGradingHueShift());
}
}

@ -41,37 +41,42 @@ namespace AZ
void FrameBeginInternal(FramePrepareParams params) override;
bool IsEnabled() const override;
private:
const HDRColorGradingSettings* GetHDRColorGradingSettings() const;
void SetSrgConstants();
virtual void SetSrgConstants();
private:
RHI::ShaderInputNameIndex m_colorAdjustmentWeightIndex = "m_colorAdjustmentWeight";
RHI::ShaderInputNameIndex m_colorGradingExposureIndex = "m_colorGradingExposure";
RHI::ShaderInputNameIndex m_colorGradingContrastIndex = "m_colorGradingContrast";
RHI::ShaderInputNameIndex m_colorGradingHueShiftIndex = "m_colorGradingHueShift";
RHI::ShaderInputNameIndex m_colorGradingPreSaturationIndex = "m_colorGradingPreSaturation";
RHI::ShaderInputNameIndex m_colorFilterIntensityIndex = "m_colorFilterIntensity";
RHI::ShaderInputNameIndex m_colorFilterMultiplyIndex = "m_colorFilterMultiply";
RHI::ShaderInputNameIndex m_colorFilterSwatchIndex = "m_colorFilterSwatch";
RHI::ShaderInputNameIndex m_whiteBalanceWeightIndex = "m_whiteBalanceWeight";
RHI::ShaderInputNameIndex m_whiteBalanceKelvinIndex = "m_whiteBalanceKelvin";
RHI::ShaderInputNameIndex m_whiteBalanceTintIndex = "m_whiteBalanceTint";
RHI::ShaderInputNameIndex m_splitToneBalanceIndex = "m_splitToneBalance";
RHI::ShaderInputNameIndex m_splitToneWeightIndex = "m_splitToneWeight";
RHI::ShaderInputNameIndex m_colorGradingPostSaturationIndex = "m_colorGradingPostSaturation";
RHI::ShaderInputNameIndex m_splitToneShadowsColorIndex = "m_splitToneShadowsColor";
RHI::ShaderInputNameIndex m_splitToneHighlightsColorIndex = "m_splitToneHighlightsColor";
RHI::ShaderInputNameIndex m_smhShadowsStartIndex = "m_smhShadowsStart";
RHI::ShaderInputNameIndex m_smhShadowsEndIndex = "m_smhShadowsEnd";
RHI::ShaderInputNameIndex m_smhHighlightsStartIndex = "m_smhHighlightsStart";
RHI::ShaderInputNameIndex m_smhHighlightsEndIndex = "m_smhHighlightsEnd";
RHI::ShaderInputNameIndex m_smhWeightIndex = "m_smhWeight";
RHI::ShaderInputNameIndex m_smhShadowsColorIndex = "m_smhShadowsColor";
RHI::ShaderInputNameIndex m_smhMidtonesColorIndex = "m_smhMidtonesColor";
RHI::ShaderInputNameIndex m_smhHighlightsColorIndex = "m_smhHighlightsColor";
RHI::ShaderInputNameIndex m_channelMixingRedIndex = "m_channelMixingRed";
RHI::ShaderInputNameIndex m_channelMixingGreenIndex = "m_channelMixingGreen";
RHI::ShaderInputNameIndex m_channelMixingBlueIndex = "m_channelMixingBlue";
RHI::ShaderInputNameIndex m_colorFilterSwatchIndex = "m_colorFilterSwatch";
RHI::ShaderInputNameIndex m_splitToneShadowsColorIndex = "m_splitToneShadowsColor";
RHI::ShaderInputNameIndex m_splitToneHighlightsColorIndex = "m_splitToneHighlightsColor";
RHI::ShaderInputNameIndex m_smhShadowsColorIndex = "m_smhShadowsColor";
RHI::ShaderInputNameIndex m_smhMidtonesColorIndex = "m_smhMidtonesColor";
RHI::ShaderInputNameIndex m_smhHighlightsColorIndex = "m_smhHighlightsColor";
RHI::ShaderInputNameIndex m_finalAdjustmentWeightIndex = "m_finalAdjustmentWeight";
RHI::ShaderInputNameIndex m_colorGradingPostSaturationIndex = "m_colorGradingPostSaturation";
RHI::ShaderInputNameIndex m_colorGradingHueShiftIndex = "m_colorGradingHueShift";
};
} // namespace Render
} // namespace AZ

@ -12,6 +12,7 @@ set(FILES
Include/Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h
Include/Atom/Feature/Automation/AtomAutomationBus.h
Include/Atom/Feature/AuxGeom/AuxGeomFeatureProcessor.h
Include/Atom/Feature/ColorGrading/LutResolution.h
Include/Atom/Feature/CoreLights/CoreLightsConstants.h
Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h
Include/Atom/Feature/DisplayMapper/AcesOutputTransformLutPass.h
@ -66,6 +67,8 @@ set(FILES
Source/AuxGeom/DynamicPrimitiveProcessor.h
Source/AuxGeom/FixedShapeProcessor.cpp
Source/AuxGeom/FixedShapeProcessor.h
Source/ColorGrading/LutGenerationPass.cpp
Source/ColorGrading/LutGenerationPass.h
Source/CoreLights/CapsuleLightFeatureProcessor.h
Source/CoreLights/CapsuleLightFeatureProcessor.cpp
Source/CoreLights/CascadedShadowmapsPass.h
@ -212,8 +215,6 @@ set(FILES
Source/PostProcessing/BloomCompositePass.cpp
Source/PostProcessing/BloomParentPass.h
Source/PostProcessing/BloomParentPass.cpp
Source/PostProcessing/HDRColorGradingPass.cpp
Source/PostProcessing/HDRColorGradingPass.h
Source/PostProcessing/DepthOfFieldCompositePass.h
Source/PostProcessing/DepthOfFieldCompositePass.cpp
Source/PostProcessing/DepthOfFieldBokehBlurPass.h
@ -234,6 +235,8 @@ set(FILES
Source/PostProcessing/EyeAdaptationPass.h
Source/PostProcessing/FastDepthAwareBlurPasses.cpp
Source/PostProcessing/FastDepthAwareBlurPasses.h
Source/PostProcessing/HDRColorGradingPass.cpp
Source/PostProcessing/HDRColorGradingPass.h
Source/PostProcessing/LookModificationCompositePass.cpp
Source/PostProcessing/LookModificationCompositePass.h
Source/PostProcessing/LookModificationTransformPass.cpp

@ -0,0 +1,89 @@
"""
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
"""
"""
This script is used by the Editor HDR Color Grading component to use a stored lut asset path
and pass it onto a Look Modification Component.
The HDR Color Grading component will be disabled as it is not compatible with the Look
Modification Component.
"""
import azlmbr
import azlmbr.legacy.general as general
LOOK_MODIFICATION_LUT_PROPERTY_PATH = 'Controller|Configuration|Color Grading LUT'
LOOK_MODIFICATION_ENABLE_PROPERTY_PATH = 'Controller|Configuration|Enable look modification'
COLOR_GRADING_COMPONENT_ID = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["HDR Color Grading"], 0)
LOOK_MODIFICATION_COMPONENT_ID = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Look Modification"], 0)
def disable_hdr_color_grading_component(entity_id):
componentOutcome = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'GetComponentOfType', entity_id, COLOR_GRADING_COMPONENT_ID[0])
if(componentOutcome.IsSuccess()):
azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'DisableComponents', [componentOutcome.GetValue()])
def add_look_modification_component(entity_id):
componentOutcome = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'AddComponentsOfType', entity_id, LOOK_MODIFICATION_COMPONENT_ID)
return componentOutcome.GetValue()[0]
def get_look_modification_component(entity_id):
componentOutcome = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'GetComponentOfType', entity_id, LOOK_MODIFICATION_COMPONENT_ID[0])
if componentOutcome.IsSuccess():
return componentOutcome.GetValue()
else:
return None
def activate_look_modification_lut(look_modification_component, asset_relative_path):
print(asset_relative_path)
asset_id = azlmbr.asset.AssetCatalogRequestBus(
azlmbr.bus.Broadcast,
'GetAssetIdByPath',
asset_relative_path,
azlmbr.math.Uuid(),
False
)
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
look_modification_component,
LOOK_MODIFICATION_LUT_PROPERTY_PATH,
asset_id
)
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
look_modification_component,
LOOK_MODIFICATION_ENABLE_PROPERTY_PATH,
True
)
def activate_lut_asset(entity_id, asset_relative_path):
disable_hdr_color_grading_component(entity_id)
look_modification_component = get_look_modification_component(entity_id)
if not look_modification_component:
look_modification_component = add_look_modification_component(entity_id)
general.idle_wait_frames(5)
if look_modification_component:
activate_look_modification_lut(look_modification_component, asset_relative_path)
if __name__ == "__main__":
parser=argparse.ArgumentParser()
parser.add_argument('--entityName', type=str, required=True, help='Entity ID to manage')
parser.add_argument('--assetRelativePath', type=str, required=True, help='Lut asset relative path to activate')
args=parser.parse_args()
# Get the entity id
searchFilter = azlmbr.entity.SearchFilter()
searchFilter.names = [args.entityName]
entityIdList = azlmbr.entity.SearchBus(azlmbr.bus.Broadcast, 'SearchEntities', searchFilter)
for entityId in entityIdList:
activate_lut_asset(entityId, args.assetRelativePath)

@ -0,0 +1,63 @@
# coding:utf-8
#!/usr/bin/python
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import numpy as np
import logging as _logging
from ColorGrading import get_uv_coord
# ------------------------------------------------------------------------
_MODULENAME = 'ColorGrading.azasset_converter_utils'
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Initializing: {0}.'.format({_MODULENAME}))
# ------------------------------------------------------------------------
""" Utility functions for generating LUT azassets """
def generate_lut_values(image_spec, image_buffer):
lut_size = image_spec.height
lut_intervals = []
lut_values = []
# First line contains the vertex intervals
dv = 1023.0 / float(lut_size-1)
for i in range(lut_size):
lut_intervals.append(np.uint16(dv * i))
# Texels are in R G B per line with indices increasing first with blue, then green, and then red.
for r in range(lut_size):
for g in range(lut_size):
for b in range(lut_size):
uv = get_uv_coord(lut_size, r, g, b)
px = np.array(image_buffer.getpixel(uv[0], uv[1]), dtype='f')
px = np.clip(px, 0.0, 1.0)
px = np.uint16(px * 4095)
lut_values.append(px)
return lut_intervals, lut_values
# To Do: add some input file validation
# If the input file doesn't exist, you'll get a LUT with res of 0 x 0 and result in a math error
#Resolution is 0 x 0
#writing C:\Depot\o3de-engine\Gems\AtomLyIntegration\CommonFeatures\Tools\ColorGrading\TestData\Nuke\HDR\Nuke_Post_grade_LUT.3dl...
#Traceback (most recent call last):
#File "..\..\Editor\Scripts\ColorGrading\exr_to_3dl_azasset.py", line 103, in <module>
#dv = 1023.0 / float(lutSize)
# ZeroDivisionError: float division by zero
def write_3DL(file_path, lut_size, lut_intervals, lut_values):
lut_file_path = f'{file_path}.3dl'
_LOGGER.info(f"Writing {lut_file_path}...")
lut_file = open(lut_file_path, 'w')
for i in range(lut_size):
lut_file.write(f"{lut_intervals[i]} ")
lut_file.write("\n")
for px in lut_values:
lut_file.write(f"{px[0]} {px[1]} {px[2]}\n")
lut_file.close()

@ -46,48 +46,7 @@ from ColorGrading.from_3dl_to_azasset import write_azasset
from ColorGrading import get_uv_coord
def generate_lut_values(image_spec, image_buffer):
lut_size = image_spec.height
lut_intervals = []
lut_values = []
# First line contains the vertex intervals
dv = 1023.0 / float(lut_size-1)
for i in range(lut_size):
lut_intervals.append(np.uint16(dv * i))
# Texels are in R G B per line with indices increasing first with blue, then green, and then red.
for r in range(lut_size):
for g in range(lut_size):
for b in range(lut_size):
uv = get_uv_coord(lut_size, r, g, b)
px = np.array(image_buffer.getpixel(uv[0], uv[1]), dtype='f')
px = np.clip(px, 0.0, 1.0)
px = np.uint16(px * 4095)
lut_values.append(px)
return lut_intervals, lut_values
# To Do: add some input file validation
# If the input file doesn't exist, you'll get a LUT with res of 0 x 0 and result in a math error
#Resolution is 0 x 0
#writing C:\Depot\o3de-engine\Gems\AtomLyIntegration\CommonFeatures\Tools\ColorGrading\TestData\Nuke\HDR\Nuke_Post_grade_LUT.3dl...
#Traceback (most recent call last):
#File "..\..\Editor\Scripts\ColorGrading\exr_to_3dl_azasset.py", line 103, in <module>
#dv = 1023.0 / float(lutSize)
# ZeroDivisionError: float division by zero
def write_3DL(file_path, lut_size, lut_intervals, lut_values):
lut_file_path = f'{file_path}.3dl'
_LOGGER.info(f"Writing {lut_file_path}...")
lut_file = open(lut_file_path, 'w')
for i in range(lut_size):
lut_file.write(f"{lut_intervals[i]} ")
lut_file.write("\n")
for px in lut_values:
lut_file.write(f"{px[0]} {px[1]} {px[2]}\n")
lut_file.close()
from ColorGrading.azasset_converter_utils import generate_lut_values, write_3DL
###########################################################################
# Main Code Block, runs this script as main (testing)

@ -0,0 +1,81 @@
# coding:utf-8
#!/usr/bin/python
#
# 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
#
#
"""
input: a shaped .tiff representing a LUT (for instance coming out of photoshop)
output: a inverse shaped LUT as .tiff
^ as a .3DL (normalized lut file type)
^ as a .azasset (for o3de engine)
"""
import sys
import os
import argparse
import math
import site
import pathlib
from pathlib import Path
import logging as _logging
import numpy as np
# ------------------------------------------------------------------------
_MODULENAME = 'ColorGrading.tiff_to_3dl_azasset'
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Initializing: {0}.'.format({_MODULENAME}))
import ColorGrading.initialize
if ColorGrading.initialize.start():
try:
import OpenImageIO as oiio
pass
except ImportError as e:
_LOGGER.error(f"invalid import: {e}")
sys.exit(1)
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
from ColorGrading.from_3dl_to_azasset import write_azasset
from ColorGrading.azasset_converter_utils import generate_lut_values, write_3DL
###########################################################################
# Main Code Block, runs this script as main (testing)
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
parser=argparse.ArgumentParser()
parser.add_argument('--i', type=str, required=True, help='input file')
parser.add_argument('--o', type=str, required=True, help='output file')
args=parser.parse_args()
# Read input image
image_buffer=oiio.ImageBuf(args.i)
image_spec=image_buffer.spec()
#img = oiio.ImageInput.open(args.i)
#_LOGGER.info(f"Resolution is, x: {img.spec().width} and y: {img.spec().height}")
_LOGGER.info(f"Resolution is, x: {image_buffer.spec().width} and y: {image_buffer.spec().height}")
if image_spec.width != image_spec.height * image_spec.height:
_LOGGER.info(f"invalid input file dimensions. Expect lengthwise LUT with dimension W: s*s X H: s, where s is the size of the LUT")
sys.exit(1)
lut_intervals, lut_values = generate_lut_values(image_spec, image_buffer)
write_3DL(args.o, image_spec.height, lut_intervals, lut_values)
# write_azasset(file_path, lut_intervals, lut_values, azasset_json=AZASSET_LUT)
write_azasset(args.o, lut_intervals, lut_values)
# example from command line
# python % DCCSI_COLORGRADING_SCRIPTS %\lut_helper.py - -i C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\linear_32_LUT.tiff - -op pre - grading - -shaper Log2 - 48nits - -o C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\base_Log2-48nits_32_LUT.exr

@ -0,0 +1,16 @@
#
# 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
#
#
set(FILES
Scripts/ColorGrading/__init__.py
Scripts/ColorGrading/initialize.py
Scripts/ColorGrading/azasset_converter_utils.py
Scripts/ColorGrading/from_3dl_to_azasset.py
Scripts/ColorGrading/tiff_to_3dl_azasset.py
Scripts/ColorGrading/activate_lut_asset.py
)

@ -7,6 +7,10 @@
*/
#include <PostProcess/ColorGrading/EditorHDRColorGradingComponent.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzCore/StringFunc/StringFunc.h>
namespace AZ
{
@ -18,7 +22,10 @@ namespace AZ
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()->Version(1);
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()
->Version(2)
->Field("generatedLut", &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
@ -31,6 +38,20 @@ namespace AZ
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO ATOM-2672][PostFX] need to create page for PostProcessing.
->ClassElement(AZ::Edit::ClassElements::Group, "LUT Generation")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->UIElement(AZ::Edit::UIHandlers::Button, "Generate LUT", "Generates a LUT from the scene's enabled color grading blend.")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Generate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::GenerateLut)
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath, "Generated LUT Path", "Generated LUT Path")
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
->UIElement(AZ::Edit::UIHandlers::Button, "Activate LUT", "Use the generated LUT asset in a Look Modification component")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Activate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::ActivateLut)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
;
editContext->Class<HDRColorGradingComponentController>(
@ -47,6 +68,9 @@ namespace AZ
"Enable HDR color grading.")
->ClassElement(AZ::Edit::ClassElements::Group, "Color Adjustment")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorAdjustmentWeight, "Weight", "Weight of color adjustments")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingExposure, "Exposure", "Exposure Value")
->Attribute(Edit::Attributes::Min, AZStd::numeric_limits<float>::lowest())
->Attribute(Edit::Attributes::Max, AZStd::numeric_limits<float>::max())
@ -66,10 +90,13 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingFilterMultiply, "Filter Multiply", "Filter Multiply Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_colorFilterSwatch, "Color Filter Swatch", "Color Filter Swatch Value")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_colorFilterSwatch, "Filter Swatch", "Color Filter Swatch Value")
->ClassElement(AZ::Edit::ClassElements::Group, "White Balance")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceWeight, "Weight", "Weight of white balance")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceKelvin, "Temperature", "Temperature in Kelvin")
->Attribute(Edit::Attributes::Min, 1000.0f)
->Attribute(Edit::Attributes::Max, 40000.0f)
@ -79,14 +106,14 @@ namespace AZ
->ClassElement(AZ::Edit::ClassElements::Group, "Split Toning")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneWeight, "Split Tone Weight", "Modulates the split toning effect.")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneWeight, "Weight", "Modulates the split toning effect.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneBalance, "Split Tone Balance", "Split Tone Balance Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_splitToneBalance, "Balance", "Split Tone Balance Value")
->Attribute(Edit::Attributes::Min, -1.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneShadowsColor, "Split Tone Shadows Color", "Split Tone Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneHighlightsColor, "Split Tone Highlights Color", "Split Tone Highlights Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneShadowsColor, "Shadows Color", "Split Tone Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_splitToneHighlightsColor, "Highlights Color", "Split Tone Highlights Color")
->ClassElement(AZ::Edit::ClassElements::Group, "Channel Mixing")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
@ -99,33 +126,52 @@ namespace AZ
->ClassElement(AZ::Edit::ClassElements::Group, "Shadow Midtones Highlights")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhWeight, "SMH Weight", "Modulates the SMH effect.")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhWeight, "Weight", "Modulates the SMH effect.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsStart, "SMH Shadows Start", "SMH Shadows Start Value")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsStart, "Shadows Start", "SMH Shadows Start Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsEnd, "SMH Shadows End", "SMH Shadows End Value")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhShadowsEnd, "Shadows End", "SMH Shadows End Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsStart, "SMH Highlights Start", "SMH Highlights Start Value")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsStart, "Highlights Start", "SMH Highlights Start Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsEnd, "SMH Highlights End", "SMH Highlights End Value")
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_smhHighlightsEnd, "Highlights End", "SMH Highlights End Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhShadowsColor, "SMH Shadows Color", "SMH Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhMidtonesColor, "SMH Midtones Color", "SMH Midtones Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhHighlightsColor, "SMH Highlights Color", "SMH Highlights Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhShadowsColor, "Shadows Color", "SMH Shadows Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhMidtonesColor, "Midtones Color", "SMH Midtones Color")
->DataElement(AZ::Edit::UIHandlers::Color, &HDRColorGradingComponentConfig::m_smhHighlightsColor, "Highlights Color", "SMH Highlights Color")
->ClassElement(AZ::Edit::ClassElements::Group, "Final Adjustment")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_finalAdjustmentWeight, "Weight", "Weight of final adjustments")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingHueShift, "Hue Shift", "Hue Shift Value")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_colorGradingPostSaturation, "Post Saturation", "Post Saturation Value")
->Attribute(Edit::Attributes::Min, -100.0f)
->Attribute(Edit::Attributes::Max, 100.0f)
->ClassElement(AZ::Edit::ClassElements::Group, "LUT Generation")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &HDRColorGradingComponentConfig::m_lutResolution, "LUT Resolution", "Resolution of generated LUT")
->EnumAttribute(LutResolution::Lut16x16x16, "16x16x16")
->EnumAttribute(LutResolution::Lut32x32x32, "32x32x32")
->EnumAttribute(LutResolution::Lut64x64x64, "64x64x64")
->DataElement(Edit::UIHandlers::ComboBox, &HDRColorGradingComponentConfig::m_shaperPresetType,
"Shaper Type", "Shaper Type.")
->EnumAttribute(ShaperPresetType::None, "None")
->EnumAttribute(ShaperPresetType::LinearCustomRange, "Linear Custom Range")
->EnumAttribute(ShaperPresetType::Log2_48Nits, "Log2 48 nits")
->EnumAttribute(ShaperPresetType::Log2_1000Nits, "Log2 1000 nits")
->EnumAttribute(ShaperPresetType::Log2_2000Nits, "Log2 2000 nits")
->EnumAttribute(ShaperPresetType::Log2_4000Nits, "Log2 4000 nits")
->EnumAttribute(ShaperPresetType::Log2CustomRange, "Log2 Custom Range")
->EnumAttribute(ShaperPresetType::PqSmpteSt2084, "PQ (SMPTE ST 2084)")
;
}
}
@ -136,6 +182,120 @@ namespace AZ
{
}
void EditorHDRColorGradingComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
if (m_waitOneFrame)
{
m_waitOneFrame = false;
return;
}
const char* LutAttachment = "LutOutput";
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{ "LutGenerationPass" };
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZStd::string lutGenerationCacheFolder;
AzFramework::StringFunc::Path::GetFolderPath(resolvedOutputFilePath, lutGenerationCacheFolder);
AZ::IO::SystemFile::CreateDir(lutGenerationCacheFolder.c_str());
bool startedCapture = false;
AZ::Render::FrameCaptureRequestBus::BroadcastResult(
startedCapture,
&AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachment,
LutGenerationPassHierarchy,
AZStd::string(LutAttachment),
m_currentTiffFilePath,
AZ::RPI::PassAttachmentReadbackOption::Output);
if (startedCapture)
{
AZ::TickBus::Handler::BusDisconnect();
AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect();
}
}
void EditorHDRColorGradingComponent::OnCaptureFinished([[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]]const AZStd::string& info)
{
char resolvedInputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedInputFilePath, AZ_MAX_PATH_LEN);
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentLutFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZStd::string lutGenerationFolder;
AzFramework::StringFunc::Path::GetFolderPath(resolvedOutputFilePath, lutGenerationFolder);
AZ::IO::SystemFile::CreateDir(lutGenerationFolder.c_str());
AZStd::vector<AZStd::string_view> pythonArgs
{
"--i", resolvedInputFilePath,
"--o", resolvedOutputFilePath
};
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
TiffToAzassetPythonScriptPath,
pythonArgs);
m_controller.m_configuration.m_generateLut = false;
m_controller.OnConfigChanged();
m_generatedLutAbsolutePath = resolvedOutputFilePath + AZStd::string(".azasset");
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(
&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh,
AzToolsFramework::PropertyModificationRefreshLevel::Refresh_EntireTree);
AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
}
void EditorHDRColorGradingComponent::GenerateLut()
{
// turn on lut generation pass
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
m_currentTiffFilePath = AZStd::string::format(TempTiffFilePath, uuidString.c_str());
m_currentLutFilePath = "@projectroot@/" + AZStd::string::format(GeneratedLutRelativePath, uuidString.c_str());
m_controller.SetGenerateLut(true);
m_controller.OnConfigChanged();
m_waitOneFrame = true;
AZ::TickBus::Handler::BusConnect();
}
AZ::u32 EditorHDRColorGradingComponent::ActivateLut()
{
using namespace AzFramework::StringFunc::Path;
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, GetEntityId());
AZStd::string filename;
GetFileName(m_generatedLutAbsolutePath.c_str(), filename);
AZStd::string assetRelativePath = "LutGeneration/" + filename + ".azasset";
AZStd::vector<AZStd::string_view> pythonArgs
{
"--entityName", entityName,
"--assetRelativePath", assetRelativePath
};
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
ActivateLutAssetPythonScriptPath,
pythonArgs);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
bool EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings()
{
return !m_generatedLutAbsolutePath.empty();
}
u32 EditorHDRColorGradingComponent::OnConfigurationChanged()
{
m_controller.OnConfigChanged();

@ -8,16 +8,25 @@
#pragma once
#include <AzCore/Component/TickBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentAdapter.h>
#include <Atom/Feature/Utils/FrameCaptureBus.h>
#include <PostProcess/ColorGrading/HDRColorGradingComponent.h>
namespace AZ
{
namespace Render
{
static constexpr const char* const TempTiffFilePath{ "@usercache@/LutGeneration/SavedLut_%s.tiff" };
static constexpr const char* const GeneratedLutRelativePath = { "LutGeneration/SavedLut_%s" };
static constexpr const char* const TiffToAzassetPythonScriptPath{ "@engroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py" };
static constexpr const char* const ActivateLutAssetPythonScriptPath{ "@engroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py" };
class EditorHDRColorGradingComponent final
: public AzToolsFramework::Components::
EditorComponentAdapter<HDRColorGradingComponentController, HDRColorGradingComponent, HDRColorGradingComponentConfig>
, private TickBus::Handler
, private FrameCaptureNotificationBus::Handler
{
public:
using BaseClass = AzToolsFramework::Components::EditorComponentAdapter<HDRColorGradingComponentController, HDRColorGradingComponent, HDRColorGradingComponentConfig>;
@ -30,6 +39,23 @@ namespace AZ
//! EditorRenderComponentAdapter overrides...
AZ::u32 OnConfigurationChanged() override;
private:
// AZ::TickBus overrides ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// FrameCaptureNotificationBus overrides ...
void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override;
void GenerateLut();
AZ::u32 ActivateLut();
bool GetGeneratedLutVisibilitySettings();
bool m_waitOneFrame = false;
AZStd::string m_currentTiffFilePath;
AZStd::string m_currentLutFilePath;
AZStd::string m_generatedLutAbsolutePath;
};
} // namespace Render
} // namespace AZ

@ -52,6 +52,7 @@ namespace AZ
void HDRColorGradingComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("HDRColorGradingService"));
incompatible.push_back(AZ_CRC_CE("LookModificationService"));
}
void HDRColorGradingComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)

@ -49,12 +49,12 @@ namespace AZ
void LookModificationComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("LookModificationService", 0x207b7539));
provided.push_back(AZ_CRC_CE("LookModificationService"));
}
void LookModificationComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("LookModificationService", 0x207b7539));
incompatible.push_back(AZ_CRC("LookModificationService"));
}
void LookModificationComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)

Loading…
Cancel
Save