Implement lut resolution.

Signed-off-by: rbarrand <rbarrand@amazon.com>
This commit is contained in:
Robin
2021-10-10 00:41:02 -07:00
committed by rbarrand
parent 2313f912bc
commit b00ee3ff75
16 changed files with 295391 additions and 78 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,74 @@
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):
typeIdsList = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["HDR Color Grading"], 0)
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()
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)
@@ -28,19 +28,39 @@ static const float FloatMax = FLOAT_32_MAX; // Max float number representable
static const float AcesCcMidGrey = 0.4135884;
float3 convert2Dto3DLutCoords(float2 uv)
float3 convert2Dto3DLutCoords(float2 uv, float width, float height)
{
const float height = 16.0;
const float width = 256.0;
//uint adjustedU = uv.x * (height-1)*(height-1);
//uint2 adjustedUv = uint2(uv.x * height*height, uv.y * (height-1));
//uint3 coords = uint3(adjustedUv.x%height, adjustedUv.y, adjustedU/(height-1));
//float3 coords = float3(clamp(((adjustedUv.x-1)%height+1), 0, height), adjustedUv.y, (int)(adjustedUv.x/height));
float2 adjustedUv = float2(uv.x * width, uv.y * height);
float3 coords = float3(adjustedUv.x%height, adjustedUv.x/height, adjustedUv.y);
float2 adjustedUv = float2(uv.x * height*height, uv.y * height);
float3 coords = float3(adjustedUv.x%height, uv.x*height, adjustedUv.y);
return coords/height;
//return float3(uv.x, uv.x, uv.y);
}
enum class LutResolution
{
Lut16x16x16,
Lut32x32x32,
Lut64x64x64
};
ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
{
// framebuffer sampler
Sampler PointSampler
{
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
Sampler LinearSampler
{
MinFilter = Linear;
@@ -53,6 +73,13 @@ ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
// Identity LUTs
Texture3D<float4> m_identityLut16x16x16;
Texture3D<float4> m_identityLut32x32x32;
Texture3D<float4> m_identityLut64x64x64;
int m_lutResolution;
int m_shaperType;
float m_shaperBias;
float m_shaperScale;
float m_colorGradingExposure;
float m_colorGradingContrast;
@@ -125,7 +152,8 @@ float3 ColorGradeHueShift (float3 frameColor, float amount)
float3 ColorGradeSaturation (float3 frameColor, float control)
{
const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::LinearSRGB);
//const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
return (frameColor - vLuminance) * control + vLuminance;
}
@@ -184,20 +212,7 @@ float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStar
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;
}
@@ -207,6 +222,11 @@ struct PSOutput
float4 m_lutOutput : SV_Target0;
};
float3 InverseGamma(float3 color)
{
return pow(color, 2.2);
}
float3 GetSourceLutLinearColor(float3 baseColor, Texture3D<float4> sourceLut, ShaperType shaperType, float shaperBias, float shaperScale)
{
// Convert from reference linearColor to the lutCoordinate for this Lut
@@ -219,38 +239,49 @@ float3 GetSourceLutLinearColor(float3 baseColor, Texture3D<float4> sourceLut, Sh
float3 coordScale = (outputDimensions - 1.0) / outputDimensions;
lutCoord = (lutCoord * coordScale) + coordBias;
float3 lutColor = sourceLut.SampleLevel(PassSrg::LinearSampler, lutCoord, 0).rgb;
float3 lutColor = sourceLut.SampleLevel(PassSrg::PointSampler, lutCoord, 0).rgb;
// Convert to linear
float3 linearColor = ShaperToLinear(lutColor, shaperType, shaperBias, shaperScale);
return linearColor;
}
float3 InverseGamma(float3 color)
{
return pow(color, 2.2);
}
PSOutput MainPS(VSOutput IN)
{
int shaperNum = 0;
ShaperType shaperType = (ShaperType)shaperNum;
//ShaperType shaperType = ShaperType::ShaperLinear;
float bias = 0.0;
float scale = 1.0;
ShaperType shaperType = (ShaperType)PassSrg::m_shaperType;
PSOutput OUT;
float3 baseCoords = convert2Dto3DLutCoords(IN.m_texCoord);
float3 baseColor = ShaperToLinear(baseCoords, shaperType, bias, scale);
float3 lutColor = PassSrg::m_identityLut16x16x16.Sample(PassSrg::LinearSampler, baseColor, 0.0).rgb;
//float3 lutColor = GetSourceLutLinearColor(baseColor, PassSrg::m_identityLut16x16x16, shaperType, bias, scale);
//float3 gradedColor = float4(ColorGrade(lutColor), 1.0);
//float3 finalColor = LinearToShaper(gradedColor, shaperType, bias, scale);
OUT.m_lutOutput = float4(lutColor, 1.0);
uint3 lutDimensions;
float3 baseCoords = float3(0.0, 0.0, 0.0);
float3 lutColor = float3(0.0, 0.0, 0.0);
LutResolution lutRes = (LutResolution)PassSrg::m_lutResolution;
switch(lutRes)
{
case LutResolution::Lut16x16x16:
{
baseCoords = convert2Dto3DLutCoords(IN.m_texCoord, 256, 16);
lutColor = PassSrg::m_identityLut16x16x16.Sample(PassSrg::PointSampler, baseCoords, 0.0).rgb;
//lutColor = TransformColor(lutColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
break;
}
case LutResolution::Lut32x32x32:
{
baseCoords = convert2Dto3DLutCoords(IN.m_texCoord, 1024, 32);
lutColor = PassSrg::m_identityLut32x32x32.Sample(PassSrg::PointSampler, baseCoords, 0.0).rgb;
break;
}
case LutResolution::Lut64x64x64:
{
baseCoords = convert2Dto3DLutCoords(IN.m_texCoord, 4096, 64);
lutColor = PassSrg::m_identityLut64x64x64.Sample(PassSrg::PointSampler, baseCoords, 0.0).rgb;
break;
}
}
//float3 lutColor = ShaperToLinear(baseCoords, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
float3 gradedColor = float4(ColorGrade(lutColor), 1.0);
//float3 finalColor = LinearToShaper(gradedColor, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
gradedColor = TransformColor(gradedColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
OUT.m_lutOutput = float4(gradedColor, 1.0);
return OUT;
}
@@ -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,
Lut32x32x32,
Lut64x64x64
};
}
}
@@ -36,3 +36,7 @@ AZ_GFX_VEC3_PARAM(SplitToneHighlightsColor, m_splitToneHighlightsColor, AZ::Vect
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_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)
@@ -12,6 +12,8 @@
#include <AzCore/Math/Vector4.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Component/EntityId.h>
#include <Atom/Feature/ColorGrading/LutResolution.h>
#include <ACES/Aces.h>
namespace AZ
{
@@ -38,22 +38,19 @@ namespace AZ
AcesDisplayMapperFeatureProcessor* dmfp = scene->GetFeatureProcessor<AcesDisplayMapperFeatureProcessor>();
if (dmfp)
{
// load the image assets
auto assetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(
"lookuptables/lut_identitylinear_16x16x16.azasset", AZ::RPI::AssetUtils::TraceLevel::Error);
AZ_Assert(assetId.IsValid(), "LUT Asset is not valid.");
dmfp->GetLutFromAssetId(m_colorGradingLut, assetId);
for (int i = 0; i < NumLuts; ++i)
{
auto assetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(LutIdentityProductPath[i], AZ::RPI::AssetUtils::TraceLevel::Error);
AZ_Assert(assetId.IsValid(), "LUT Asset is not valid.");
dmfp->GetLutFromAssetId(m_colorGradingLuts[i], assetId);
// set srg image index
m_shaderResourceGroup->SetImageView(m_identityLut16x16x16Index, m_colorGradingLut.m_lutStreamingImage->GetImageView());
m_shaderResourceGroup->SetImageView(m_identityLutIndices[i], m_colorGradingLuts[i].m_lutStreamingImage->GetImageView());
// Get the output image attachment
RPI::Ptr<RPI::PassAttachment> attachment = FindOwnedAttachment(Name{ "ColorGradingLut" });
RHI::ImageDescriptor& imageDescriptor = attachment->m_descriptor.m_image;
imageDescriptor.m_size = RHI::Size(
m_colorGradingLut.m_lutStreamingImage->GetDescriptor().m_size.m_width*m_colorGradingLut.m_lutStreamingImage->GetDescriptor().m_size.m_width,
m_colorGradingLut.m_lutStreamingImage->GetDescriptor().m_size.m_height,
1);
m_colorGradingLutSizes[i] = RHI::Size(
m_colorGradingLuts[i].m_lutStreamingImage->GetDescriptor().m_size.m_width * m_colorGradingLuts[i].m_lutStreamingImage->GetDescriptor().m_size.m_width,
m_colorGradingLuts[i].m_lutStreamingImage->GetDescriptor().m_size.m_height,
1);
}
}
}
@@ -64,27 +61,46 @@ namespace AZ
{
HDRColorGradingPass::InitializeInternal();
m_identityLut16x16x16Index.Reset();
m_identityLut32x32x32Index.Reset();
m_identityLut64x64x64Index.Reset();
//// load the image assets
//DisplayMapperAssetLut m_colorGradingLut;
//auto assetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath("lookuptables/lut_identitylinear_16x16x16.azasset", AZ::RPI::AssetUtils::TraceLevel::Error);
//AcesDisplayMapperFeatureProcessor* dmfp = GetScene()->GetFeatureProcessor<AcesDisplayMapperFeatureProcessor>();
//dmfp->GetLutFromAssetId(m_colorGradingLut, assetId);
//// set srg image index
//m_shaderResourceGroup->SetImageView(m_identityLut16x16x16Index, m_colorGradingLut.m_lutStreamingImage->GetImageView());
for (int i = 0; i < NumLuts; ++i)
{
m_identityLutIndices[i].Reset();
}
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)
{
LutResolution lutResolution = colorGradingSettings->GetLutResolution();
RPI::Ptr<RPI::PassAttachment> attachment = FindOwnedAttachment(Name{ "ColorGradingLut" });
RHI::ImageDescriptor& imageDescriptor = attachment->m_descriptor.m_image;
imageDescriptor.m_size = m_colorGradingLutSizes[(int)lutResolution];
SetViewportScissorFromImageSize(m_colorGradingLutSizes[(int)lutResolution]);
}
HDRColorGradingPass::BuildCommandListInternal(context);
}
@@ -94,6 +110,15 @@ namespace AZ
//return colorGradingSettings ? colorGradingSettings->GetGenerateLut() : false;
return true;
}
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
@@ -24,6 +24,8 @@ namespace AZ
: public AZ::Render::HDRColorGradingPass
{
public:
static const int NumLuts = 3;
AZ_RTTI(LutGenerationPass, "{C21DABA8-B538-4C80-BA18-5B97CC9259E5}", AZ::RPI::FullscreenTrianglePass);
AZ_CLASS_ALLOCATOR(LutGenerationPass, SystemAllocator, 0);
@@ -41,11 +43,25 @@ namespace AZ
void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override;
bool IsEnabled() const override;
private:
RHI::ShaderInputNameIndex m_identityLut16x16x16Index = "m_identityLut16x16x16";
RHI::ShaderInputNameIndex m_identityLut32x32x32Index = "m_identityLut32x32x32";
RHI::ShaderInputNameIndex m_identityLut64x64x64Index = "m_identityLut64x64x64";
// Set viewport scissor based on output LUT resolution
void SetViewportScissorFromImageSize(const RHI::Size& imageSize);
DisplayMapperAssetLut m_colorGradingLut;
DisplayMapperAssetLut m_colorGradingLuts[NumLuts];
RHI::Size m_colorGradingLutSizes[NumLuts];
const char* const LutIdentityProductPath[NumLuts] = {
"lookuptables/lut_identitylinear_16x16x16.azasset",
"lookuptables/lut_identitylinear_32x32x32.azasset",
"lookuptables/lut_identitylinear_64x64x64.azasset" };
RHI::ShaderInputNameIndex m_identityLutIndices[NumLuts] = {
"m_identityLut16x16x16",
"m_identityLut32x32x32",
"m_identityLut64x64x64" };
RHI::ShaderInputNameIndex m_lutResolutionIndex = "m_lutResolution";
RHI::ShaderInputNameIndex m_lutShaperTypeIndex = "m_shaperType";
RHI::ShaderInputNameIndex m_lutShaperBiasIndex = "m_shaperBias";
RHI::ShaderInputNameIndex m_lutShaperScaleIndex = "m_shaperScale";
bool m_isInitialized = false;
};
@@ -33,6 +33,7 @@ namespace AZ
target->m_enabled = m_enabled;
#define AZ_GFX_BOOL_PARAM(NAME, MEMBER_NAME, DefaultValue) ;
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue) ;
#define AZ_GFX_FLOAT_PARAM(NAME, MEMBER_NAME, DefaultValue) \
{ \
target->Set##NAME(AZ::Lerp(target->MEMBER_NAME, MEMBER_NAME, alpha)); \
@@ -13,6 +13,7 @@
#include <Atom/Feature/PostProcess/ColorGrading/HDRColorGradingSettingsInterface.h>
#include <PostProcess/PostProcessBase.h>
#include <ACES/Aces.h>
namespace AZ
{
@@ -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
@@ -0,0 +1,124 @@
# 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 import get_uv_coord
def generate_lut_values(image_spec, image_buffer):
lut_size = image_spec.height
lut_intervals = []
lut_values = []
# First line contains the vertex intervals
dv = 1023.0 / float(lut_size-1)
for i in range(lut_size):
lut_intervals.append(np.uint16(dv * i))
# Texels are in R G B per line with indices increasing first with blue, then green, and then red.
for r in range(lut_size):
for g in range(lut_size):
for b in range(lut_size):
uv = get_uv_coord(lut_size, r, g, b)
px = np.array(image_buffer.getpixel(uv[0], uv[1]), dtype='f')
px = np.clip(px, 0.0, 1.0)
px = np.uint16(px * 4095)
lut_values.append(px)
return lut_intervals, lut_values
# To Do: add some input file validation
# If the input file doesn't exist, you'll get a LUT with res of 0 x 0 and result in a math error
#Resolution is 0 x 0
#writing C:\Depot\o3de-engine\Gems\AtomLyIntegration\CommonFeatures\Tools\ColorGrading\TestData\Nuke\HDR\Nuke_Post_grade_LUT.3dl...
#Traceback (most recent call last):
#File "..\..\Editor\Scripts\ColorGrading\exr_to_3dl_azasset.py", line 103, in <module>
#dv = 1023.0 / float(lutSize)
# ZeroDivisionError: float division by zero
def write_3DL(file_path, lut_size, lut_intervals, lut_values):
lut_file_path = f'{file_path}.3dl'
_LOGGER.info(f"Writing {lut_file_path}...")
lut_file = open(lut_file_path, 'w')
for i in range(lut_size):
lut_file.write(f"{lut_intervals[i]} ")
lut_file.write("\n")
for px in lut_values:
lut_file.write(f"{px[0]} {px[1]} {px[2]}\n")
lut_file.close()
###########################################################################
# 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
@@ -8,6 +8,9 @@
#include <PostProcess/ColorGrading/EditorHDRColorGradingComponent.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzCore/StringFunc/StringFunc.h>
namespace AZ
{
@@ -19,7 +22,10 @@ namespace AZ
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()->Version(1);
serializeContext->Class<EditorHDRColorGradingComponent, BaseClass>()
->Version(2)
->Field("generatedLut", &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
@@ -38,6 +44,14 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Generate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::GenerateLut)
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorHDRColorGradingComponent::m_generatedLutAbsolutePath, "Generated LUT Path", "Generated LUT Path")
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
->UIElement(AZ::Edit::UIHandlers::Button, "Activate LUT", "Use the generated LUT asset in a Look Modification component")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Activate LUT")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorHDRColorGradingComponent::ActivateLut)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings)
;
editContext->Class<HDRColorGradingComponentController>(
@@ -133,6 +147,22 @@ namespace AZ
->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)")
;
}
}
@@ -163,7 +193,8 @@ namespace AZ
startedCapture,
&AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachment,
LutGenerationPassHierarchy,
AZStd::string(LutAttachment), TempTiffFilePath,
AZStd::string(LutAttachment),
m_currentTiffFilePath,
AZ::RPI::PassAttachmentReadbackOption::Output);
m_lutGenerationInProgress = !startedCapture;
@@ -173,9 +204,9 @@ namespace AZ
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(TempTiffFilePath, resolvedInputFilePath, AZ_MAX_PATH_LEN);
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(GeneratedLutFilePath, resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentLutFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
AZStd::vector<AZStd::string_view> pythonArgs
{
@@ -185,11 +216,17 @@ namespace AZ
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
"@devroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py", pythonArgs);
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::TickBus::Handler::BusDisconnect();
AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
}
@@ -197,6 +234,13 @@ namespace AZ
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 = "@devassets@/" + AZStd::string::format(GeneratedLutRelativePath, uuidString.c_str());
m_lutGenerationInProgress = true;
m_controller.m_configuration.m_generateLut = true;
m_controller.OnConfigChanged();
@@ -206,6 +250,35 @@ namespace AZ
AZ::TickBus::Handler::BusConnect();
}
AZ::u32 EditorHDRColorGradingComponent::ActivateLut()
{
using namespace AzFramework::StringFunc::Path;
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, GetEntityId());
AZStd::string filename;
GetFileName(m_generatedLutAbsolutePath.c_str(), filename);
AZStd::string assetRelativePath = "LutGeneration/" + filename + ".azasset";
AZStd::vector<AZStd::string_view> pythonArgs
{
"--entityName", entityName,
"--assetRelativePath", assetRelativePath
};
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
ActivateLutAssetPythonScriptPath,
pythonArgs);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
bool EditorHDRColorGradingComponent::GetGeneratedLutVisibilitySettings()
{
return !m_generatedLutAbsolutePath.empty();
}
u32 EditorHDRColorGradingComponent::OnConfigurationChanged()
{
m_controller.OnConfigChanged();
@@ -17,8 +17,10 @@ namespace AZ
{
namespace Render
{
static const char* const TempTiffFilePath{ "@projectcache@/LutGeneration/SavedLut.tiff" };
static const char* const GeneratedLutFilePath{ "@projectcache@/LutGeneration/SavedLut" };
static const char* const TempTiffFilePath{ "@projectcache@/LutGeneration/SavedLut_%s.tiff" };
static const char* const GeneratedLutRelativePath = { "LutGeneration/SavedLut_%s" };
static const char* const TiffToAzassetPythonScriptPath{ "@devroot@/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/tiff_to_3dl_azasset.py" };
static const char* const ActivateLutAssetPythonScriptPath{ "@devroot@/Gems/Atom/Feature/Common/Assets/Scripts/activate_lut_asset.py" };
class EditorHDRColorGradingComponent final
: public AzToolsFramework::Components::
@@ -50,9 +52,15 @@ namespace AZ
void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override;
void GenerateLut();
AZ::u32 ActivateLut();
bool GetGeneratedLutVisibilitySettings();
AZStd::atomic_bool m_lutGenerationInProgress = false;
int m_frameCounter;
AZStd::string m_currentTiffFilePath;
AZStd::string m_currentLutFilePath;
AZStd::string m_generatedLutAbsolutePath;
};
} // namespace Render
} // namespace AZ
@@ -52,6 +52,7 @@ namespace AZ
void HDRColorGradingComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("HDRColorGradingService"));
incompatible.push_back(AZ_CRC("LookModificationService", 0x207b7539));
}
void HDRColorGradingComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)