Merge pull request #4618 from aws-lumberyard-dev/Atom/EditorColorGrading
Implement LUT Generation Pass and hook up into Editormonroegm-disable-blank-issue-2
commit
fa3f3e4285
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -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
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue