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