diff --git a/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass b/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass index adcd43ce83..c043d1e72b 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/HDRColorGrading.pass @@ -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", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass index eec3634045..2347aeb811 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass @@ -105,6 +105,11 @@ } ] }, + { + "Name": "LutGenerationPass", + "TemplateName": "LutGenerationTemplate", + "Enabled": true + }, { "Name": "LookModificationTransformPass", "TemplateName": "LookModificationTransformTemplate", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LutGeneration.pass b/Gems/Atom/Feature/Common/Assets/Passes/LutGeneration.pass new file mode 100644 index 0000000000..4a8735cf7c --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/LutGeneration.pass @@ -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" + } + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset index 76285b00c7..7770b326a6 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset +++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset @@ -511,7 +511,11 @@ { "Name": "HDRColorGradingTemplate", "Path": "Passes/HDRColorGrading.pass" - } + }, + { + "Name": "LutGenerationTemplate", + "Path": "Passes/LutGeneration.pass" + } ] } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli index e84b18c550..1528bdc63e 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli @@ -59,7 +59,7 @@ UNDISCLOSED. #pragma once -static const float HALF_MAX = 65504.0f; +#include float AcesCcToLinear(float value) { diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PostProcessing/HDRColorGradingCommon.azsl b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PostProcessing/HDRColorGradingCommon.azsl new file mode 100644 index 0000000000..099a6394d4 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PostProcessing/HDRColorGradingCommon.azsl @@ -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 +#include +#include +#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli> +#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli> +#include <3rdParty/Features/PostProcessing/KelvinToRgb.azsli> + +static const float FloatEpsilon = 1.192092896e-07; // 1.0 + FloatEpsilon != 1.0, smallest positive float +static const float FloatMin = FLOAT_32_MIN; // Min float number that is positive +static const float FloatMax = FLOAT_32_MAX; // Max float number representable + +static const float AcesCcMidGrey = 0.4135884; + +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); +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.azsl new file mode 100644 index 0000000000..6a76f58519 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.azsl @@ -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 + +#include + +#include + +#include +#include + +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 + +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; +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.shader b/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.shader new file mode 100644 index 0000000000..4e2c83db35 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/ColorGrading/LutGeneration.shader @@ -0,0 +1,22 @@ +{ + "Source" : "LutGeneration", + + "DepthStencilState" : { + "Depth" : { "Enable" : false } + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl index cfa149f0d5..bc33a7e920 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/HDRColorGrading.azsl @@ -13,18 +13,6 @@ #include #include -#include -#include -#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli> -#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli> -#include <3rdParty/Features/PostProcessing/KelvinToRgb.azsli> - -static const float FloatEpsilon = 1.192092896e-07; // 1.0 + FloatEpsilon != 1.0, smallest positive float -static const float FloatMin = FLOAT_32_MIN; // Min float number that is positive -static const float FloatMax = FLOAT_32_MAX; // Max float number representable - -static const float AcesCcMidGrey = 0.4135884; - ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback { // get the framebuffer @@ -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 PSOutput MainPS(VSOutput IN) { diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index cf456b2e41..123e5da7ba 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -86,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 diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index 9c4ffe5b5e..b558be3714 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -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 diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ColorGrading/LutResolution.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ColorGrading/LutResolution.h new file mode 100644 index 0000000000..a33b49b419 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ColorGrading/LutResolution.h @@ -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 + }; + } +} diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingParams.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingParams.inl index 241ba3b5de..c5865b0cfe 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingParams.inl +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingParams.inl @@ -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) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h index 019df206eb..62361b49c1 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.cpp new file mode 100644 index 0000000000..edf26c3eec --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.cpp @@ -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 +#include + +#include +#include + +namespace AZ +{ + namespace Render + { + + RPI::Ptr LutGenerationPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr 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(colorGradingSettings->GetLutResolution()); + RHI::Size lutSize{ lutResolution * lutResolution, lutResolution, 1 }; + + RPI::Ptr 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 diff --git a/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.h b/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.h new file mode 100644 index 0000000000..4a9b358d2f --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ColorGrading/LutGenerationPass.h @@ -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 +#include +#include +#include + +#include +#include + +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 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 diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 22c5f37ff8..4ddf609f41 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index cdcc07b545..8c0360dec2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -35,6 +35,7 @@ #include #include +#include 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> 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 || diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.cpp index 4542b53a15..bc23ea3769 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.cpp @@ -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)); \ diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.h index 2358919c28..4f00192e9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ColorGrading/HDRColorGradingSettings.h @@ -13,6 +13,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.cpp index 62fff6b6fe..88266ba789 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.cpp @@ -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()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.h index e5eaf7db26..dc706b8501 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/HDRColorGradingPass.h @@ -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 diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 18cdc273d2..c875f7c177 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -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 diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py new file mode 100644 index 0000000000..016ad024aa --- /dev/null +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py @@ -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) diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/azasset_converter_utils.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/azasset_converter_utils.py new file mode 100644 index 0000000000..1a2bf41711 --- /dev/null +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/azasset_converter_utils.py @@ -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 + #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() + diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/exr_to_3dl_azasset.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/exr_to_3dl_azasset.py index a3aae9cb94..3186b7498f 100644 --- a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/exr_to_3dl_azasset.py +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/exr_to_3dl_azasset.py @@ -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 - #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) diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py new file mode 100644 index 0000000000..479aa40976 --- /dev/null +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py @@ -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 diff --git a/Gems/Atom/Feature/Common/Editor/atom_feature_common_editor_script_files.cmake b/Gems/Atom/Feature/Common/Editor/atom_feature_common_editor_script_files.cmake new file mode 100644 index 0000000000..c9fa76e7dc --- /dev/null +++ b/Gems/Atom/Feature/Common/Editor/atom_feature_common_editor_script_files.cmake @@ -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 +) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.cpp index 49c8275141..2d8f83a32a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.cpp @@ -7,6 +7,10 @@ */ #include +#include +#include +#include +#include namespace AZ { @@ -18,7 +22,10 @@ namespace AZ if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { - serializeContext->Class()->Version(1); + serializeContext->Class() + ->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( @@ -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::lowest()) ->Attribute(Edit::Attributes::Max, AZStd::numeric_limits::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 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 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 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(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.h index 8eea568e3a..df3842d57a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/EditorHDRColorGradingComponent.h @@ -8,16 +8,25 @@ #pragma once +#include #include +#include #include 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 + , private TickBus::Handler + , private FrameCaptureNotificationBus::Handler { public: using BaseClass = AzToolsFramework::Components::EditorComponentAdapter; @@ -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 diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/HDRColorGradingComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/HDRColorGradingComponentController.cpp index c0f70ab145..fb5e792430 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/HDRColorGradingComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ColorGrading/HDRColorGradingComponentController.cpp @@ -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) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp index 4f321ed8b1..aa8c305e72 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/LookModificationComponentController.cpp @@ -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)