diff --git a/TestProjects/HDRP_DXR_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset b/TestProjects/HDRP_DXR_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset index a3f427afb73..ca34101e0bf 100644 --- a/TestProjects/HDRP_DXR_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset +++ b/TestProjects/HDRP_DXR_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -18,7 +18,7 @@ MonoBehaviour: m_RenderingPathDefaultCameraFrameSettings: bitDatas: data1: 136268574097245 - data2: 4539628428617252888 + data2: 4539628437207187480 lodBias: 1 lodBiasMode: 0 lodBiasQualityLevel: 0 @@ -62,9 +62,11 @@ MonoBehaviour: materialQuality: 0 m_RenderPipelineResources: {fileID: 11400000, guid: 3ce144cff5783da45aa5d4fdc2da14b7, type: 2} - m_RenderPipelineRayTracingResources: {fileID: 0} + m_RenderPipelineRayTracingResources: {fileID: 11400000, guid: ba6e7f30e5cffc249a8bf7ee5756c196, + type: 2} beforeTransparentCustomPostProcesses: [] beforePostProcessCustomPostProcesses: [] + afterPostProcessBlursCustomPostProcesses: [] afterPostProcessCustomPostProcesses: [] beforeTAACustomPostProcesses: [] lightLayerName0: @@ -85,6 +87,7 @@ MonoBehaviour: decalLayerName7: shaderVariantLogLevel: 0 lensAttenuationMode: 0 + colorGradingSpace: 1 diffusionProfileSettingsList: - {fileID: 11400000, guid: dd7a918c1bae69f44837b38174e50a61, type: 2} - {fileID: 11400000, guid: d48d38dbecb5bf44db08516376edc733, type: 2} @@ -98,4 +101,15 @@ MonoBehaviour: - {fileID: 11400000, guid: 458d5c32111ea5749a494da813d01275, type: 2} - {fileID: 11400000, guid: 404820c4cf36ad944862fa59c56064f0, type: 2} - {fileID: 11400000, guid: 2384dbf2c1c420f45a792fbc315fbfb1, type: 2} - m_Version: 1 + rendererListCulling: 0 + DLSSProjectId: 000000 + useDLSSCustomProjectId: 0 + supportProbeVolumes: 0 + supportRuntimeDebugDisplay: 1 + apvScenesData: + serializedBounds: [] + serializedHasVolumes: [] + serializedProfiles: [] + serializedBakeSettings: [] + serializedBakingSets: [] + m_Version: 3 diff --git a/TestProjects/HDRP_HybridTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset b/TestProjects/HDRP_HybridTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset new file mode 100644 index 00000000000..cf5bde0c417 --- /dev/null +++ b/TestProjects/HDRP_HybridTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -0,0 +1,102 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 781cc897cf8675041a751163b51f97dd, type: 3} + m_Name: HDRenderPipelineGlobalSettings + m_EditorClassIdentifier: + m_DefaultVolumeProfile: {fileID: 11400000, guid: 582adbd84082fdb4faf7cd4beb1ccd14, + type: 2} + m_LookDevVolumeProfile: {fileID: 0} + m_RenderingPathDefaultCameraFrameSettings: + bitDatas: + data1: 140649441525597 + data2: 4539628434053070872 + lodBias: 1 + lodBiasMode: 0 + lodBiasQualityLevel: 0 + maximumLODLevel: 0 + maximumLODLevelMode: 0 + maximumLODLevelQualityLevel: 0 + sssQualityMode: 0 + sssQualityLevel: 0 + sssCustomSampleBudget: 20 + msaaMode: 1 + materialQuality: 0 + m_RenderingPathDefaultBakedOrCustomReflectionFrameSettings: + bitDatas: + data1: 135310787769117 + data2: 4539628424389459992 + lodBias: 1 + lodBiasMode: 0 + lodBiasQualityLevel: 0 + maximumLODLevel: 0 + maximumLODLevelMode: 0 + maximumLODLevelQualityLevel: 0 + sssQualityMode: 0 + sssQualityLevel: 0 + sssCustomSampleBudget: 20 + msaaMode: 1 + materialQuality: 0 + m_RenderingPathDefaultRealtimeReflectionFrameSettings: + bitDatas: + data1: 140060864290589 + data2: 4539628424389459992 + lodBias: 1 + lodBiasMode: 0 + lodBiasQualityLevel: 0 + maximumLODLevel: 0 + maximumLODLevelMode: 0 + maximumLODLevelQualityLevel: 0 + sssQualityMode: 0 + sssQualityLevel: 0 + sssCustomSampleBudget: 20 + msaaMode: 1 + materialQuality: 0 + m_RenderPipelineResources: {fileID: 11400000, guid: 3ce144cff5783da45aa5d4fdc2da14b7, + type: 2} + m_RenderPipelineRayTracingResources: {fileID: 0} + beforeTransparentCustomPostProcesses: [] + beforePostProcessCustomPostProcesses: [] + afterPostProcessBlursCustomPostProcesses: [] + afterPostProcessCustomPostProcesses: [] + beforeTAACustomPostProcesses: [] + lightLayerName0: Light Layer default + lightLayerName1: Light Layer 1 + lightLayerName2: Light Layer 2 + lightLayerName3: Light Layer 3 + lightLayerName4: Light Layer 4 + lightLayerName5: Light Layer 5 + lightLayerName6: Light Layer 6 + lightLayerName7: Light Layer 7 + decalLayerName0: Decal Layer default + decalLayerName1: Decal Layer 1 + decalLayerName2: Decal Layer 2 + decalLayerName3: Decal Layer 3 + decalLayerName4: Decal Layer 4 + decalLayerName5: Decal Layer 5 + decalLayerName6: Decal Layer 6 + decalLayerName7: Decal Layer 7 + shaderVariantLogLevel: 0 + lensAttenuationMode: 0 + colorGradingSpace: 1 + diffusionProfileSettingsList: [] + rendererListCulling: 0 + DLSSProjectId: 000000 + useDLSSCustomProjectId: 0 + supportProbeVolumes: 0 + supportRuntimeDebugDisplay: 0 + apvScenesData: + serializedBounds: [] + serializedHasVolumes: [] + serializedProfiles: [] + serializedBakeSettings: [] + serializedBakingSets: [] + m_Version: 3 diff --git a/TestProjects/HDRP_RuntimeTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset b/TestProjects/HDRP_RuntimeTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset index 00bb90e34ed..23531ebe4b3 100644 --- a/TestProjects/HDRP_RuntimeTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset +++ b/TestProjects/HDRP_RuntimeTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -86,6 +86,7 @@ MonoBehaviour: decalLayerName7: shaderVariantLogLevel: 0 lensAttenuationMode: 0 + colorGradingSpace: 1 diffusionProfileSettingsList: - {fileID: 11400000, guid: 2384dbf2c1c420f45a792fbc315fbfb1, type: 2} - {fileID: 11400000, guid: 2b7005ba3a4d8474b8cdc34141ad766e, type: 2} diff --git a/TestProjects/HDRP_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset b/TestProjects/HDRP_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset index f2c26454a37..b54429ce313 100644 --- a/TestProjects/HDRP_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset +++ b/TestProjects/HDRP_Tests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -93,6 +93,7 @@ MonoBehaviour: decalLayerName7: Decal Layer 7 shaderVariantLogLevel: 0 lensAttenuationMode: 0 + colorGradingSpace: 1 diffusionProfileSettingsList: - {fileID: 11400000, guid: 802c802428a2d9640a87e821dfcdd9e8, type: 2} - {fileID: 11400000, guid: 09c63d8f96a14884e8efd2f01004f491, type: 2} @@ -114,7 +115,10 @@ MonoBehaviour: useDLSSCustomProjectId: 0 supportProbeVolumes: 0 supportRuntimeDebugDisplay: 0 - apvScenesBounds: + apvScenesData: serializedBounds: [] serializedHasVolumes: [] + serializedProfiles: [] + serializedBakeSettings: [] + serializedBakingSets: [] m_Version: 3 diff --git a/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset b/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset index a7744de4075..89851ddd0ec 100644 --- a/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset +++ b/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -86,6 +86,7 @@ MonoBehaviour: decalLayerName7: Decal Layer 7 shaderVariantLogLevel: 0 lensAttenuationMode: 0 + colorGradingSpace: 1 diffusionProfileSettingsList: - {fileID: 11400000, guid: cbe1ee9036c47b84ba1b8b3dbcde2aff, type: 2} - {fileID: 11400000, guid: 38c0905fbe269274782e939ce4393d85, type: 2} @@ -99,4 +100,5 @@ MonoBehaviour: serializedHasVolumes: [] serializedProfiles: [] serializedBakeSettings: [] + serializedBakingSets: [] m_Version: 3 diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs new file mode 100644 index 00000000000..1cd9d7d11a2 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs @@ -0,0 +1,36 @@ +using UnityEngine.Serialization; + +namespace UnityEngine.Rendering +{ + [GenerateHLSL] + /// + /// The available options for range reduction/tonemapping when outputting to an HDR device. + /// + public enum HDRRangeReduction + { + /// + /// No range reduction. + /// + None, + /// + /// Reinhard tonemapping. + /// + Reinhard, + /// + /// BT2390 Hermite spline EETF range reduction. + /// + BT2390, + /// + /// ACES tonemapping preset for 1000 nits displays. + /// + ACES1000Nits, + /// + /// ACES tonemapping preset for 2000 nits displays. + /// + ACES2000Nits, + /// + /// ACES tonemapping preset for 4000 nits displays. + /// + ACES4000Nits + } +} diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl new file mode 100644 index 00000000000..5f1423e3977 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl @@ -0,0 +1,18 @@ +// +// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead +// + +#ifndef HDROUTPUTDEFINES_CS_HLSL +#define HDROUTPUTDEFINES_CS_HLSL +// +// UnityEngine.Rendering.HDRRangeReduction: static fields +// +#define HDRRANGEREDUCTION_NONE (0) +#define HDRRANGEREDUCTION_REINHARD (1) +#define HDRRANGEREDUCTION_BT2390 (2) +#define HDRRANGEREDUCTION_ACES1000NITS (3) +#define HDRRANGEREDUCTION_ACES2000NITS (4) +#define HDRRANGEREDUCTION_ACES4000NITS (5) + + +#endif diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl.meta b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl.meta new file mode 100644 index 00000000000..bc90d42750c --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 413c288ef05043d4285cf0407f8188b9 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.meta b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.meta new file mode 100644 index 00000000000..8f6cbdf6833 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d568fc1905aef314a9f36afd557bc4f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index 8e602342207..1d16d8fa36e 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -201,6 +201,12 @@ half3 ACEScg_to_unity(half3 x) return x; } +half3 ACEScg_to_Rec2020(half3 x) +{ + half3 xyz = mul(AP1_2_XYZ_MAT, x); + return mul(XYZ_2_REC2020_MAT, xyz); +} + // // ACES Color Space Conversion - ACES to ACEScc // @@ -501,16 +507,19 @@ half segmented_spline_c5_fwd(half x) return pow(10.0, logy); } -half segmented_spline_c9_fwd(half x) +struct SegmentedSplineParams_c9 { - const half coefsLow[10] = { -1.6989700043, -1.6989700043, -1.4779000000, -1.2291000000, -0.8648000000, -0.4480000000, 0.0051800000, 0.4511080334, 0.9113744414, 0.9113744414 }; // coefs for B-spline between minPoint and midPoint (units of log luminance) - const half coefsHigh[10] = { 0.5154386965, 0.8470437783, 1.1358000000, 1.3802000000, 1.5197000000, 1.5985000000, 1.6467000000, 1.6746091357, 1.6878733390, 1.6878733390 }; // coefs for B-spline between midPoint and maxPoint (units of log luminance) - const half2 minPoint = half2(segmented_spline_c5_fwd(0.18 * exp2(-6.5)), 0.02); // {luminance, luminance} linear extension below this - const half2 midPoint = half2(segmented_spline_c5_fwd(0.18), 4.8); // {luminance, luminance} - const half2 maxPoint = half2(segmented_spline_c5_fwd(0.18 * exp2(6.5)), 48.0); // {luminance, luminance} linear extension above this - const half slopeLow = 0.0; // log-log slope of low linear extension - const half slopeHigh = 0.04; // log-log slope of high linear extension + float coefsLow[10]; // coefs for B-spline between minPoint and midPoint (units of log luminance) + float coefsHigh[10]; // coefs for B-spline between midPoint and maxPoint (units of log luminance) + half2 minPoint; // {luminance, luminance} linear extension below this + half2 midPoint; // {luminance, luminance} + half2 maxPoint; // {luminance, luminance} linear extension above this + float slopeLow; // log-log slope of low linear extension + float slopeHigh; // log-log slope of high linear extension +}; +half segmented_spline_c9_fwd(half x, SegmentedSplineParams_c9 params) +{ const int N_KNOTS_LOW = 8; const int N_KNOTS_HIGH = 8; @@ -522,38 +531,114 @@ half segmented_spline_c9_fwd(half x) half logx = log10(xCheck); half logy; - if (logx <= log10(minPoint.x)) + if (logx <= log10(params.minPoint.x)) { - logy = logx * slopeLow + (log10(minPoint.y) - slopeLow * log10(minPoint.x)); + logy = logx * params.slopeLow + (log10(params.minPoint.y) - params.slopeLow * log10(params.minPoint.x)); } - else if ((logx > log10(minPoint.x)) && (logx < log10(midPoint.x))) + else if ((logx > log10(params.minPoint.x)) && (logx < log10(params.midPoint.x))) { - half knot_coord = (N_KNOTS_LOW - 1) * (logx - log10(minPoint.x)) / (log10(midPoint.x) - log10(minPoint.x)); + half knot_coord = (N_KNOTS_LOW - 1) * (logx - log10(params.minPoint.x)) / (log10(params.midPoint.x) - log10(params.minPoint.x)); int j = knot_coord; half t = knot_coord - j; - half3 cf = half3(coefsLow[j], coefsLow[j + 1], coefsLow[j + 2]); + half3 cf = half3(params.coefsLow[j], params.coefsLow[j + 1], params.coefsLow[j + 2]); half3 monomials = half3(t * t, t, 1.0); logy = dot(monomials, mul(M, cf)); } - else if ((logx >= log10(midPoint.x)) && (logx < log10(maxPoint.x))) + else if ((logx >= log10(params.midPoint.x)) && (logx < log10(params.maxPoint.x))) { - half knot_coord = (N_KNOTS_HIGH - 1) * (logx - log10(midPoint.x)) / (log10(maxPoint.x) - log10(midPoint.x)); + half knot_coord = (N_KNOTS_HIGH - 1) * (logx - log10(params.midPoint.x)) / (log10(params.maxPoint.x) - log10(params.midPoint.x)); int j = knot_coord; half t = knot_coord - j; - half3 cf = half3(coefsHigh[j], coefsHigh[j + 1], coefsHigh[j + 2]); + half3 cf = half3(params.coefsHigh[j], params.coefsHigh[j + 1], params.coefsHigh[j + 2]); half3 monomials = half3(t * t, t, 1.0); logy = dot(monomials, mul(M, cf)); } else { //if (logIn >= log10(maxPoint.x)) { - logy = logx * slopeHigh + (log10(maxPoint.y) - slopeHigh * log10(maxPoint.x)); + logy = logx * params.slopeHigh + (log10(params.maxPoint.y) - params.slopeHigh * log10(params.maxPoint.x)); } return pow(10.0, logy); } + +// > 48 Nits from https://github.com/ampas/aces-dev/blob/dev/transforms/ctl/lib/ACESlib.Tonescales.ctl +SegmentedSplineParams_c9 GetSplineParams_ODT48Nits() +{ + const SegmentedSplineParams_c9 ODT_48nits = + { + // coefsLow[10] + { -1.6989700043, -1.6989700043, -1.4779000000, -1.2291000000, -0.8648000000, -0.4480000000, 0.0051800000, 0.4511080334, 0.9113744414, 0.9113744414}, + // coefsHigh[10] + { 0.5154386965, 0.8470437783, 1.1358000000, 1.3802000000, 1.5197000000, 1.5985000000, 1.6467000000, 1.6746091357, 1.6878733390, 1.6878733390 }, + {segmented_spline_c5_fwd(0.18*pow(2.,-6.5)), 0.02}, // minPoint + {segmented_spline_c5_fwd(0.18), 4.8}, // midPoint + {segmented_spline_c5_fwd(0.18*pow(2.,6.5)), 48.0}, // maxPoint + 0.0, // slopeLow + 0.04 // slopeHigh + }; + return ODT_48nits; +} + +SegmentedSplineParams_c9 GetSplineParams_ODT1000Nits() +{ + const SegmentedSplineParams_c9 ODT_1000nits = + { + // coefsLow[10] + { -4.9706219331, -3.0293780669, -2.1262, -1.5105, -1.0578, -0.4668, 0.11938, 0.7088134201, 1.2911865799, 1.2911865799 }, + // coefsHigh[10] + { 0.8089132070, 1.1910867930, 1.5683, 1.9483, 2.3083, 2.6384, 2.8595, 2.9872608805, 3.0127391195, 3.0127391195 }, + {segmented_spline_c5_fwd(0.18*pow(2.,-12.)), 0.0001}, // minPoint + {segmented_spline_c5_fwd(0.18), 10.0}, // midPoint + {segmented_spline_c5_fwd(0.18*pow(2.,10.)), 1000.0}, // maxPoint + 3.0, // slopeLow + 0.06 // slopeHigh + }; + return ODT_1000nits; +} + +SegmentedSplineParams_c9 GetSplineParams_ODT2000Nits() +{ + const SegmentedSplineParams_c9 ODT_2000nits = + { + // coefsLow[10] + { -4.9706219331, -3.0293780669, -2.1262, -1.5105, -1.0578, -0.4668, 0.11938, 0.7088134201, 1.2911865799, 1.2911865799 }, + // coefsHigh[10] + { 0.8019952042, 1.1980047958, 1.5943000000, 1.9973000000, 2.3783000000, 2.7684000000, 3.0515000000, 3.2746293562, 3.3274306351, 3.3274306351 }, + {segmented_spline_c5_fwd(0.18*pow(2.,-12.)), 0.0001}, // minPoint + {segmented_spline_c5_fwd(0.18), 10.0}, // midPoint + {segmented_spline_c5_fwd(0.18*pow(2.,11.)), 2000.0}, // maxPoint + 3.0, // slopeLow + 0.12 // slopeHigh + }; + return ODT_2000nits; +} + +SegmentedSplineParams_c9 GetSplineParams_ODT4000Nits() +{ + const SegmentedSplineParams_c9 ODT_4000nits = + { + // coefsLow[10] + { -4.9706219331, -3.0293780669, -2.1262, -1.5105, -1.0578, -0.4668, 0.11938, 0.7088134201, 1.2911865799, 1.2911865799 }, + // coefsHigh[10] + { 0.7973186613, 1.2026813387, 1.6093000000, 2.0108000000, 2.4148000000, 2.8179000000, 3.1725000000, 3.5344995451, 3.6696204376, 3.6696204376 }, + {segmented_spline_c5_fwd(0.18*pow(2.,-12.)), 0.0001}, // minPoint + {segmented_spline_c5_fwd(0.18), 10.0}, // midPoint + {segmented_spline_c5_fwd(0.18*pow(2.,12.)), 4000.0}, // maxPoint + 3.0, // slopeLow + 0.3 // slopeHigh + }; + return ODT_4000nits; +} + + +half segmented_spline_c9_fwd(half x) +{ + return segmented_spline_c9_fwd(x, GetSplineParams_ODT48Nits()); +} + static const half RRT_GLOW_GAIN = 0.05; static const half RRT_GLOW_MID = 0.08; @@ -601,9 +686,9 @@ half3 RRT(half3 aces) rgbPost.z = segmented_spline_c5_fwd(rgbPre.z); // --- RGB rendering space to OCES --- // - half3 rgbOces = mul(AP1_2_AP0_MAT, rgbPost); + half3 outputVal = mul(AP1_2_AP0_MAT, rgbPost); - return rgbOces; + return outputVal; } // @@ -712,7 +797,7 @@ half3 linear_to_bt1886(half3 x, half gamma, half Lw, half Lb) return V; } -static const half CINEMA_WHITE = 48.0; +static const half CINEMA_WHITE = 48.0f; static const half CINEMA_BLACK = CINEMA_WHITE / 2400.0; static const half ODT_SAT_FACTOR = 0.93; @@ -762,14 +847,16 @@ static const half ODT_SAT_FACTOR = 0.93; // half3 ODT_RGBmonitor_100nits_dim(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -860,14 +947,16 @@ half3 ODT_RGBmonitor_100nits_dim(half3 oces) // half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -970,14 +1059,16 @@ half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) // half3 ODT_Rec709_100nits_dim(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -1062,14 +1153,16 @@ half3 ODT_Rec709_100nits_dim(half3 oces) // half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -1172,14 +1265,16 @@ half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) half3 ODT_Rec2020_100nits_dim(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -1254,14 +1349,16 @@ half3 ODT_Rec2020_100nits_dim(half3 oces) // half3 ODT_P3DCI_48nits(half3 oces) { + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); // Apply the tonescale independently in rendering-space RGB half3 rgbPost; - rgbPost.x = segmented_spline_c9_fwd(rgbPre.x); - rgbPost.y = segmented_spline_c9_fwd(rgbPre.y); - rgbPost.z = segmented_spline_c9_fwd(rgbPre.z); + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_48nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_48nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_48nits); // Scale luminance to linear code value half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); @@ -1320,6 +1417,91 @@ half3 ODT_P3DCI_48nits(half3 oces) return outputCV; } + +// IMPORTANT: This will need transforming to the final output space after unlike the standard ODT. +half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) +{ + const SegmentedSplineParams_c9 ODT_1000nits = GetSplineParams_ODT1000Nits(); + + // OCES to RGB rendering space + half3 rgbPre = mul(AP0_2_AP1_MAT, oces); + + // Apply the tonescale independently in rendering-space RGB + half3 rgbPost; + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_1000nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_1000nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_1000nits); + + // Scale luminance to linear code value + half3 linearCV = Y_2_linCV(rgbPost, ODT_1000nits.maxPoint.y, ODT_1000nits.minPoint.y); + + // Apply desaturation to compensate for luminance difference + //linearCV = mul(ODT_SAT_MAT, linearCV); + linearCV = lerp(dot(linearCV, AP1_RGB2Y).xxx, linearCV, ODT_SAT_FACTOR.xxx); + + // Convert to display primary encoding + // Rendering space RGB to XYZ + half3 XYZ = mul(AP1_2_XYZ_MAT, linearCV); + + // Apply CAT from ACES white point to assumed observer adapted white point + XYZ = mul(D60_2_D65_CAT, XYZ); + + // CIE XYZ to display primaries + linearCV = mul(XYZ_2_REC2020_MAT, XYZ); + + // Handle out-of-gamut values + linearCV = max(linearCV, 0.); + + return linearCV; +} + +half3 ODT_1000nits_ToAP1(half3 oces) +{ + const SegmentedSplineParams_c9 ODT_1000nits = GetSplineParams_ODT1000Nits(); + + // OCES to RGB rendering space + half3 rgbPre = mul(AP0_2_AP1_MAT, oces); + + // Apply the tonescale independently in rendering-space RGB + half3 rgbPost; + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_1000nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_1000nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_1000nits); + + return rgbPost; +} + +half3 ODT_2000nits_ToAP1(half3 oces) +{ + const SegmentedSplineParams_c9 ODT_2000nits = GetSplineParams_ODT2000Nits(); + + // OCES to RGB rendering space + half3 rgbPre = mul(AP0_2_AP1_MAT, oces); + + // Apply the tonescale independently in rendering-space RGB + half3 rgbPost; + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_2000nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_2000nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_2000nits); + + return rgbPost; +} + +half3 ODT_4000nits_ToAP1(half3 oces) +{ + const SegmentedSplineParams_c9 ODT_4000nits = GetSplineParams_ODT4000Nits(); + + // OCES to RGB rendering space + half3 rgbPre = mul(AP0_2_AP1_MAT, oces); + + // Apply the tonescale independently in rendering-space RGB + half3 rgbPost; + rgbPost.x = segmented_spline_c9_fwd(rgbPre.x, ODT_4000nits); + rgbPost.y = segmented_spline_c9_fwd(rgbPre.y, ODT_4000nits); + rgbPost.z = segmented_spline_c9_fwd(rgbPre.z, ODT_4000nits); + + return rgbPost; +} #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3 #pragma warning (enable : 3205) // conversion of larger type to smaller #endif diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index 9c28334eb82..16e95e80a09 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -324,57 +324,33 @@ real RotateHue(real value, real low, real hi) : value; } -// Soft-light blending mode use for split-toning. Works in HDR as long as `blend` is [0;1] which is -// fine for our use case. -float3 SoftLight(float3 base, float3 blend) -{ - float3 r1 = 2.0 * base * blend + base * base * (1.0 - 2.0 * blend); - float3 r2 = sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend); - float3 t = step(0.5, blend); - return r2 * t + (1.0 - t) * r1; -} - -// SMPTE ST.2084 (PQ) transfer functions -// 1.0 = 100nits, 100.0 = 10knits -#define DEFAULT_MAX_PQ 100.0 - -struct ParamsPQ -{ - real N, M; - real C1, C2, C3; -}; - -static const ParamsPQ PQ = +// CIE xyY to CIE 1931 XYZ +float3 xyYtoXYZ(float3 xyY) { - 2610.0 / 4096.0 / 4.0, // N - 2523.0 / 4096.0 * 128.0, // M - 3424.0 / 4096.0, // C1 - 2413.0 / 4096.0 * 32.0, // C2 - 2392.0 / 4096.0 * 32.0, // C3 -}; + float x = xyY.x; + float y = xyY.y; + float Y = xyY.z; -real3 LinearToPQ(real3 x, real maxPQValue) -{ - x = PositivePow(x / maxPQValue, PQ.N); - real3 nd = (PQ.C1 + PQ.C2 * x) / (1.0 + PQ.C3 * x); - return PositivePow(nd, PQ.M); -} + float X = (Y / y) * x; + float Z = (Y / y) * (1.0 - x - y); -real3 LinearToPQ(real3 x) -{ - return LinearToPQ(x, DEFAULT_MAX_PQ); + return float3(X, Y, Z); } -real3 PQToLinear(real3 x, real maxPQValue) +// CIE 1931 XYZ to CIE xy (Y component not returned) +float2 XYZtoxy(float3 XYZ) { - x = PositivePow(x, rcp(PQ.M)); - real3 nd = max(x - PQ.C1, 0.0) / (PQ.C2 - (PQ.C3 * x)); - return PositivePow(nd, rcp(PQ.N)) * maxPQValue; + return XYZ.xy / (dot(XYZ, 1)); } -real3 PQToLinear(real3 x) +// Soft-light blending mode use for split-toning. Works in HDR as long as `blend` is [0;1] which is +// fine for our use case. +float3 SoftLight(float3 base, float3 blend) { - return PQToLinear(x, DEFAULT_MAX_PQ); + float3 r1 = 2.0 * base * blend + base * base * (1.0 - 2.0 * blend); + float3 r2 = sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend); + float3 t = step(0.5, blend); + return r2 * t + (1.0 - t) * r1; } // Alexa LogC converters (El 1000) @@ -647,7 +623,9 @@ real3 CustomTonemap(real3 x, real3 curve, real4 toeSegmentA, real2 toeSegmentB, // Filmic tonemapping (ACES fitting, unless TONEMAPPING_USE_FULL_ACES is set to 1) // Input is ACES2065-1 (AP0 w/ linear encoding) +#ifndef TONEMAPPING_USE_FULL_ACES #define TONEMAPPING_USE_FULL_ACES 0 +#endif float3 AcesTonemap(float3 aces) { diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl new file mode 100644 index 00000000000..5accdda52b5 --- /dev/null +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -0,0 +1,657 @@ +// Important! This file assumes Color.hlsl and ACES.hlsl has been already included. +#ifndef HDROUTPUT_INCLUDED +#define HDROUTPUT_INCLUDED + +#include "Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl" + +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) +#define HDR_OUTPUT +#endif + +// A bit of nomenclature that will be used in the file: +// Gamut: It is the subset of colors that is possible to reproduce by using three specific primary colors. +// Rec709 (ITU-R Recommendation BT709) is a HDTV standard, in our context, we mostly care about its color gamut (https://en.wikipedia.org/wiki/Rec._709). The Rec709 gamut is the same as BT1886 and sRGB. +// Rec2020 (ITU-R Recommendation BT2020) is an UHDTV standard. As above, we mostly reference it w.r.t. the color gamut. (https://en.wikipedia.org/wiki/Rec._2020). Nice property is that all primaries are on the locus. +// DCI-P3 (or just P3): is a gamut used in cinema grading and used by iPhone for example. +// ACEScg: A gamut that is larger than Rec2020. +// ACES2065-1: A gamut that covers the full XYZ space, part of the ACES specs. Mostly used for storage since it is harder to work with than ACEScg. +// WCG: Wide color gamut. This is defined as a color gamut that is wider than the Rec709 one. +// LMS: A color space represented by the response of the three cones of human eye (responsivity peaks Long, Medium, Short) +// OETF (Optical Eelectro Transfer Function): This is a function to goes from optical (linear light) to electro (signal transmitted to the display). +// EOTF (Eelectro Optical Transfer Function): The inverse of the OETF, used by the TV/Monitor. +// EETF (Eelectro-Electro Transfer Function): This is generally just a remapping function, we use the BT2390 EETF to perform range reduction based on the actual display. +// PQ (Perceptual Quantizer): the EOTF used for HDR10 TVs. It works in the range [0, 10000] nits. Important to keep in mind that this represents an absolute intensity and not relative as for SDR. Sometimes this can be referenced as ST2084. As OETF we'll use the inverse of the PQ curve. +// scRGB: a wide color gamut that uses same color space and white point as sRGB, but with much wider coordinates. Used on windows when 16 bit depth is selected. Most of the color space is imaginary colors. Works differently than with PQ. + +// -------------------------------- +// Perceptual Quantizer (PQ) / ST 2084 +// -------------------------------- + +#define MAX_PQ_VALUE 10000 // 10k nits is the maximum supported by the standard. + +#define PQ_N (2610.0f / 4096.0f / 4.0f) +#define PQ_M (2523.0f / 4096.0f * 128.0f) +#define PQ_C1 (3424.0f / 4096.0f) +#define PQ_C2 (2413.0f / 4096.0f * 32.0f) +#define PQ_C3 (2392.0f / 4096.0f * 32.0f) + +float LinearToPQ(float value, float maxPQValue) +{ + value /= maxPQValue; + float Ym1 = PositivePow(value, PQ_N); + float n = (PQ_C1 + PQ_C2 * Ym1); + float d = (1.0f + PQ_C3 * Ym1); + return PositivePow(n / d, PQ_M); +} + +float LinearToPQ(float value) +{ + return LinearToPQ(value, MAX_PQ_VALUE); +} + +float3 LinearToPQ(float3 value, float maxPQValue) +{ + float3 outPQ; + outPQ.x = LinearToPQ(value.x, maxPQValue); + outPQ.y = LinearToPQ(value.y, maxPQValue); + outPQ.z = LinearToPQ(value.z, maxPQValue); + return outPQ; +} + +float3 LinearToPQ(float3 value) +{ + return LinearToPQ(value, MAX_PQ_VALUE); +} + +float PQToLinear(float value) +{ + float Em2 = PositivePow(value, 1.0f / PQ_M); + float X = (max(0.0, Em2 - PQ_C1)) / (PQ_C2 - PQ_C3 * Em2); + return PositivePow(X, 1.0f / PQ_N); +} + +float PQToLinear(float value, float maxPQValue) +{ + return PQToLinear(value) * maxPQValue; +} + +float3 PQToLinear(float3 value, float maxPQValue) +{ + float3 outLinear; + outLinear.x = PQToLinear(value.x, maxPQValue); + outLinear.y = PQToLinear(value.y, maxPQValue); + outLinear.z = PQToLinear(value.z, maxPQValue); + return outLinear; +} + +float3 PQToLinear(float3 value) +{ + float3 outLinear; + outLinear.x = PQToLinear(value.x); + outLinear.y = PQToLinear(value.y); + outLinear.z = PQToLinear(value.z); + return outLinear; +} + + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// Color Space transforms +// -------------------------------- +// As any other space transform, changing color space involves a change of basis and therefore a matrix multiplication. +// Note that Rec2020 and Rec2100 share the same color space. + +float3 RotateRec709ToRec2020(float3 Rec709Input) +{ + static const float3x3 Rec709ToRec2020Mat = float3x3( + + 0.627402, 0.329292, 0.043306, + 0.069095, 0.919544, 0.011360, + 0.016394, 0.088028, 0.895578 + ); + + return mul(Rec709ToRec2020Mat, Rec709Input); +} + +float3 RotateRec2020ToRec709(float3 Rec2020Input) +{ + static const float3x3 Rec2020ToRec709Mat = float3x3( + 1.660496, -0.587656, -0.072840, + -0.124547, 1.132895, -0.008348, + -0.018154, -0.100597, 1.118751 + ); + return mul(Rec2020ToRec709Mat, Rec2020Input); +} + +float3 RotateRec709ToOutputSpace(float3 Rec709Input) +{ +#ifdef HDR_OUTPUT_SCRGB + return Rec709Input; +#else + return RotateRec709ToRec2020(Rec709Input); +#endif +} + +float3 RotateRec2020ToOutputSpace(float3 Rec2020Input) +{ +#ifdef HDR_OUTPUT_SCRGB + return RotateRec2020ToRec709(Rec2020Input); +#else + return Rec2020Input; +#endif +} + +float3 RotateRec2020ToLMS(float3 Rec2020Input) +{ + static const float3x3 Rec2020ToLMSMat = + { + 0.412109375, 0.52392578125, 0.06396484375, + 0.166748046875, 0.720458984375, 0.11279296875, + 0.024169921875, 0.075439453125, 0.900390625 + }; + + return mul(Rec2020ToLMSMat, Rec2020Input); +} + +float3 Rotate709ToLMS(float3 Rec709Input) +{ + static const float3x3 Rec709ToLMSMat = + { + 0.412109375, 0.52392578125, 0.06396484375, + 0.166748046875, 0.720458984375, 0.11279296875, + 0.024169921875, 0.075439453125, 0.900390625 + }; + return mul(Rec709ToLMSMat, Rec709Input); +} + +// Ref: ICtCp Dolby white paper (https://www.dolby.com/us/en/technologies/dolby-vision/ictcp-white-paper.pdf) +float3 RotatePQLMSToICtCp(float3 LMSInput) +{ + static const float3x3 PQLMSToICtCpMat = float3x3( + 0.5f, 0.5f, 0.0f, + 1.613769f, -3.323486f, 1.709716f, + 4.378174f, -4.245605f, -0.1325683f + ); + + return mul(PQLMSToICtCpMat, LMSInput); +} + +float3 RotateLMSToICtCp(float3 lms) +{ + float3 PQLMS = LinearToPQ(max(0.0f, lms)); + return RotatePQLMSToICtCp(PQLMS); +} + +float3 RotateRec2020ToICtCp(float3 Rec2020) +{ + float3 lms = RotateRec2020ToLMS(Rec2020); + float3 PQLMS = LinearToPQ(max(0.0f, lms)); + return RotatePQLMSToICtCp(PQLMS); +} + + + +float3 RotateOutputSpaceToICtCp(float3 inputColor) +{ + // TODO: Do the conversion directly from Rec709 (bake matrix Rec709 -> XYZ -> LMS) +#ifdef HDR_OUTPUT_SCRGB + inputColor = RotateRec709ToRec2020(inputColor); +#endif + return RotateRec2020ToICtCp(inputColor); +} + +float3 RotateLMSToXYZ(float3 LMSInput) +{ + static const float3x3 LMSToXYZMat = float3x3( + 2.07018005669561320f, -1.32645687610302100f, 0.206616006847855170f, + 0.36498825003265756f, 0.68046736285223520f, -0.045421753075853236f, + -0.04959554223893212f, -0.04942116118675749f, 1.187995941732803400f + ); + return mul(LMSToXYZMat, LMSInput); +} + +float3 RotateXYZToRec2020(float3 XYZ) +{ + static const float3x3 XYZToRec2020Mat = float3x3( + 1.71235168f, -0.35487896f, -0.25034135f, + -0.66728621f, 1.61794055f, 0.01495380f, + 0.01763985f, -0.04277060f, 0.94210320f + ); + + return mul(XYZToRec2020Mat, XYZ); +} + +float3 RotateXYZToRec709(float3 XYZ) +{ + return mul(XYZ_2_REC709_MAT, XYZ); +} + +float3 RotateRec709ToXYZ(float3 rgb) +{ + static const float3x3 Rec709ToXYZMat = float3x3( + 0.412391f, 0.357584f, 0.180481, + 0.212639, 0.715169, 0.0721923, + 0.0193308, 0.119195, 0.950532 + ); + return mul(Rec709ToXYZMat, rgb); +} + +float3 RotateRec2020ToXYZ(float3 rgb) +{ + static const float3x3 Rec2020ToXYZMat = float3x3( + 0.638574, 0.144617, 0.167265, + 0.263367, 0.677998, 0.0586353, + 0.0f, 0.0280727, 1.06099 + ); + + return mul(Rec2020ToXYZMat, rgb); +} + +float3 RotateICtCpToPQLMS(float3 ICtCp) +{ + static const float3x3 ICtCpToPQLMSMat = float3x3( + 1.0f, 0.0086051456939815f, 0.1110356044754732f, + 1.0f, -0.0086051456939815f, -0.1110356044754732f, + 1.0f, 0.5600488595626390f, -0.3206374702321221f + ); + + return mul(ICtCpToPQLMSMat, ICtCp); +} + +float3 RotateICtCpToXYZ(float3 ICtCp) +{ + float3 PQLMS = RotateICtCpToPQLMS(ICtCp); + float3 LMS = PQToLinear(PQLMS, MAX_PQ_VALUE); + return RotateLMSToXYZ(LMS); +} + +float3 RotateICtCpToRec2020(float3 ICtCp) +{ + return RotateXYZToRec2020(RotateICtCpToXYZ(ICtCp)); +} + +float3 RotateICtCpToRec709(float3 ICtCp) +{ + return RotateXYZToRec709(RotateICtCpToXYZ(ICtCp)); +} + +float3 RotateICtCpToOutputSpace(float3 ICtCp) +{ +#ifdef HDR_OUTPUT_SCRGB + return RotateICtCpToRec709(ICtCp); +#elif defined(HDR_OUTPUT_REC2020) + return RotateICtCpToRec2020(ICtCp); +#else + return RotateICtCpToRec2020(ICtCp); +#endif + +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// OETFs +// -------------------------------- +// The functions here are OETF, technically for applying the opposite of the PQ curve, we are mapping +// from linear to PQ space as this is what the display expects. +// See this desmos for comparisons https://www.desmos.com/calculator/5jdfc4pgtk +#define PRECISE_PQ 0 +#define ISS_APPROX_PQ 1 +#define GTS_APPROX_PQ 2 + +#define OETF_CHOICE GTS_APPROX_PQ + +// Ref: [Patry 2017] HDR Display Support in Infamous Second Son and Infamous First Light +// Fastest option, but also the least accurate. Behaves well for values up to 1400 nits but then starts diverging. +// IMPORTANT! It requires the input to be scaled from [0 ... 10000] to [0...100]! +float3 PatryApproxLinToPQ(float3 x) +{ + return (x * (x * (x * (x * (x * 533095.76 + 47438306.2) + 29063622.1) + 575216.76) + 383.09104) + 0.000487781) / + (x * (x * (x * (x * 66391357.4 + 81884528.2) + 4182885.1) + 10668.404) + 1.0); +} + +// Ref: [Uchimura and Suzuki 2018] Practical HDR and Wide Color Techniques in Gran Turismo Sport +// Slower than Infamous approx, but more precise ( https://www.desmos.com/calculator/up4wwozghk ) in the full [0... 10 000] range, but still faster than reference +// IMPORTANT! It requires the input to be scaled from [0 ... 10000] to [0...100]! +float3 GTSApproxLinToPQ(float3 inputCol) +{ + float3 k = PositivePow((inputCol * 0.01), PQ_N); + return (3.61972*(1e-8) + k * (0.00102859 + k * (-0.101284 + 2.05784 * k))) / + (0.0495245 + k * (0.135214 + k * (0.772669 + k))); +} + +// IMPORTANT! This wants the input in [0...10000] range, if the method requires scaling, it is done inside this function. +float3 OETF(float3 inputCol) +{ +#ifdef HDR_OUTPUT_SCRGB + // IMPORTANT! This assumes that the maximum nits is always higher or same as 80.0f. Seems like a sensible choice, but revisit if we find weird use cases (just min with the the max nits). + // We need to map the value 1 to 80 nits. + return inputCol / 80.0f; +#else + #if OETF_CHOICE == PRECISE_PQ + return LinearToPQ(inputCol); + #elif OETF_CHOICE == ISS_APPROX_PQ + return PatryApproxLinToPQ(inputCol * 0.01f); + #elif OETF_CHOICE == GTS_APPROX_PQ + return GTSApproxLinToPQ(inputCol * 0.01f); + #endif +#endif + +} + +#define LIN_TO_PQ_FOR_LUT GTS_APPROX_PQ // GTS is close enough https://www.desmos.com/calculator/up4wwozghk +float3 LinearToPQForLUT(float3 inputCol) +{ +#if LIN_TO_PQ_FOR_LUT == PRECISE_PQ + return LinearToPQ(inputCol); +#elif LIN_TO_PQ_FOR_LUT == ISS_APPROX_PQ + return PatryApproxLinToPQ(inputCol * 0.01f); +#elif LIN_TO_PQ_FOR_LUT == GTS_APPROX_PQ + return GTSApproxLinToPQ(inputCol * 0.01f); +#endif +} + + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// Range reduction +// -------------------------------- +// This section of the file concerns the way we map from full range to whatever range the display supports. +// Also note, we always tonemap luminance component only, so we need to reach this point after we converted +// to a format such as ICtCp or YCbCr +// See https://www.desmos.com/calculator/pqc3raolms for plots +#define RANGE_REDUCTION HDRRANGEREDUCTION_BT2390LUMA_ONLY + +// Note this takes x being in [0...10k nits] +float ReinhardTonemap(float x, float peakValue) +{ + float m = MAX_PQ_VALUE * peakValue / (MAX_PQ_VALUE - peakValue); + return x * m / (x + m); +} + +/// BT2390 EETF Helper functions +float T(float A, float Ks) +{ + return (A - Ks) / (1.0f - Ks); +} + +float P(float B, float Ks, float L_max) +{ + float TB2 = T(B, Ks) * T(B, Ks); + float TB3 = TB2 * T(B, Ks); + + return lerp((TB3 - 2 * TB2 + T(B, Ks)), (2.0f * TB3 - 3.0f * TB2 + 1.0f), Ks) + (-2.0f * TB3 + 3.0f*TB2)*L_max; +} + + +// Ref: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf page 21 +// This takes values in [0...10k nits] and it outputs in the same space. PQ conversion outside. +// If we chose this, it can be optimized (a few identity happen with moving between linear and PQ) +float BT2390EETF(float x, float minLimit, float maxLimit) +{ + float E_0 = LinearToPQ(x); + // For the following formulas we are assuming L_B = 0 and L_W = 10000 -- see original paper for full formulation + float E_1 = E_0; + float L_min = LinearToPQ(minLimit); + float L_max = LinearToPQ(maxLimit); + float Ks = 1.5f * L_max - 0.5f; // Knee start + float b = L_min; + + float E_2 = E_1 < Ks ? E_1 : P(E_1, Ks, L_max); + float E3Part = (1.0f - E_2); + float E3Part2 = E3Part * E3Part; + float E_3 = E_2 + b * (E3Part2 * E3Part2); + float E_4 = E_3; // Is like this because PQ(L_W)= 1 and PQ(L_B) = 0 + + return PQToLinear(E_4, MAX_PQ_VALUE); +} + + +float3 PerformRangeReduction(float3 input, float minNits, float maxNits) +{ + float3 ICtCp = RotateOutputSpaceToICtCp(input); // This is in PQ space. + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); +#if RANGE_REDUCTION == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY + linearLuma = ReinhardTonemap(linearLuma, maxNits); +#elif RANGE_REDUCTION == HDRRANGEREDUCTION_BT2390LUMA_ONLY + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); +#endif + ICtCp.x = LinearToPQ(linearLuma); + + + return RotateICtCpToOutputSpace(ICtCp); // This moves back to linear too! +} + +// TODO: This is very ad-hoc and eyeballed on a limited set. Would be nice to find a standard. +float3 DesaturateReducedICtCp(float3 ICtCp, float lumaPre, float maxNits) +{ + float saturationAmount = min(1.0f, ICtCp.x / max(lumaPre, 1e-6f)); // BT2390, but only when getting darker. + //saturationAmount = min(lumaPre / ICtCp.x, ICtCp.x / lumaPre); // Actual BT2390 suggestion + saturationAmount *= saturationAmount; + //saturationAmount = pow(smoothstep(1.0f, 0.4f, ICtCp.x), 0.9f); // A smoothstepp-y function. + ICtCp.yz *= saturationAmount; + return ICtCp; +} + +float LumaRangeReduction(float input, float minNits, float maxNits, int mode) +{ + float output = input; + if (mode == HDRRANGEREDUCTION_REINHARD) + { + output = ReinhardTonemap(input, maxNits); + } + else if (mode == HDRRANGEREDUCTION_BT2390) + { + output = BT2390EETF(input, minNits, maxNits); + } + + return output; +} + +float3 HuePreservingRangeReduction(float3 input, float minNits, float maxNits, int mode) +{ + float3 ICtCp = RotateOutputSpaceToICtCp(input); + + float lumaPreRed = ICtCp.x; + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); + linearLuma = LumaRangeReduction(linearLuma, minNits, maxNits, mode); + ICtCp.x = LinearToPQ(linearLuma); + ICtCp = DesaturateReducedICtCp(ICtCp, lumaPreRed, maxNits); + + return RotateICtCpToOutputSpace(ICtCp); +} + +float3 HueShiftingRangeReduction(float3 input, float minNits, float maxNits, int mode) +{ + float3 hueShiftedResult = input; + if (mode == HDRRANGEREDUCTION_REINHARD) + { + hueShiftedResult.x = ReinhardTonemap(input.x, maxNits); + hueShiftedResult.y = ReinhardTonemap(input.y, maxNits); + hueShiftedResult.z = ReinhardTonemap(input.z, maxNits); + } + else if(mode == HDRRANGEREDUCTION_BT2390) + { + hueShiftedResult.x = BT2390EETF(input.x, minNits, maxNits); + hueShiftedResult.y = BT2390EETF(input.y, minNits, maxNits); + hueShiftedResult.z = BT2390EETF(input.z, minNits, maxNits); + } + return hueShiftedResult; +} + +// Ref "High Dynamic Range color grading and display in Frostbite" [Fry 2017] +float3 FryHuePreserving(float3 input, float minNits, float maxNits, float hueShift, int mode) +{ + float3 ictcp = RotateOutputSpaceToICtCp(input); + + // Hue-preserving range compression requires desaturation in order to achieve a natural look. We adaptively desaturate the input based on its luminance. + float saturationAmount = pow(smoothstep(1.0, 0.3, ictcp.x), 1.3); + float3 col = RotateICtCpToOutputSpace(ictcp * float3(1, saturationAmount.xx)); + + // Only compress luminance starting at a certain point. Dimmer inputs are passed through without modification. + float linearSegmentEnd = 0.25f; + + // Hue-preserving mapping + float maxCol = max(col.x, max(col.y, col.z)); + float mappedMax = maxCol; + if (maxCol > linearSegmentEnd) + { + mappedMax = LumaRangeReduction(maxCol, minNits, maxNits, mode); + } + + float3 compressedHuePreserving = col * mappedMax / maxCol; + + // Non-hue preserving mapping + float3 perChannelCompressed = 0; + perChannelCompressed.x = col.x > linearSegmentEnd ? LumaRangeReduction(col.x, minNits, maxNits, mode) : col.x; + perChannelCompressed.y = col.y > linearSegmentEnd ? LumaRangeReduction(col.y, minNits, maxNits, mode) : col.y; + perChannelCompressed.z = col.z > linearSegmentEnd ? LumaRangeReduction(col.z, minNits, maxNits, mode) : col.z; + + // Combine hue-preserving and non-hue-preserving colors. Absolute hue preservation looks unnatural, as bright colors *appear* to have been hue shifted. + // Actually doing some amount of hue shifting looks more pleasing + col = lerp(perChannelCompressed, compressedHuePreserving, 1-hueShift); + + float3 ictcpMapped = RotateOutputSpaceToICtCp(col); + + // Smoothly ramp off saturation as brightness increases, but keep some even for very bright input + float postCompressionSaturationBoost = 0.3 * smoothstep(1.0, 0.5, ictcp.x); + + // Re-introduce some hue from the pre-compression color. Something similar could be accomplished by delaying the luma-dependent desaturation before range compression. + // Doing it here however does a better job of preserving perceptual luminance of highly saturated colors. Because in the hue-preserving path we only range-compress the max channel, + // saturated colors lose luminance. By desaturating them more aggressively first, compressing, and then re-adding some saturation, we can preserve their brightness to a greater extent. + ictcpMapped.yz = lerp(ictcpMapped.yz, ictcp.yz * ictcpMapped.x / max(1e-3, ictcp.x), postCompressionSaturationBoost); + + col = RotateICtCpToOutputSpace(ictcpMapped); + + return col; + +} + +float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mode, float hueShift) +{ + float3 outputValue = input; + bool reduceLuma = hueShift < 1.0f; + bool needHueShiftVersion = hueShift > 0.0f; + + if (mode == HDRRANGEREDUCTION_NONE) + { + outputValue = input; + } + else + { + float3 huePreserving = reduceLuma ? HuePreservingRangeReduction(input, minNits, maxNits, mode) : 0; + float3 hueShifted = needHueShiftVersion ? HueShiftingRangeReduction(input, minNits, maxNits, mode) : 0; + + if (reduceLuma && !needHueShiftVersion) + { + outputValue = huePreserving; + } + else if (!reduceLuma && needHueShiftVersion) + { + outputValue = hueShifted; + } + else + { + // We need to combine the two cases + outputValue = lerp(huePreserving, hueShifted, hueShift); + } + } + + return outputValue; +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// Public facing functions +// -------------------------------- +// These functions are aggregate of most of what we have above. You can think of this as the public API of the HDR Output library. +// Note that throughout HDRP we are assuming that when it comes to the final pass adjustements, our tonemapper has *NOT* +// performed range reduction and everything is assumed to be displayed on a reference 10k nits display and everything post-tonemapping +// is in either the Rec 2020 or Rec709 color space. The Rec709 version just rotate to Rec2020 before going forward if required by the output device. + +float3 HDRMappingFromRec2020(float3 Rec2020Input, float paperWhite, float minNits, float maxNits, int reductionMode, float hueShift, bool skipOETF = false) +{ + float3 outputSpaceInput = RotateRec2020ToOutputSpace(Rec2020Input); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode, hueShift); + + if (skipOETF) return reducedHDR; + + return OETF(reducedHDR); +} + +float3 HDRMappingFromRec709(float3 Rec709Input, float paperWhite, float minNits, float maxNits, int reductionMode, float hueShift, bool skipOETF = false) +{ + float3 outputSpaceInput = RotateRec709ToOutputSpace(Rec709Input); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode, hueShift); + + if (skipOETF) return reducedHDR; + + return OETF(reducedHDR); +} + + +float3 HDRMappingACES(float3 aces, float hdrBoost, int reductionMode, bool skipOETF = false) +{ + aces = (aces * hdrBoost * 0.01f); + float3 oces = RRT(aces); + + float3 AP1ODT = 0; + + // This is a static branch. + if (reductionMode == HDRRANGEREDUCTION_ACES1000NITS) + { + AP1ODT = ODT_1000nits_ToAP1(oces); + } + else if (reductionMode == HDRRANGEREDUCTION_ACES2000NITS) + { + AP1ODT = ODT_2000nits_ToAP1(oces); + } + else if (reductionMode == HDRRANGEREDUCTION_ACES4000NITS) + { + AP1ODT = ODT_4000nits_ToAP1(oces); + } + + float3 linearODT = 0; +#if defined(HDR_OUTPUT_SCRGB) + const float3x3 AP1_2_Rec709 = mul(XYZ_2_REC709_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); + linearODT = mul(AP1_2_Rec709, AP1ODT); +#else + const float3x3 AP1_2_Rec2020 = mul(XYZ_2_REC2020_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); + linearODT = mul(AP1_2_Rec2020, AP1ODT); +#endif + if (skipOETF) return linearODT; + + return OETF(linearODT); +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// UI Related functions +// -------------------------------- + +float3 ProcessUIForHDR(float3 uiSample, float paperWhite, float maxNits) +{ +#ifdef HDR_OUTPUT_SCRGB + uiSample.rgb = (uiSample.rgb * paperWhite); +#else + uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb); + uiSample.rgb *= paperWhite; +#endif + return uiSample.rgb; +} + +float3 SceneUIComposition(float4 uiSample, float3 sceneColor, float paperWhite, float maxNits) +{ + // Undo the pre multiply. + uiSample.rgb = uiSample.rgb / (uiSample.a == 0.0f ? 1.0 : uiSample.a); + uiSample.rgb = ProcessUIForHDR(uiSample.rgb, paperWhite, maxNits); + return uiSample.rgb * uiSample.a + sceneColor.rgb * (1.0f - uiSample.a); +} + +// -------------------------------------------------------------------------------------------- + +#endif diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl.meta b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl.meta new file mode 100644 index 00000000000..6ade4d23097 --- /dev/null +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b06473c622f844540bd141fc0efae169 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 80fa64269cb..e3d7ede2b23 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -74,7 +74,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [13.0.0] - 2021-09-01 +### Added + +- Added support for HDR output devices. +- Added option to use full ACES tonemap instead of the approximation. + ### Fixed + - Fixed impossibility to release the cursor in the template. - Fixed assert failure when enabling the probe volume system for the first time. - Significantly improved performance of APV probe debug. @@ -131,6 +137,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Improved sampling of overlapping point/area lights in path-traced volumetric scattering (case 1358777). - Path-traced volumetric scattering now takes fog color into account, adding scattered contribution on top of the non-scattered result (cases 1346105, 1358783). - Fixed minor readability issues in the ray tracing code. +- Optimized color grading LUT building. +- Made ACEScg the default color space for color grading. ## [12.0.0] - 2021-01-11 diff --git a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs index 6901a136abb..96d38e5825c 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -11,6 +11,7 @@ namespace UnityEditor.Rendering.HighDefinition sealed class TonemappingEditor : VolumeComponentEditor { SerializedDataParameter m_Mode; + SerializedDataParameter m_UseFullACES; SerializedDataParameter m_ToeStrength; SerializedDataParameter m_ToeLength; SerializedDataParameter m_ShoulderStrength; @@ -20,6 +21,19 @@ sealed class TonemappingEditor : VolumeComponentEditor SerializedDataParameter m_LutTexture; SerializedDataParameter m_LutContribution; + // HDR Mode. + SerializedDataParameter m_NeutralHDRRangeReductionMode; + SerializedDataParameter m_HueShiftAmount; + SerializedDataParameter m_HDRDetectPaperWhite; + SerializedDataParameter m_HDRPaperwhite; + SerializedDataParameter m_HDRDetectNitLimits; + SerializedDataParameter m_HDRMinNits; + SerializedDataParameter m_HDRMaxNits; + SerializedDataParameter m_HDRAcesPreset; + SerializedDataParameter m_HDRFallbackMode; + + public override bool hasAdditionalProperties => true; + // Curve drawing utilities readonly HableCurve m_HableCurve = new HableCurve(); Rect m_CurveRect; @@ -31,6 +45,7 @@ public override void OnEnable() var o = new PropertyFetcher(serializedObject); m_Mode = Unpack(o.Find(x => x.mode)); + m_UseFullACES = Unpack(o.Find(x => x.useFullACES)); m_ToeStrength = Unpack(o.Find(x => x.toeStrength)); m_ToeLength = Unpack(o.Find(x => x.toeLength)); m_ShoulderStrength = Unpack(o.Find(x => x.shoulderStrength)); @@ -40,6 +55,16 @@ public override void OnEnable() m_LutTexture = Unpack(o.Find(x => x.lutTexture)); m_LutContribution = Unpack(o.Find(x => x.lutContribution)); + m_NeutralHDRRangeReductionMode = Unpack(o.Find(x => x.neutralHDRRangeReductionMode)); + m_HueShiftAmount = Unpack(o.Find(x => x.hueShiftAmount)); + m_HDRDetectPaperWhite = Unpack(o.Find(x => x.detectPaperWhite)); + m_HDRPaperwhite = Unpack(o.Find(x => x.paperWhite)); + m_HDRDetectNitLimits = Unpack(o.Find(x => x.detectBrightnessLimits)); + m_HDRMinNits = Unpack(o.Find(x => x.minNits)); + m_HDRMaxNits = Unpack(o.Find(x => x.maxNits)); + m_HDRAcesPreset = Unpack(o.Find(x => x.acesPreset)); + m_HDRFallbackMode = Unpack(o.Find(x => x.fallbackMode)); + m_Material = new Material(Shader.Find("Hidden/HD PostProcessing/Editor/Custom Tonemapper Curve")); } @@ -54,6 +79,8 @@ public override void OnDisable() public override void OnInspectorGUI() { + bool hdrInPlayerSettings = UnityEditor.PlayerSettings.useHDRDisplay; + PropertyField(m_Mode); // Draw a curve for the custom tonemapping mode to make it easier to tweak visually @@ -125,6 +152,57 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("Use \"Edit > Rendering > Render Selected HDRP Camera to Log EXR\" to export a log-encoded frame for external grading.", MessageType.Info); } + else if (m_Mode.value.intValue == (int)TonemappingMode.ACES) + { + PropertyField(m_UseFullACES); + } + + if (hdrInPlayerSettings && m_Mode.value.intValue != (int)TonemappingMode.None) + { + EditorGUILayout.LabelField("HDR Output"); + int hdrTonemapMode = m_Mode.value.intValue; + if (m_Mode.value.intValue == (int)TonemappingMode.Custom || hdrTonemapMode == (int)TonemappingMode.External) + { + EditorGUILayout.HelpBox("The selected tonemapping mode is not supported in HDR Output mode. Select a fallback mode.", MessageType.Warning); + PropertyField(m_HDRFallbackMode); + hdrTonemapMode = (m_HDRFallbackMode.value.intValue == (int)FallbackHDRTonemap.ACES) ? (int)TonemappingMode.ACES : + (m_HDRFallbackMode.value.intValue == (int)FallbackHDRTonemap.Neutral) ? (int)TonemappingMode.Neutral : + (int)TonemappingMode.None; + } + + if (hdrTonemapMode == (int)TonemappingMode.Neutral) + { + PropertyField(m_NeutralHDRRangeReductionMode); + PropertyField(m_HueShiftAmount); + + PropertyField(m_HDRDetectPaperWhite); + EditorGUI.indentLevel++; + using (new EditorGUI.DisabledScope(m_HDRDetectPaperWhite.value.boolValue)) + { + PropertyField(m_HDRPaperwhite); + } + EditorGUI.indentLevel--; + PropertyField(m_HDRDetectNitLimits); + EditorGUI.indentLevel++; + using (new EditorGUI.DisabledScope(m_HDRDetectNitLimits.value.boolValue)) + { + PropertyField(m_HDRMinNits); + PropertyField(m_HDRMaxNits); + } + EditorGUI.indentLevel--; + } + if (hdrTonemapMode == (int)TonemappingMode.ACES) + { + PropertyField(m_HDRAcesPreset); + PropertyField(m_HDRDetectPaperWhite); + EditorGUI.indentLevel++; + using (new EditorGUI.DisabledScope(m_HDRDetectPaperWhite.value.boolValue)) + { + PropertyField(m_HDRPaperwhite); + } + EditorGUI.indentLevel--; + } + } } void CheckCurveRT(int width, int height) diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.Skin.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.Skin.cs index 1bc7a290706..8ebc1ba2277 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.Skin.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.Skin.cs @@ -61,6 +61,7 @@ internal class Styles public static readonly GUIContent shaderVariantLogLevelLabel = EditorGUIUtility.TrTextContent("Shader Variant Log Level", "Controls the level logging in of shader variants information is outputted when a build is performed. Information appears in the Unity Console when the build finishes.."); public static readonly GUIContent lensAttenuationModeContentLabel = EditorGUIUtility.TrTextContent("Lens Attenuation Mode", "Set the attenuation mode of the lens that is used to compute exposure. With imperfect lens some energy is lost when converting from EV100 to the exposure multiplier."); + public static readonly GUIContent colorGradingSpaceContentLabel = EditorGUIUtility.TrTextContent("Color Grading Space", "Set the color space in which color grading is performed. If ACES is used as tonemapper, the grading always happens in ACEScg. sRGB will lead to rendering in a non-wide color gamut, while ACEScg is a wider color gamut that will allow to exploit the wide color gamut on UHD TV when outputting in HDR."); public static readonly GUIContent useDLSSCustomProjectIdLabel = EditorGUIUtility.TrTextContent("Use DLSS Custom Project Id", "Set to utilize a custom project Id for the NVIDIA Deep Learning Super Sampling extension."); public static readonly GUIContent DLSSProjectIdLabel = EditorGUIUtility.TrTextContent("DLSS Custom Project Id", "The custom project ID string to utilize for the NVIDIA Deep Learning Super Sampling extension."); diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.cs index 1c93bbf4452..b0b97a83c6b 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/HDGlobalSettingsWindow.cs @@ -482,6 +482,7 @@ static void DrawMiscSettings(SerializedHDRenderPipelineGlobalSettings serialized { EditorGUILayout.PropertyField(serialized.shaderVariantLogLevel, Styles.shaderVariantLogLevelLabel); EditorGUILayout.PropertyField(serialized.lensAttenuation, Styles.lensAttenuationModeContentLabel); + EditorGUILayout.PropertyField(serialized.colorGradingSpace, Styles.colorGradingSpaceContentLabel); EditorGUILayout.PropertyField(serialized.rendererListCulling, Styles.rendererListCulling); #if ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedHDRenderPipelineGlobalSettings.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedHDRenderPipelineGlobalSettings.cs index 92a3a394136..1731c84015c 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedHDRenderPipelineGlobalSettings.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedHDRenderPipelineGlobalSettings.cs @@ -43,6 +43,7 @@ class SerializedHDRenderPipelineGlobalSettings public SerializedProperty shaderVariantLogLevel; public SerializedProperty lensAttenuation; + public SerializedProperty colorGradingSpace; public SerializedProperty diffusionProfileSettingsList; public SerializedProperty supportProbeVolumes; public SerializedProperty supportRuntimeDebugDisplay; @@ -132,6 +133,7 @@ public SerializedHDRenderPipelineGlobalSettings(SerializedObject serializedObjec shaderVariantLogLevel = serializedObject.Find((HDRenderPipelineGlobalSettings s) => s.shaderVariantLogLevel); lensAttenuation = serializedObject.FindProperty("lensAttenuationMode"); + colorGradingSpace = serializedObject.Find((HDRenderPipelineGlobalSettings s) => s.colorGradingSpace); diffusionProfileSettingsList = serializedObject.Find((HDRenderPipelineGlobalSettings s) => s.diffusionProfileSettingsList); m_DiffusionProfileUI = new DiffusionProfileSettingsListUI() { diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs index 1f1802c4a57..09e423e1601 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs @@ -34,7 +34,6 @@ class SerializedRenderPipelineSettings public SerializedProperty supportCustomPass; public SerializedProperty customBufferFormat; public SerializedScalableSetting planarReflectionResolution; - public SerializedProperty supportDecals; public SerializedProperty supportDecalLayers; public SerializedProperty supportSurfaceGradient; @@ -56,7 +55,6 @@ class SerializedRenderPipelineSettings internal SerializedProperty supportProbeVolumeStreaming; internal SerializedProperty probeVolumeSHBands; - public SerializedGlobalLightLoopSettings lightLoopSettings; public SerializedHDShadowInitParameters hdShadowInitParams; public SerializedGlobalDecalSettings decalSettings; @@ -113,7 +111,6 @@ public SerializedRenderPipelineSettings(SerializedProperty root) probeVolumeTextureSize = root.Find((RenderPipelineSettings s) => s.probeVolumeMemoryBudget); supportProbeVolumeStreaming = root.Find((RenderPipelineSettings s) => s.supportProbeVolumeStreaming); probeVolumeSHBands = root.Find((RenderPipelineSettings s) => s.probeVolumeSHBands); - supportRayTracing = root.Find((RenderPipelineSettings s) => s.supportRayTracing); supportedRayTracingMode = root.Find((RenderPipelineSettings s) => s.supportedRayTracingMode); diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset b/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset index 6773d90ac78..299b477908f 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset @@ -20,7 +20,6 @@ MonoBehaviour: terrainDetailLitShader: {fileID: 0} terrainDetailGrassShader: {fileID: 0} terrainDetailGrassBillboardShader: {fileID: 0} - probeVolumeGizmoShader: {fileID: 4800000, guid: 3b21275fd12d65f49babb5286f040f2d, type: 3} materials: defaultDiffuseMat: {fileID: 2100000, guid: 73c176f402d2c2f4d929aa5da7585d17, type: 2} defaultMirrorMat: {fileID: 2100000, guid: 6b17274157b33bc45b6a40e7d4ff51fe, type: 2} @@ -32,11 +31,7 @@ MonoBehaviour: autodeskInteractive: {fileID: 4800000, guid: 7252379db4c18b641b517f2c91bb57e1, type: 3} autodeskInteractiveMasked: {fileID: 4800000, guid: 29c4adff654862b40a2e9fb2015a42c3, type: 3} autodeskInteractiveTransparent: {fileID: 4800000, guid: ee2ce0be66f45d9449d71ba9b49c2acd, type: 3} - autodeskInteractive: {fileID: 4800000, guid: 7252379db4c18b641b517f2c91bb57e1, type: 3} - autodeskInteractiveMasked: {fileID: 4800000, guid: 29c4adff654862b40a2e9fb2015a42c3, type: 3} - autodeskInteractiveTransparent: {fileID: 4800000, guid: ee2ce0be66f45d9449d71ba9b49c2acd, type: 3} - defaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 4819724840ee9444f9da841b477038ce, - type: 3} + defaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 4819724840ee9444f9da841b477038ce, type: 3} lookDev: defaultLookDevVolumeProfile: {fileID: 11400000, guid: 254c4fe87beb7be4fa72e1681edbed02, type: 2} m_Version: 0 diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 6f7d0d82074..90ce75817b3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -291,6 +291,7 @@ public class DebugData internal int terrainTextureEnumIndex; internal int colorPickerDebugModeEnumIndex; internal int exposureDebugModeEnumIndex; + internal int hdrDebugModeEnumIndex; internal int msaaSampleDebugModeEnumIndex; internal int debugCameraToFreezeEnumIndex; internal int volumeComponentEnumIndex; @@ -547,6 +548,15 @@ public bool IsDebugExposureModeEnabled() return data.lightingDebugSettings.exposureDebugMode != ExposureDebugMode.None; } + /// + /// Returns true if any full screen HDR debug display is enabled. + /// + /// True if any full screen exposure debug display is enabled. + public bool IsHDRDebugModeEnabled() + { + return data.lightingDebugSettings.hdrDebugMode != HDRDebugMode.None; + } + /// /// Returns true if material validation is enabled. /// @@ -740,12 +750,22 @@ public void SetDebugLightingMode(DebugLightingMode value) /// /// Set the current Exposure Debug Mode. /// - /// Desired Probe Volume Debug Mode. + /// Desired Exposure Debug Mode. internal void SetExposureDebugMode(ExposureDebugMode value) { data.lightingDebugSettings.exposureDebugMode = value; } + /// + /// Set the current HDR Debug Mode. + /// + /// Desired HDR output Debug Mode. + internal void SetHDRDebugMode(HDRDebugMode value) + { + data.lightingDebugSettings.hdrDebugMode = value; + } + + /// /// Set the current Mip Map Debug Mode. /// @@ -1155,6 +1175,8 @@ static class LightingStrings public static readonly NameAndTooltip ReflectionProbes = new() { name = "Reflection Probes", tooltip = "Temporarily enables or disables Reflection Probes in your Scene." }; public static readonly NameAndTooltip Exposure = new() { name = "Exposure", tooltip = "Allows the selection of an Exposure debug mode to use." }; + public static readonly NameAndTooltip HDROutput = new() { name = "HDR", tooltip = "Allows the selection of an HDR debug mode to use." }; + public static readonly NameAndTooltip HDROutputDebugMode = new() { name = "DebugMode", tooltip = "Use the drop-down to select a debug mode for HDR Output." }; public static readonly NameAndTooltip ExposureDebugMode = new() { name = "DebugMode", tooltip = "Use the drop-down to select a debug mode to validate the exposure." }; public static readonly NameAndTooltip ExposureDisplayMaskOnly = new() { name = "Display Mask Only", tooltip = "Display only the metering mask in the picture-in-picture. When disabled, the mask is visible after weighting the scene color instead." }; public static readonly NameAndTooltip ExposureShowTonemapCurve = new() { name = "Show Tonemap Curve", tooltip = "Overlay the tonemap curve to the histogram debug view." }; @@ -1345,8 +1367,28 @@ void RegisterLightingDebug() setter = value => data.lightingDebugSettings.debugExposure = value }); + lighting.children.Add(exposureFoldout); + var hdrFoldout = new DebugUI.Foldout + { + nameAndTooltip = LightingStrings.HDROutput, + children = + { + new DebugUI.EnumField + { + nameAndTooltip = LightingStrings.HDROutputDebugMode, + getter = () => (int)data.lightingDebugSettings.hdrDebugMode, + setter = value => SetHDRDebugMode((HDRDebugMode)value), + autoEnum = typeof(HDRDebugMode), onValueChanged = RefreshLightingDebug, + getIndex = () => data.hdrDebugModeEnumIndex, + setIndex = value => data.hdrDebugModeEnumIndex = value + } + } + }; + + lighting.children.Add(hdrFoldout); + lighting.children.Add(new DebugUI.EnumField { nameAndTooltip = LightingStrings.LightingDebugMode, getter = () => (int)data.lightingDebugSettings.debugLightingMode, setter = value => SetDebugLightingMode((DebugLightingMode)value), autoEnum = typeof(DebugLightingMode), onValueChanged = RefreshLightingDebug, getIndex = () => data.lightingDebugModeEnumIndex, setIndex = value => { data.ResetExclusiveEnumIndices(); data.lightingDebugModeEnumIndex = value; } }); lighting.children.Add(new DebugUI.BitField { nameAndTooltip = LightingStrings.LightHierarchyDebugMode, getter = () => data.lightingDebugSettings.debugLightFilterMode, setter = value => SetDebugLightFilterMode((DebugLightFilterMode)value), enumType = typeof(DebugLightFilterMode), onValueChanged = RefreshLightingDebug, }); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader new file mode 100644 index 00000000000..a5e373a4e10 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -0,0 +1,322 @@ +Shader "Hidden/HDRP/DebugHDR" +{ + HLSLINCLUDE + + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs.hlsl" + #define DEBUG_DISPLAY + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" + + #pragma vertex Vert + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + + TEXTURE2D_X(_DebugFullScreenTexture); + + float4 _HDRDebugParams; + + float4 _HDROutputParams; + float4 _HDROutputParams2; + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _RangeReductionMode (int)_HDROutputParams2.x + #define _IsRec709 (int)(_HDROutputParams.w == 1) + + #define _TonemapType _HDRDebugParams.w + + TEXTURE2D_X(_xyBuffer); + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_OUTPUT_STEREO + }; + + Varyings Vert(Attributes input) + { + Varyings output; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + output.texcoord = GetNormalizedFullScreenTriangleTexCoord(input.vertexID); + + return output; + } + + float3 ToHeat(float value) + { + float3 r = value * 2.1f - float3(1.8f, 1.14f, 0.3f); + return 1.0f - r * r; + } + + float3 FragMetering(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + return color; + } + + float DistToLine(float2 pt1, float2 pt2, float2 testPt) + { + float2 lineDir = pt2 - pt1; + float2 perpDir = float2(lineDir.y, -lineDir.x); + float2 dirToPt1 = pt1 - testPt; + return (dot(normalize(perpDir), dirToPt1)); + } + + float4 DrawSegment(float2 uv, float2 p1, float2 p2, float thickness, float3 color) { + + float a = abs(distance(p1, uv)); + float b = abs(distance(p2, uv)); + float c = abs(distance(p1, p2)); + + if (a >= c || b >= c) return 0; + + float p = (a + b + c) * 0.5; + float h = 2 / c * sqrt(p * (p - a) * (p - b) * (p - c)); + + + float lineAlpha = lerp(1.0, 0.0, smoothstep(0.5 * thickness, 1.5 * thickness, h)); + return float4(color * lineAlpha, lineAlpha); + } + + + float2 RGBtoxy(float3 rgb) + { + float3 XYZ = 0; + if (_IsRec709) + { + XYZ = RotateRec709ToXYZ(rgb); + } + else + { + XYZ = RotateRec2020ToXYZ(rgb); + } + return XYZtoxy(XYZ); + } + + float3 uvToGamut(float2 uv) + { + float3 xyzColor = xyYtoXYZ(float3(uv.x, uv.y, 1.0f)); + float3 linearRGB = RotateXYZToRec2020(xyzColor); + if (_IsRec709) + { + linearRGB = RotateXYZToRec709(xyzColor); + } + + float scale = 1.0f / length(linearRGB); + + float desat = dot(linearRGB, 0.333f); + scale *= 1.0 + exp(-length(linearRGB - desat) * 2.0f) * 0.5f; + + linearRGB *= scale; + + return linearRGB; + } + + float3 Barycentric(float2 p, float2 a, float2 b, float2 c) + { + float2 v0 = b - a; + float2 v1 = c - a; + float2 v2 = p - a; + float d00 = dot(v0, v0); + float d01 = dot(v0, v1); + float d11 = dot(v1, v1); + float d20 = dot(v2, v0); + float d21 = dot(v2, v1); + float denom = d00 * d11 - d01 * d01; + float3 bary = 0; + bary.y = (d11 * d20 - d01 * d21) / denom; + bary.z = (d00 * d21 - d01 * d20) / denom; + bary.x = 1.0f - bary.y - bary.z; + return bary; + } + + bool PointInTriangle(float2 p, float2 a, float2 b, float2 c) + { + float3 bar = Barycentric(p, a, b, c); + return (bar.x >= 0 && bar.x <= 1 && bar.y >= 0 && bar.y <= 1 && (bar.x + bar.y) <= 1); + } + + bool IsInImage(float2 xy) + { + return SAMPLE_TEXTURE2D_X_LOD(_xyBuffer, s_point_clamp_sampler, xy, 0.0).x != 0; + } + + + float3 CommonFrag(Varyings input, bool displayClip) + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + + int gamutPiPSize = _ScreenSize.x / 3.0f; + + float2 r_2020 = float2(0.708, 0.292); + float2 g_2020 = float2(0.170, 0.797); + float2 b_2020 = float2(0.131, 0.046); + + float2 r_709 = float2(0.64, 0.33); + float2 g_709 = float2(0.3, 0.6); + float2 b_709 = float2(0.15, 0.06); + + float2 pos = input.positionCS.xy; + float lineThickness = 0.002; + + float2 xy = RGBtoxy(color.rgb); + + float3 rec2020Color = float3(_PaperWhite, 0, 0); + float3 rec2020ColorDesat = float3(3.0, 0.5, 0.5); + float3 rec709Color = float3(0, _PaperWhite, 0); + float3 rec709ColorDesat = float3(0.4, 0.6, 0.4); + + + if (displayClip) + { + float clipAlpha = 0.2f; + if (PointInTriangle(xy, r_709, g_709, b_709)) + { + color.rgb = (color.rgb * (1 - clipAlpha) + clipAlpha * rec709Color); + } + else if (PointInTriangle(xy, r_2020, g_2020, b_2020)) + { + color.rgb = (color.rgb * (1 - clipAlpha) + clipAlpha * rec2020Color); + } + } + + float4 gamutColor = 0; + if (all(pos < gamutPiPSize)) + { + float2 uv = pos / gamutPiPSize; + float4 lineColor = DrawSegment(uv, g_709, b_709, lineThickness, float3(0, 0, 0)) + DrawSegment(uv, b_709, r_709, lineThickness, float3(0, 0, 0)) + + DrawSegment(uv, r_709, g_709, lineThickness, float3(0, 0, 0)) + + DrawSegment(uv, g_2020, b_2020, lineThickness, float3(0, 0, 0)) + DrawSegment(uv, b_2020, r_2020, lineThickness, float3(0, 0, 0)) + + DrawSegment(uv, r_2020, g_2020, lineThickness, float3(0, 0, 0)); + + float3 linearRGB = 0; + bool pointInRec709 = true; + if (PointInTriangle(uv, r_2020, g_2020, b_2020)) + { + linearRGB = uvToGamut(uv); + + if (displayClip) + { + if (PointInTriangle(uv, r_709, g_709, b_709)) + { + linearRGB.rgb = rec709ColorDesat; + } + else + { + pointInRec709 = false; + linearRGB.rgb = rec2020ColorDesat; + } + } + + gamutColor.a = max(lineColor.a, 0.15); + gamutColor.rgb = linearRGB * _PaperWhite; + + if (IsInImage(uv)) + { + gamutColor.a = 1; + if (displayClip) + gamutColor.rgb = pointInRec709 ? rec709Color : rec2020Color; + } + } + + gamutColor.rgb = gamutColor.rgb * (1.0f - lineColor.a) + lineColor.rgb; + } + + color.rgb = gamutColor.rgb * gamutColor.a + color.rgb * (1 - gamutColor.a); + + return color; + } + + float3 FragColorGamut(Varyings input) : SV_Target + { + return CommonFrag(input, false); + } + + float3 FragColorGamutClip(Varyings input) : SV_Target + { + return CommonFrag(input, true); + } + + + float3 FragNits(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + float2 uv = input.texcoord.xy; + float3 color = SAMPLE_TEXTURE2D_X_LOD(_DebugFullScreenTexture, s_linear_clamp_sampler, uv, 0.0).xyz; + + float maxC = max(color.x, max(color.y, color.z)); + + float t = (maxC - _PaperWhite) / (_MaxNits - _PaperWhite); + + if (maxC > _PaperWhite) + { + return lerp(float3(_PaperWhite, _PaperWhite, 0), float3(_PaperWhite, 0, 0), saturate(t)); + } + else + { + return Luminance(color).xxx; + } + } + + ENDHLSL + + SubShader + { + Tags{ "RenderPipeline" = "HDRenderPipeline" } + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment FragColorGamut + ENDHLSL + } + + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment FragColorGamutClip + ENDHLSL + } + + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment FragNits + ENDHLSL + } + } + Fallback Off +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader.meta new file mode 100644 index 00000000000..6f0422e2ce5 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9bc5229549892084da43ad706d84f1bc +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index fb684028dbf..8c8937ffb0b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -189,6 +189,21 @@ public enum ExposureDebugMode MeteringWeighted, } + /// + /// HDR debug mode. + /// + [GenerateHLSL] + public enum HDRDebugMode + { + /// No hdr debug. + None, + /// Gamut view - show the gamuts and what part of the gamut are represented in the image. + GamutView, + /// Gamut clip - show what part of the scene are covered by the Rec709 gamut and what parts are in the Rec2020 gamut. + GamutClip, + /// Show in colors between yellow and red any value that is above the paper white value. Luminance otherwise. + ValuesAbovePaperWhite, + } /// /// Probe Volume Debug Modes. @@ -325,6 +340,10 @@ public bool IsDebugDisplayEnabled() /// Whether to show the only the mask in the picture in picture. If unchecked, the mask view is weighted by the scene color. public bool displayMaskOnly = false; + /// HDR debug mode. + public HDRDebugMode hdrDebugMode = HDRDebugMode.None; + + /// Display the light cookies atlas. public bool displayCookieAtlas = false; /// Display the light cookies cubemap array. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl index dc54312d99f..0afefec9be5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs.hlsl @@ -73,6 +73,14 @@ #define EXPOSUREDEBUGMODE_FINAL_IMAGE_HISTOGRAM_VIEW (3) #define EXPOSUREDEBUGMODE_METERING_WEIGHTED (4) +// +// UnityEngine.Rendering.HighDefinition.HDRDebugMode: static fields +// +#define HDRDEBUGMODE_NONE (0) +#define HDRDEBUGMODE_GAMUT_VIEW (1) +#define HDRDEBUGMODE_GAMUT_CLIP (2) +#define HDRDEBUGMODE_VALUES_ABOVE_PAPER_WHITE (3) + // // UnityEngine.Rendering.HighDefinition.ProbeVolumeDebugMode: static fields // diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/UI.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/UI.meta new file mode 100644 index 00000000000..11ffa87de31 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d3003815a251b80468910fa6356dadb2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs index 79d60e4de86..52d3a42005b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs @@ -20,7 +20,7 @@ public enum TonemappingMode Neutral, /// - /// Close approximation of the reference ACES tonemapper for a more filmic look. + /// ACES tonemapper for a more filmic look. /// ACES, @@ -37,6 +37,92 @@ public enum TonemappingMode External } + /// + /// Available options for when HDR Output is enabled and Tonemap is set to Neutral. + /// + public enum NeutralRangeReductionMode + { + /// + /// Simple Reinhard tonemapping curve. + /// + Reinhard = 1, + /// + /// Range reduction curve as specified in the BT.2390 standard. + /// + BT2390 = 2 + } + + /// + /// Preset used when selecting ACES tonemapping for HDR displays. + /// + public enum HDRACESPreset + { + /// + /// Preset for display with maximum 1000 nits display. + /// + ACES1000Nits = HDRRangeReduction.ACES1000Nits, + /// + /// Preset for display with maximum 2000 nits display. + /// + ACES2000Nits = HDRRangeReduction.ACES2000Nits, + /// + /// Preset for display with maximum 4000 nits display. + /// + ACES4000Nits = HDRRangeReduction.ACES4000Nits, + } + + /// + /// Tonemap mode to be used when outputting to HDR device and when the main mode is not supported on HDR. + /// + public enum FallbackHDRTonemap + { + /// + /// No tonemapping. + /// + None = 0, + /// + /// Tonemapping mode with minimal impact on color hue and saturation. + /// + Neutral, + /// + /// ACES tonemapper for a more filmic look. + /// + ACES + } + + [Serializable] + public sealed class NeutralRangeReductionModeParameter : VolumeParameter + { + /// + /// Creates a new instance. + /// + /// The initial value to store in the parameter. + /// The initial override state for the parameter. + public NeutralRangeReductionModeParameter(NeutralRangeReductionMode value, bool overrideState = false) : base(value, overrideState) { } + } + + [Serializable] + public sealed class HDRACESPresetParameter : VolumeParameter + { + /// + /// Creates a new instance. + /// + /// The initial value to store in the parameter. + /// The initial override state for the parameter. + public HDRACESPresetParameter(HDRACESPreset value, bool overrideState = false) : base(value, overrideState) { } + } + + [Serializable] + public sealed class FallbackHDRTonemapParameter : VolumeParameter + { + /// + /// Creates a new instance. + /// + /// The initial value to store in the parameter. + /// The initial override state for the parameter. + public FallbackHDRTonemapParameter(FallbackHDRTonemap value, bool overrideState = false) : base(value, overrideState) { } + } + /// /// A volume component that holds settings for the Tonemapping effect. /// @@ -51,6 +137,13 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent [Tooltip("Specifies the tonemapping algorithm to use for the color grading process.")] public TonemappingModeParameter mode = new TonemappingModeParameter(TonemappingMode.None); + /// + /// Whether to use full ACES tonemap instead of an approximation. + /// + [AdditionalProperty] + [Tooltip("Whether to use full ACES tonemap instead of an approximation. When outputting to an HDR display, full ACES is always used regardless of this checkbox.")] + public BoolParameter useFullACES = new BoolParameter(false); + /// /// Controls the transition between the toe and the mid section of the curve. A value of 0 /// results in no transition and a value of 1 results in a very hard transition. @@ -110,6 +203,60 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent [Tooltip("How much of the lookup texture will contribute to the color grading effect.")] public ClampedFloatParameter lutContribution = new ClampedFloatParameter(1f, 0f, 1f); + // -- HDR Output options -- + + /// + /// Specifies the range reduction mode used when HDR output is enabled and Neutral tonemapping is enabled. + /// + [AdditionalProperty] + [Tooltip("Specifies the range reduction mode used when HDR output is enabled and Neutral tonemapping is enabled.")] + public NeutralRangeReductionModeParameter neutralHDRRangeReductionMode = new NeutralRangeReductionModeParameter(NeutralRangeReductionMode.BT2390); + + /// + /// Specifies the preset to be used for HDR displays. + /// + [Tooltip("Specifies the ACES preset to be used for HDR displays.")] + public HDRACESPresetParameter acesPreset = new HDRACESPresetParameter(HDRACESPreset.ACES1000Nits); + + /// + /// Specifies the fallback tonemapping algorithm to use when outputting to an HDR device, when the main mode is not supported. + /// + /// + [Tooltip("Specifies the fallback tonemapping algorithm to use when outputting to an HDR device, when the main mode is not supported.")] + public FallbackHDRTonemapParameter fallbackMode = new FallbackHDRTonemapParameter(FallbackHDRTonemap.Neutral); + + /// + /// How much hue we want to preserve. Values closer to 0 try to preserve hue, while as values get closer to 1 hue shifts are reintroduced. + /// + [Tooltip("How much hue we want to preserve. Values closer to 0 try to preserve hue, while as values get closer to 1 hue shifts are reintroduced.")] + public ClampedFloatParameter hueShiftAmount = new ClampedFloatParameter(0.0f, 0.0f, 1.0f); + + /// + /// Whether to use values detected from the output device as paperwhite. This value will often not lead to equivalent images between SDR and HDR. It is suggested to manually set this value. + /// + [Tooltip("Whether to use values detected from the output device as paperwhite. This value will often not lead to equivalent images between SDR and HDR. It is suggested to manually set this value.")] + public BoolParameter detectPaperWhite = new BoolParameter(false); + /// + /// The paper white value. It controls how bright a paper white surface should be, it also determines the maximum brightness of UI. The scene is also scaled relative to this value. Value in nits. + /// + [Tooltip("It controls how bright a paper white surface should be, it also determines the maximum brightness of UI. The scene is also scaled relative to this value. Value in nits.")] + public ClampedFloatParameter paperWhite = new ClampedFloatParameter(300.0f, 0.0f, 400.0f); + /// + /// Whether to use the minimum and maximum brightness values detected from the output device. It might be worth considering calibrating this values manually if the results are not the desired ones. + /// + [Tooltip("Whether to use the minimum and maximum brightness values detected from the output device. It might be worth considering calibrating this values manually if the results are not the desired ones.")] + public BoolParameter detectBrightnessLimits = new BoolParameter(true); + /// + /// The minimum brightness (in nits) of the screen. Note that this is assumed to be 0.005f with ACES Tonemap. + /// + [Tooltip("The minimum brightness (in nits) of the screen. Note that this is assumed to be 0.005 with ACES Tonemap.")] + public ClampedFloatParameter minNits = new ClampedFloatParameter(0.005f, 0.0f, 50.0f); + /// + /// The maximum brightness (in nits) of the screen. Note that this is assumed to be defined by the preset when ACES Tonemap is used. + /// + [Tooltip("The maximum brightness (in nits) of the screen. Note that this is assumed to be defined by the preset when ACES Tonemap is used.")] + public ClampedFloatParameter maxNits = new ClampedFloatParameter(1000.0f, 0.0f, 5000.0f); + /// /// Tells if the effect needs to be rendered or not. /// @@ -122,6 +269,19 @@ public bool IsActive() return mode.value != TonemappingMode.None; } + internal TonemappingMode GetHDRTonemappingMode() + { + if (mode.value == TonemappingMode.Custom || + mode.value == TonemappingMode.External) + { + if (fallbackMode.value == FallbackHDRTonemap.None) return TonemappingMode.None; + if (fallbackMode.value == FallbackHDRTonemap.Neutral) return TonemappingMode.Neutral; + if (fallbackMode.value == FallbackHDRTonemap.ACES) return TonemappingMode.ACES; + } + + return mode.value; + } + /// /// Validates the format and size of the LUT texture set in . /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader new file mode 100644 index 00000000000..fa7ba3b213e --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -0,0 +1,95 @@ +Shader "Hidden/HDRP/CompositeUI" +{ + HLSLINCLUDE + + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + #pragma editor_sync_compilation + #pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB + #pragma multi_compile_local_fragment _ APPLY_AFTER_POST + + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" + + TEXTURE2D_X(_InputTexture); + TEXTURE2D_X(_UITexture); + TEXTURE2D_X(_AfterPostProcessTexture); + + CBUFFER_START(cb) + float4 _HDROutputParams; + int _NeedsFlip; + CBUFFER_END + + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_OUTPUT_STEREO + }; + + Varyings Vert(Attributes input) + { + Varyings output; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + output.texcoord = GetNormalizedFullScreenTriangleTexCoord(input.vertexID); + return output; + } + + float4 Frag(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + + float2 uv = input.texcoord; + float2 samplePos = input.positionCS.xy; + if (_NeedsFlip) + { + samplePos.y = _ScreenSize.y - samplePos.y; + } + // We need to flip y + float4 outColor = LOAD_TEXTURE2D_X(_InputTexture, samplePos.xy); + // Apply AfterPostProcess target + #if APPLY_AFTER_POST + float4 afterPostColor = LOAD_TEXTURE2D_X(_AfterPostProcessTexture, samplePos.xy); + afterPostColor.rgb = ProcessUIForHDR(afterPostColor.rgb, _PaperWhite, _MaxNits); + // After post objects are blended according to the method described here: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html + outColor.xyz = afterPostColor.a * outColor.xyz + afterPostColor.xyz; + #endif + + float4 uiValue = LOAD_TEXTURE2D_X(_UITexture, samplePos.xy); + outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite, _MaxNits); + outColor.rgb = OETF(outColor.rgb); + + return outColor; + } + ENDHLSL + + SubShader + { + Tags{ "RenderPipeline" = "HDRenderPipeline" } + + Pass + { + ZWrite Off ZTest Always Blend Off Cull Off + + HLSLPROGRAM + #pragma vertex Vert + #pragma fragment Frag + ENDHLSL + } + } + Fallback Off +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader.meta new file mode 100644 index 00000000000..2956b255281 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 08b7ad21d2b8e9142b730b22d7355821 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute new file mode 100644 index 00000000000..f821f53323e --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute @@ -0,0 +1,43 @@ +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" + +#pragma kernel KCIExyGen +#define GROUP_SIZE_X 8 +#define GROUP_SIZE_Y 8 + +TEXTURE2D_X(_SourceTexture); +RW_TEXTURE2D_X(float, _xyBuffer); + +float4 _HDRxyBufferDebugParams; +#define _SizePerDim _HDRxyBufferDebugParams.xy +#define _IsRec709 (int)(_HDRxyBufferDebugParams.w == 1) + +float2 RGBtoxy(float3 rgb) +{ + float3 XYZ = 0; + if (_IsRec709) + { + XYZ = RotateRec709ToXYZ(rgb); + } + else + { + XYZ = RotateRec2020ToXYZ(rgb); + } + return XYZ.xy / (dot(XYZ, 1)); +} + + +[numthreads(GROUP_SIZE_X, GROUP_SIZE_Y, 1)] +void KCIExyGen(uint groupIndex : SV_GroupIndex, + uint3 dispatchThreadId : SV_DispatchThreadID) +{ + UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); + float3 rgbData = LOAD_TEXTURE2D_X(_SourceTexture, dispatchThreadId.xy).rgb; + + float2 xy = (RGBtoxy(rgbData)); + + _xyBuffer[COORD_TEXTURE2D_X(xy * _SizePerDim)] = 1; +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute.meta new file mode 100644 index 00000000000..f2cde3c8de3 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f055d2983d992b64494f1a03fc725cde +ComputeShaderImporter: + externalObjects: {} + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FinalPass.shader b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FinalPass.shader index df17b291c2f..d7258edd9a1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FinalPass.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FinalPass.shader @@ -11,6 +11,7 @@ Shader "Hidden/HDRP/FinalPass" #pragma multi_compile_local_fragment _ DITHER #pragma multi_compile_local_fragment _ ENABLE_ALPHA #pragma multi_compile_local_fragment _ APPLY_AFTER_POST + #pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 @@ -21,13 +22,19 @@ Shader "Hidden/HDRP/FinalPass" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/PostProcessDefines.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl" +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" +#endif TEXTURE2D_X(_InputTexture); TEXTURE2D(_GrainTexture); + TEXTURE2D_X(_AfterPostProcessTexture); TEXTURE2D_ARRAY(_BlueNoiseTexture); TEXTURE2D_X(_AlphaTexture); + TEXTURE2D_X(_UITexture); + SAMPLER(sampler_LinearClamp); SAMPLER(sampler_LinearRepeat); @@ -38,6 +45,13 @@ Shader "Hidden/HDRP/FinalPass" float4 _ViewPortSize; float _KeepAlpha; + float4 _HDROutputParams; + float4 _HDROutputParams2; + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _RangeReductionMode (int)_HDROutputParams2.x + struct Attributes { uint vertexID : SV_VertexID; @@ -148,10 +162,24 @@ Shader "Hidden/HDRP/FinalPass" // Apply AfterPostProcess target #if APPLY_AFTER_POST float4 afterPostColor = SAMPLE_TEXTURE2D_X_LOD(_AfterPostProcessTexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); + #ifdef HDR_OUTPUT + afterPostColor.rgb = ProcessUIForHDR(afterPostColor.rgb, _PaperWhite, _MaxNits); + #endif // After post objects are blended according to the method described here: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html outColor.xyz = afterPostColor.a * outColor.xyz + afterPostColor.xyz; #endif + + #ifdef HDR_OUTPUT + // Screen space overlay blending. + { + float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); + outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite, _MaxNits); + + outColor.rgb = OETF(outColor.rgb); + } + #endif + #if !defined(ENABLE_ALPHA) return float4(outColor, outAlpha); #else diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute index 97389bd534b..ec2d87fd1b1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute @@ -1,12 +1,22 @@ -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" - #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch -#pragma multi_compile TONEMAPPING_NONE TONEMAPPING_NEUTRAL TONEMAPPING_ACES TONEMAPPING_CUSTOM TONEMAPPING_EXTERNAL +#pragma multi_compile TONEMAPPING_NONE TONEMAPPING_NEUTRAL TONEMAPPING_ACES_APPROX TONEMAPPING_ACES_FULL TONEMAPPING_CUSTOM TONEMAPPING_EXTERNAL +#pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB +#pragma multi_compile_local GRADE_IN_SRGB GRADE_IN_ACESCG + +#if (defined(TONEMAPPING_ACES_APPROX) || defined(TONEMAPPING_ACES_FULL)) +#define TONEMAPPING_ACES +#endif +#define TONEMAPPING_USE_FULL_ACES defined(TONEMAPPING_ACES_FULL) + #pragma kernel KBuild +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" +#endif TEXTURE3D(_LogLut3D); RW_TEXTURE3D(float4, _OutputTexture); @@ -50,11 +60,20 @@ CBUFFER_START(cb0) float4 _MidSegmentB; float4 _ShoSegmentA; float4 _ShoSegmentB; + + float4 _HDROutputParams; + float4 _HDROutputParams2; + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _RangeReductionMode (int)_HDROutputParams2.x + #define _HueShift _HDROutputParams2.y + CBUFFER_END float GetLuminance(float3 colorLinear) { - #if defined(TONEMAPPING_ACES) + #if defined(TONEMAPPING_ACES) || defined(GRADE_IN_ACESCG) return AcesLuminance(colorLinear); #else return Luminance(colorLinear); @@ -67,11 +86,64 @@ float EvaluateCurve(TEXTURE2D(curve), float t) return saturate(x); } +float3 RotateToColorGradingSpace_LogToLinear(float3 logColor) +{ +#if defined(TONEMAPPING_ACES) || defined(GRADE_IN_ACESCG) + return ACES_to_ACEScg(ACEScc_to_ACES(logColor)); +#elif defined(GRADE_IN_SRGB) + return LogCToLinear(logColor); +#endif +} + +float3 RotateToColorGradingSpace_LinearToLog(float3 linearColor) +{ +#if defined(TONEMAPPING_ACES) || defined(GRADE_IN_ACESCG) + return ACES_to_ACEScc(unity_to_ACES(linearColor)); +#elif defined(GRADE_IN_SRGB) + return LinearToLogC(linearColor); +#endif +} + + +float3 RotateToColorGradeOutputSpace(float3 gradedColor) +{ +#ifdef TONEMAPPING_ACES + + // In ACES workflow we return graded color in ACEScg, we move to ACES (AP0) later on + return gradedColor; + +#elif defined(HDR_OUTPUT) // HDR but not ACES workflow + + // If we are doing HDR we expect grading to finish at Rec2020. Any supplemental rotation is done inside the various options. +#ifdef GRADE_IN_ACESCG + return ACEScg_to_Rec2020(gradedColor); +#elif defined(GRADE_IN_SRGB) + return RotateRec709ToRec2020(gradedColor); +#endif + +#else // Nor ACES or HDR + +#ifdef GRADE_IN_ACESCG + // If we are not HDR or ACES, we move back to Rec709 + return ACEScg_to_unity(gradedColor); +#elif defined(GRADE_IN_SRGB) + // We already graded in sRGB + return gradedColor; +#endif + +#endif +} + // Note: when the ACES tonemapper is selected the grading steps will be done using ACES spaces float3 ColorGrade(float3 colorLutSpace) { // Switch back to linear +#ifdef HDR_OUTPUT + // For LUT purposes, we assume 1.0 == 100 nits (max PQ value is 10k nits) + float3 colorLinear = PQToLinear(colorLutSpace, 100.0f); +#else float3 colorLinear = LogCToLinear(colorLutSpace); +#endif // White balance in LMS space float3 colorLMS = LinearToLMS(colorLinear); @@ -79,19 +151,11 @@ float3 ColorGrade(float3 colorLutSpace) colorLinear = LMSToLinear(colorLMS); // Do contrast in log after white balance - #if defined(TONEMAPPING_ACES) - float3 colorLog = ACES_to_ACEScc(unity_to_ACES(colorLinear)); - #else - float3 colorLog = LinearToLogC(colorLinear); - #endif + float3 colorLog = RotateToColorGradingSpace_LinearToLog(colorLinear); colorLog = (colorLog - ACEScc_MIDGRAY) * _HueSatCon.z + ACEScc_MIDGRAY; - #if defined(TONEMAPPING_ACES) - colorLinear = ACES_to_ACEScg(ACEScc_to_ACES(colorLog)); - #else - colorLinear = LogCToLinear(colorLog); - #endif + colorLinear = RotateToColorGradingSpace_LogToLinear(colorLog); // Color filter is just an unclipped multiplier colorLinear *= _ColorFilter.xyz; @@ -183,20 +247,22 @@ float3 ColorGrade(float3 colorLutSpace) colorLinear = FastTonemapInvert(colorLinear); colorLinear = max(0.0, colorLinear); - return colorLinear; + + return RotateToColorGradeOutputSpace(colorLinear); } // Used for debugging - see the ColorGrading option in FrameSettings float3 NeutralColorGrade(float3 colorLutSpace) { // Switch back to linear +#ifdef HDR_OUTPUT + // For LUT purposes, we assume 1.0 == 100 nits (max PQ value is 10k nits) + float3 colorLinear = PQToLinear(colorLutSpace, 100.0f); +#else float3 colorLinear = LogCToLinear(colorLutSpace); +#endif - #if defined(TONEMAPPING_ACES) - colorLinear = ACES_to_ACEScg(unity_to_ACES(colorLinear)); - #endif - - return colorLinear; + return RotateToColorGradeOutputSpace(colorLinear); } float3 Tonemap(float3 colorLinear) @@ -226,6 +292,23 @@ float3 Tonemap(float3 colorLinear) return colorLinear; } + +float3 ProcessColorForHDR(float3 gradedColor) +{ +#ifdef HDR_OUTPUT + +#ifdef TONEMAPPING_ACES + gradedColor = ACEScg_to_ACES(gradedColor); + return HDRMappingACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); +#else + return HDRMappingFromRec2020(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, _HueShift, true); +#endif + +#endif + return gradedColor; +} + + // Note: according to the specs the maximum thread group size for Metal/Desktop is 1024. 8x8x8 is // 512 so it shouldn't be an issue... except with some Intel chipsets where for some reason it won't // allow anything higher than 256 threads. We'll use 4x4x4 then. @@ -238,6 +321,7 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) // Lut space // We use Alexa LogC (El 1000) to store the LUT as it provides a good enough range (~58.85666) // and is good enough to be stored in fp16 without losing precision in the darks + // If HDR Output is enabled, then the LUT space is PQ. float3 colorLutSpace = float3(dispatchThreadId) * _Size.yyy; // Color grade & tonemap @@ -253,7 +337,11 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) gradedColor = NeutralColorGrade(gradedColor); } +#ifdef HDR_OUTPUT + gradedColor = ProcessColorForHDR(gradedColor); +#else gradedColor = Tonemap(gradedColor); +#endif _OutputTexture[dispatchThreadId] = float4(max(gradedColor, 0.0), 1.0); } diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPost.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPost.compute index 2a99fee657e..49c4fefd98c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPost.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPost.compute @@ -4,7 +4,6 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/UberPostFeatures.cs.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/BloomCommon.hlsl" - #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch #pragma kernel Uber @@ -14,8 +13,12 @@ #pragma multi_compile _ LENS_DISTORTION #pragma multi_compile _ ENABLE_ALPHA #pragma multi_compile _ GAMMA2_OUTPUT +#pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/PostProcessDefines.hlsl" +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" +#endif TEXTURE2D_X(_InputTexture); TEXTURE2D_X(_BloomTexture); @@ -221,8 +224,16 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID) // Move from linear to LogC float3 colorLutSpace = saturate(LinearToLogC(color.xyz)); +#ifndef HDR_OUTPUT // Color lookup in the LogC lut color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); +#else + // We use the Gran Turismo Approx which has a somewhat small error vs accurate https://www.desmos.com/calculator/5jdfc4pgtk + // TODO: Evaluate whether we should use accurate version as it is not *that* more expensive. Also, consider using Patry if max nits is below 1400 + // We multiply by 100 as in lut space 1 = 100 nits. + colorLutSpace = LinearToPQForLUT(color.xyz * 100.0f); + color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); +#endif } // Alpha mask diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs index 8a94e24052b..e0c38704e98 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -182,6 +182,7 @@ internal enum HDProfileId // Misc VolumeUpdate, CustomPassVolumeUpdate, + OffscreenUIRendering, // XR XRMirrorView, @@ -232,6 +233,7 @@ internal enum HDProfileId SetResolutionGroup, FinalPost, FinalImageHistogram, + HDRDebugData, CustomPostProcessBeforeTAA, CustomPostProcessBeforePP, CustomPostProcessAfterPPBlurs, diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs index e016be9dabc..c98461dfa2d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs @@ -20,6 +20,7 @@ public partial class HDRenderPipeline Material m_DebugFullScreen; Material m_DebugColorPicker; Material m_DebugExposure; + Material m_DebugHDROutput; Material m_DebugViewTilesMaterial; Material m_DebugHDShadowMapMaterial; Material m_DebugLocalVolumetricFogMaterial; @@ -46,6 +47,7 @@ void InitializeDebug() m_DebugFullScreen = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugFullScreenPS); m_DebugColorPicker = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugColorPickerPS); m_DebugExposure = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugExposurePS); + m_DebugHDROutput = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugHDRPS); m_DebugViewTilesMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugViewTilesPS); m_DebugHDShadowMapMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugHDShadowMapPS); m_DebugLocalVolumetricFogMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.debugLocalVolumetricFogAtlasPS); @@ -63,6 +65,7 @@ void CleanupDebug() CoreUtils.Destroy(m_DebugFullScreen); CoreUtils.Destroy(m_DebugColorPicker); CoreUtils.Destroy(m_DebugExposure); + CoreUtils.Destroy(m_DebugHDROutput); CoreUtils.Destroy(m_DebugViewTilesMaterial); CoreUtils.Destroy(m_DebugHDShadowMapMaterial); CoreUtils.Destroy(m_DebugLocalVolumetricFogMaterial); @@ -96,6 +99,11 @@ bool NeedExposureDebugMode(DebugDisplaySettings debugSettings) return debugSettings.data.lightingDebugSettings.exposureDebugMode != ExposureDebugMode.None; } + bool NeedHDRDebugMode(DebugDisplaySettings debugSettings) + { + return debugSettings.data.lightingDebugSettings.hdrDebugMode != HDRDebugMode.None; + } + bool NeedsFullScreenDebugMode() { bool fullScreenDebugEnabled = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode != FullScreenDebugMode.None; @@ -871,6 +879,120 @@ void GenerateDebugImageHistogram(RenderGraph renderGraph, HDCamera hdCamera, Tex } } + class GenerateHDRDebugData + { + public ComputeShader generateXYMappingCS; + public TextureHandle xyBuffer; + + public int debugXYGenKernel; + public int cameraWidth; + public int cameraHeight; + public Vector4 debugParameters; + + public TextureHandle source; + } + + TextureHandle GenerateDebugHDRxyMapping(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle source) + { + if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.hdrDebugMode == HDRDebugMode.None) + return TextureHandle.nullHandle; + + using (var builder = renderGraph.AddRenderPass("Generate HDR debug data", out var passData, ProfilingSampler.Get(HDProfileId.HDRDebugData))) + { + passData.generateXYMappingCS = defaultResources.shaders.debugHDRxyMappingCS; + passData.debugXYGenKernel = passData.generateXYMappingCS.FindKernel("KCIExyGen"); + passData.cameraWidth = postProcessViewportSize.x; + passData.cameraHeight = postProcessViewportSize.y; + passData.source = builder.ReadTexture(source); + + passData.xyBuffer = builder.ReadWriteTexture(renderGraph.CreateTexture(new TextureDesc(k_SizeOfHDRXYMapping, k_SizeOfHDRXYMapping, true, true) + { colorFormat = GraphicsFormat.R32_SFloat, enableRandomWrite = true, clearBuffer = true, name = "HDR_xyMapping" })); + + int gamut = 1; + if (HDROutputIsActive()) + { + if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + gamut = 1; + else if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) + gamut = 2; + } + passData.debugParameters = new Vector4(k_SizeOfHDRXYMapping, k_SizeOfHDRXYMapping, 0, gamut); + + builder.SetRenderFunc( + (GenerateHDRDebugData data, RenderGraphContext ctx) => + { + ctx.cmd.SetComputeTextureParam(data.generateXYMappingCS, data.debugXYGenKernel, HDShaderIDs._SourceTexture, data.source); + ctx.cmd.SetComputeVectorParam(data.generateXYMappingCS, HDShaderIDs._HDRxyBufferDebugParams, data.debugParameters); + ctx.cmd.SetComputeTextureParam(data.generateXYMappingCS, data.debugXYGenKernel, HDShaderIDs._xyBuffer, data.xyBuffer); + + int threadGroupSizeX = 8; + int threadGroupSizeY = 8; + int dispatchSizeX = HDUtils.DivRoundUp(data.cameraWidth, threadGroupSizeX); + int dispatchSizeY = HDUtils.DivRoundUp(data.cameraHeight, threadGroupSizeY); + int totalPixels = data.cameraWidth * data.cameraHeight; + ctx.cmd.DispatchCompute(data.generateXYMappingCS, data.debugXYGenKernel, dispatchSizeX, dispatchSizeY, 1); + }); + + source = passData.xyBuffer; + } + + return source; + } + + class DebugHDRData + { + public LightingDebugSettings lightingDebugSettings; + public Material debugHDRMaterial; + public Vector4 hdrOutputParams; + public Vector4 hdrOutputParams2; + public Vector4 hdrDebugParams; + public int debugPass; + + public ComputeBufferHandle xyMappingBuffer; + public TextureHandle colorBuffer; + public TextureHandle xyTexture; + + public TextureHandle debugFullScreenTexture; + public TextureHandle output; + } + + TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle xyBuff) + { + using (var builder = renderGraph.AddRenderPass("Debug HDR", out var passData)) + { + passData.debugHDRMaterial = m_DebugHDROutput; + passData.lightingDebugSettings = m_CurrentDebugDisplaySettings.data.lightingDebugSettings; + if (HDROutputIsActive()) + GetHDROutputParameters(hdCamera.volumeStack.GetComponent(), out passData.hdrOutputParams, out passData.hdrOutputParams2); + else + passData.hdrOutputParams.z = 1.0f; + + passData.debugPass = (int)m_CurrentDebugDisplaySettings.data.lightingDebugSettings.hdrDebugMode - 1; + passData.colorBuffer = builder.ReadTexture(colorBuffer); + passData.debugFullScreenTexture = builder.ReadTexture(m_DebugFullScreenTexture); + passData.output = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) + { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, name = "HDRDebug" })); + + passData.hdrDebugParams = new Vector4(k_SizeOfHDRXYMapping, k_SizeOfHDRXYMapping, 0, 0); + passData.xyTexture = builder.ReadTexture(xyBuff); + + builder.SetRenderFunc( + (DebugHDRData data, RenderGraphContext ctx) => + { + data.debugHDRMaterial.SetTexture(HDShaderIDs._DebugFullScreenTexture, data.debugFullScreenTexture); + data.debugHDRMaterial.SetTexture(HDShaderIDs._xyBuffer, data.xyTexture); + + data.debugHDRMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdrOutputParams); + data.debugHDRMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdrOutputParams2); + data.debugHDRMaterial.SetVector(HDShaderIDs._HDRDebugParams, data.hdrDebugParams); + + HDUtils.DrawFullScreen(ctx.cmd, data.debugHDRMaterial, data.output, null, data.debugPass); + }); + + return passData.output; + } + } + class DebugExposureData { public LightingDebugSettings lightingDebugSettings; @@ -1005,6 +1127,7 @@ TextureHandle RenderDebug(RenderGraph renderGraph, TextureHandle depthPyramidTexture, TextureHandle colorPickerDebugTexture, TextureHandle rayCountTexture, + TextureHandle xyBufferMapping, in BuildGPULightListOutput lightLists, in ShadowResult shadowResult, CullingResults cullResults, @@ -1031,6 +1154,9 @@ TextureHandle RenderDebug(RenderGraph renderGraph, if (NeedExposureDebugMode(m_CurrentDebugDisplaySettings)) output = RenderExposureDebug(renderGraph, hdCamera, colorBuffer); + if (NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) + output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer, xyBufferMapping); + if (NeedColorPickerDebug(m_CurrentDebugDisplaySettings)) output = ResolveColorPickerDebug(renderGraph, colorPickerDebugTexture, hdCamera, colorFormat); @@ -1277,6 +1403,15 @@ void PushFullScreenExposureDebugTexture(RenderGraph renderGraph, TextureHandle i } } + void PushFullScreenHDRDebugTexture(RenderGraph renderGraph, TextureHandle input, GraphicsFormat colorFormat = GraphicsFormat.R16G16B16A16_SFloat) + { + if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.hdrDebugMode != HDRDebugMode.None) + { + PushFullScreenDebugTexture(renderGraph, input, colorFormat); + } + } + + #if ENABLE_VIRTUALTEXTURES class PushFullScreenVTDebugPassData { diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index c422c895ad4..2d42c8b9f43 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs @@ -33,6 +33,7 @@ private enum SMAAStage const int k_ExposureCurvePrecision = 128; const int k_HistogramBins = 128; // Important! If this changes, need to change HistogramExposure.compute const int k_DebugImageHistogramBins = 256; // Important! If this changes, need to change HistogramExposure.compute + const int k_SizeOfHDRXYMapping = 512; readonly Color[] m_ExposureCurveColorArray = new Color[k_ExposureCurvePrecision]; readonly int[] m_ExposureVariants = new int[4]; @@ -65,6 +66,8 @@ private enum SMAAStage int m_LutSize; GraphicsFormat m_LutFormat; HableCurve m_HableCurve; + RTHandle m_GradingAndTonemappingLUT; + int m_LutHash = -1; //Viewport information Vector2Int m_AfterDynamicResUpscaleRes = new Vector2Int(1, 1); @@ -246,6 +249,8 @@ void InitializePostProcess() SetExposureTextureToEmpty(m_EmptyExposureTexture); + m_GradingAndTonemappingLUT = RTHandles.Alloc(m_LutSize, m_LutSize, m_LutSize, dimension: TextureDimension.Tex3D, colorFormat: m_LutFormat, filterMode: FilterMode.Bilinear, wrapMode: TextureWrapMode.Clamp, enableRandomWrite: true); + resGroup = ResolutionGroup.BeforeDynamicResUpscale; m_DLSSPass = DLSSPass.Create(m_GlobalSettings); @@ -276,6 +281,8 @@ bool PostProcessEnableAlpha() void CleanupPostProcess() { RTHandles.Release(m_EmptyExposureTexture); + RTHandles.Release(m_GradingAndTonemappingLUT); + m_GradingAndTonemappingLUT = null; m_EmptyExposureTexture = null; CoreUtils.Destroy(m_ExposureCurveTexture); @@ -392,6 +399,26 @@ void BeginPostProcessFrame(CommandBuffer cmd, HDCamera camera, HDRenderPipeline m_DLSSPass.BeginFrame(camera); } + int ComputeLUTHash() + { + return m_Tonemapping.GetHashCode() * 23 + + m_WhiteBalance.GetHashCode() * 23 + + m_ColorAdjustments.GetHashCode() * 23 + + m_ChannelMixer.GetHashCode() * 23 + + m_SplitToning.GetHashCode() * 23 + + m_LiftGammaGain.GetHashCode() * 23 + + m_ShadowsMidtonesHighlights.GetHashCode() * 23 + + m_Curves.GetHashCode() * 23 + + HDROutputIsActive().GetHashCode() +#if UNITY_EDITOR + * 23 + + m_GlobalSettings.colorGradingSpace.GetHashCode() * 23 + + + UnityEditor.PlayerSettings.D3DHDRBitDepth.GetHashCode() + +#endif + ; + } + static void ValidateComputeBuffer(ref ComputeBuffer cb, int size, int stride, ComputeBufferType type = ComputeBufferType.Default) { if (cb == null || cb.count < size) @@ -436,11 +463,12 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, in PrepassOutput prepassOutput, TextureHandle inputColor, TextureHandle backBuffer, + TextureHandle uiBuffer, + TextureHandle afterPostProcessBuffer, CullingResults cullResults, HDCamera hdCamera) { bool postPRocessIsFinalPass = HDUtils.PostProcessIsFinalPass(hdCamera); - TextureHandle afterPostProcessBuffer = RenderAfterPostProcessObjects(renderGraph, hdCamera, cullResults, prepassOutput); TextureHandle dest = postPRocessIsFinalPass ? backBuffer : renderGraph.CreateTexture( new TextureDesc(Vector2.one, false, true) { colorFormat = GetColorBufferFormat(), name = "Intermediate Postprocess buffer" }); @@ -526,7 +554,7 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, source = LensFlareDataDrivenPass(renderGraph, hdCamera, source, depthBuffer); TextureHandle bloomTexture = BloomPass(renderGraph, hdCamera, source); - TextureHandle logLutOutput = ColorGradingPass(renderGraph, hdCamera); + TextureHandle logLutOutput = ColorGradingPass(renderGraph); source = UberPass(renderGraph, hdCamera, logLutOutput, bloomTexture, source); PushFullScreenDebugTexture(renderGraph, source, hdCamera.postProcessRTScales, FullScreenDebugMode.ColorLog); @@ -547,7 +575,7 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, source = RobustContrastAdaptiveSharpeningPass(renderGraph, hdCamera, source); } - FinalPass(renderGraph, hdCamera, afterPostProcessBuffer, alphaTexture, dest, source, m_BlueNoise, flipYInPostProcess); + FinalPass(renderGraph, hdCamera, afterPostProcessBuffer, alphaTexture, dest, source, uiBuffer, m_BlueNoise, flipYInPostProcess); bool currFrameIsTAAUpsampled = hdCamera.IsTAAUEnabled(); bool cameraWasRunningTAA = hdCamera.previousFrameWasTAAUpsampled; @@ -592,61 +620,6 @@ void RestoreNonjitteredMatrices(RenderGraph renderGraph, HDCamera hdCamera) } } - #region AfterPostProcess - class AfterPostProcessPassData - { - public ShaderVariablesGlobal globalCB; - public HDCamera hdCamera; - public RendererListHandle opaqueAfterPostprocessRL; - public RendererListHandle transparentAfterPostprocessRL; - } - - TextureHandle RenderAfterPostProcessObjects(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cullResults, in PrepassOutput prepassOutput) - { - if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) - return renderGraph.defaultResources.blackTextureXR; - - // We render AfterPostProcess objects first into a separate buffer that will be composited in the final post process pass - using (var builder = renderGraph.AddRenderPass("After Post-Process Objects", out var passData, ProfilingSampler.Get(HDProfileId.AfterPostProcessingObjects))) - { - bool useDepthBuffer = !hdCamera.RequiresCameraJitter() && hdCamera.frameSettings.IsEnabled(FrameSettingsField.ZTestAfterPostProcessTAA); - - passData.globalCB = m_ShaderVariablesGlobalCB; - passData.hdCamera = hdCamera; - passData.opaqueAfterPostprocessRL = builder.UseRendererList(renderGraph.CreateRendererList( - CreateOpaqueRendererListDesc(cullResults, hdCamera.camera, HDShaderPassNames.s_ForwardOnlyName, renderQueueRange: HDRenderQueue.k_RenderQueue_AfterPostProcessOpaque))); - passData.transparentAfterPostprocessRL = builder.UseRendererList(renderGraph.CreateRendererList( - CreateTransparentRendererListDesc(cullResults, hdCamera.camera, HDShaderPassNames.s_ForwardOnlyName, renderQueueRange: HDRenderQueue.k_RenderQueue_AfterPostProcessTransparent))); - - var output = builder.UseColorBuffer(renderGraph.CreateTexture( - new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, clearBuffer = true, clearColor = Color.black, name = "OffScreen AfterPostProcess" }), 0); - if (useDepthBuffer) - builder.UseDepthBuffer(prepassOutput.resolvedDepthBuffer, DepthAccess.ReadWrite); - - // If the pass is culled at runtime from the RendererList API, set the appropriate fall-back for the output - // Here we need an opaque black texture as default (alpha = 1) due to the way the output of this pass is composed with the post-process output (see FinalPass.shader) - output.SetFallBackResource(renderGraph.defaultResources.blackTextureXR); - - builder.SetRenderFunc( - (AfterPostProcessPassData data, RenderGraphContext ctx) => - { - UpdateOffscreenRenderingConstants(ref data.globalCB, true, 1.0f); - ConstantBuffer.PushGlobal(ctx.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal); - - DrawOpaqueRendererList(ctx.renderContext, ctx.cmd, data.hdCamera.frameSettings, data.opaqueAfterPostprocessRL); - // Setup off-screen transparency here - DrawTransparentRendererList(ctx.renderContext, ctx.cmd, data.hdCamera.frameSettings, data.transparentAfterPostprocessRL); - - UpdateOffscreenRenderingConstants(ref data.globalCB, false, 1.0f); - ConstantBuffer.PushGlobal(ctx.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal); - }); - - return output; - } - } - - #endregion - #region DLSS class DLSSColorMaskPassData { @@ -3620,7 +3593,6 @@ private void SetCurrentResolutionGroup(RenderGraph renderGraph, HDCamera camera, #endregion - #region Panini Projection Vector2 CalcViewExtents(HDCamera camera) { @@ -4002,6 +3974,9 @@ class ColorGradingPassData public Vector4 splitShadows; public Vector4 splitHighlights; + public Vector4 hdroutParameters; + public Vector4 hdroutParameters2; + public ColorCurves curves; public HableCurve hableCurve; @@ -4018,6 +3993,12 @@ class ColorGradingPassData void PrepareColorGradingParameters(ColorGradingPassData passData) { passData.tonemappingMode = m_TonemappingFS ? m_Tonemapping.mode.value : TonemappingMode.None; + bool tonemappingIsActive = m_Tonemapping.IsActive() && m_TonemappingFS; + if (HDROutputIsActive() && m_TonemappingFS) + { + passData.tonemappingMode = m_Tonemapping.GetHDRTonemappingMode(); + tonemappingIsActive = m_TonemappingFS && passData.tonemappingMode != TonemappingMode.None; + } passData.builderCS = defaultResources.shaders.lutBuilder3DCS; passData.builderKernel = passData.builderCS.FindKernel("KBuild"); @@ -4025,12 +4006,12 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) // Setup lut builder compute & grab the kernel we need passData.builderCS.shaderKeywords = null; - if (m_Tonemapping.IsActive() && m_TonemappingFS) + if (tonemappingIsActive) { switch (passData.tonemappingMode) { case TonemappingMode.Neutral: passData.builderCS.EnableKeyword("TONEMAPPING_NEUTRAL"); break; - case TonemappingMode.ACES: passData.builderCS.EnableKeyword("TONEMAPPING_ACES"); break; + case TonemappingMode.ACES: passData.builderCS.EnableKeyword(m_Tonemapping.useFullACES.value ? "TONEMAPPING_ACES_FULL" : "TONEMAPPING_ACES_APPROX"); break; case TonemappingMode.Custom: passData.builderCS.EnableKeyword("TONEMAPPING_CUSTOM"); break; case TonemappingMode.External: passData.builderCS.EnableKeyword("TONEMAPPING_EXTERNAL"); break; } @@ -4040,6 +4021,25 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } + if (HDROutputIsActive() && m_TonemappingFS) + { + if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + { + passData.builderCS.EnableKeyword("HDR_OUTPUT_SCRGB"); + } + else + { + passData.builderCS.EnableKeyword("HDR_OUTPUT_REC2020"); + } + + GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); + } + + if (m_GlobalSettings.colorGradingSpace == ColorGradingSpace.sRGB) + passData.builderCS.EnableKeyword("GRADE_IN_SRGB"); + else if (m_GlobalSettings.colorGradingSpace == ColorGradingSpace.AcesCg) + passData.builderCS.EnableKeyword("GRADE_IN_ACESCG"); + passData.lutSize = m_LutSize; //passData.colorFilter; @@ -4097,6 +4097,49 @@ static Vector3 GetColorBalanceCoeffs(float temperature, float tint) return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z); } + public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out Vector4 hdrOutputParameters1, out Vector4 hdrOutputParameters2) + { + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var paperWhite = HDROutputSettings.main.paperWhiteNits; + int eetfMode = 0; + float hueShift = 0.0f; + + TonemappingMode hdrTonemapMode = tonemappingComponent.GetHDRTonemappingMode(); + + if (hdrTonemapMode == TonemappingMode.Neutral) + { + hueShift = tonemappingComponent.hueShiftAmount.value; + + bool luminanceOnly = hueShift == 0; + if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.BT2390) + { + eetfMode = (int)HDRRangeReduction.BT2390; + } + if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.Reinhard) + { + eetfMode = (int)HDRRangeReduction.Reinhard; + } + } + if (hdrTonemapMode == TonemappingMode.ACES) + { + eetfMode = (int)tonemappingComponent.acesPreset.value; + } + + if (!tonemappingComponent.detectPaperWhite.value) + { + paperWhite = tonemappingComponent.paperWhite.value; + } + if (!tonemappingComponent.detectBrightnessLimits.value) + { + minNits = (int)tonemappingComponent.minNits.value; + maxNits = (int)tonemappingComponent.maxNits.value; + } + + hdrOutputParameters1 = new Vector4(minNits, maxNits, paperWhite, HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : 2); + hdrOutputParameters2 = new Vector4(eetfMode, hueShift, paperWhite, 0); + } + void ComputeShadowsMidtonesHighlights(out Vector4 shadows, out Vector4 midtones, out Vector4 highlights, out Vector4 limits) { float weight; @@ -4190,24 +4233,23 @@ void ComputeSplitToning(out Vector4 shadows, out Vector4 highlights) highlights.w = 0f; } - TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) + // TODO: This can easily go async. + TextureHandle ColorGradingPass(RenderGraph renderGraph) { + TextureHandle logLut = renderGraph.ImportTexture(m_GradingAndTonemappingLUT); + + // Verify hash + var currentGradingHash = ComputeLUTHash(); + + // The lut we have already is ok. + if (currentGradingHash == m_LutHash) + return logLut; + + // Else we update the hash and we recompute the LUT. + m_LutHash = currentGradingHash; + using (var builder = renderGraph.AddRenderPass("Color Grading", out var passData, ProfilingSampler.Get(HDProfileId.ColorGradingLUTBuilder))) { - TextureHandle logLut = renderGraph.CreateTexture(new TextureDesc(m_LutSize, m_LutSize) - { - name = "Color Grading Log Lut", - dimension = TextureDimension.Tex3D, - slices = m_LutSize, - depthBufferBits = DepthBits.None, - colorFormat = m_LutFormat, - filterMode = FilterMode.Bilinear, - wrapMode = TextureWrapMode.Clamp, - anisoLevel = 0, - useMipMap = false, - enableRandomWrite = true - }); - PrepareColorGradingParameters(passData); passData.logLut = builder.WriteTexture(logLut); @@ -4266,6 +4308,9 @@ TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) ctx.cmd.SetComputeVectorParam(builderCS, HDShaderIDs._LogLut3D_Params, new Vector4(1f / data.lutSize, data.lutSize - 1f, data.lutContribution, 0f)); } + ctx.cmd.SetComputeVectorParam(builderCS, HDShaderIDs._HDROutputParams, data.hdroutParameters); + ctx.cmd.SetComputeVectorParam(builderCS, HDShaderIDs._HDROutputParams2, data.hdroutParameters2); + // Misc parameters ctx.cmd.SetComputeVectorParam(builderCS, HDShaderIDs._Params, data.miscParams); @@ -4512,6 +4557,18 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle passData.uberPostCS.EnableKeyword("GAMMA2_OUTPUT"); } + if (HDROutputIsActive()) + { + if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + { + passData.uberPostCS.EnableKeyword("HDR_OUTPUT_SCRGB"); + } + else + { + passData.uberPostCS.EnableKeyword("HDR_OUTPUT_REC2020"); + } + } + passData.outputColorLog = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode == FullScreenDebugMode.ColorLog; passData.width = postProcessViewportSize.x; passData.height = postProcessViewportSize.y; @@ -4861,13 +4918,20 @@ class FinalPassData public bool ditheringEnabled; + public Vector4 hdroutParameters; + public Vector4 hdroutParameters2; + public int outputColorSpace; + + public TextureHandle inputTest; + public TextureHandle source; public TextureHandle afterPostProcessTexture; public TextureHandle alphaTexture; + public TextureHandle uiBuffer; public TextureHandle destination; } - void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPostProcessTexture, TextureHandle alphaTexture, TextureHandle finalRT, TextureHandle source, BlueNoise blueNoise, bool flipY) + void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPostProcessTexture, TextureHandle alphaTexture, TextureHandle finalRT, TextureHandle source, TextureHandle uiBuffer, BlueNoise blueNoise, bool flipY) { using (var builder = renderGraph.AddRenderPass("Final Pass", out var passData, ProfilingSampler.Get(HDProfileId.FinalPost))) { @@ -4886,7 +4950,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.useFXAA = hdCamera.antialiasing == HDAdditionalCameraData.AntialiasingMode.FastApproximateAntialiasing && !passData.dynamicResIsOn && m_AntialiasingFS; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS; + passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !HDROutputIsActive(); // TODO: Investigate how to make grain work with HDR. if (m_FilmGrain.type.value != FilmGrainLookup.Custom) passData.filmGrainTexture = defaultResources.textures.filmGrainTex[(int)m_FilmGrain.type.value]; else @@ -4895,12 +4959,23 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.filmGrainResponse = m_FilmGrain.response.value; // Dithering - passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS; + passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(); passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); passData.alphaTexture = builder.ReadTexture(alphaTexture); passData.destination = builder.WriteTexture(finalRT); + passData.uiBuffer = builder.ReadTexture(uiBuffer); + + passData.outputColorSpace = 0; + if (HDROutputIsActive()) + { + // This looks dumb now that we only have two options, but we'll have more at some point. + passData.outputColorSpace = HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 ? 1 : 0; + GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); + } + builder.SetRenderFunc( (FinalPassData data, RenderGraphContext ctx) => @@ -4989,6 +5064,21 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); + bool processHDR = HDROutputIsActive() && HDUtils.PostProcessIsFinalPass(data.hdCamera); + if (processHDR) + { + if (data.hdroutParameters.w == 1) + data.finalPassMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); + else + data.finalPassMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); + + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdroutParameters); + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdroutParameters2); + + } + + finalPassMaterial.SetTexture(HDShaderIDs._UITexture, data.uiBuffer); + finalPassMaterial.SetVector(HDShaderIDs._UVTransform, data.flipY ? new Vector4(1.0f, -1.0f, 0.0f, 1.0f) @@ -5008,7 +5098,12 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo backBufferRect.x = backBufferRect.y = 0; } - if (data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + if (processHDR && data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + { + finalPassMaterial.EnableKeyword("APPLY_AFTER_POST"); + finalPassMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); + } + else if (!HDROutputIsActive() && data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) { finalPassMaterial.EnableKeyword("APPLY_AFTER_POST"); finalPassMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index c669ead4163..034d40f23db 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -85,6 +85,7 @@ void RecordRenderGraph(RenderRequest renderRequest, // Once render graph move is implemented, we can probably remove the branch and this. ShadowResult shadowResult = new ShadowResult(); BuildGPULightListOutput gpuLightListOutput = new BuildGPULightListOutput(); + TextureHandle uiBuffer = m_RenderGraph.defaultResources.blackTextureXR; if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() && m_CurrentDebugDisplaySettings.IsFullScreenDebugPassEnabled()) { @@ -184,7 +185,10 @@ void RecordRenderGraph(RenderRequest renderRequest, // No need for old stencil values here since from transparent on different features are tagged ClearStencilBuffer(m_RenderGraph, hdCamera, prepassOutput.depthBuffer); - colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedNormalBuffer, vtFeedbackBuffer, currentColorPyramid, volumetricLighting, rayCountTexture, m_SkyManager.GetSkyReflection(hdCamera), gpuLightListOutput, ref prepassOutput, shadowResult, cullingResults, customPassCullingResults, aovRequest, aovCustomPassBuffers); + colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedNormalBuffer, vtFeedbackBuffer, currentColorPyramid, volumetricLighting, rayCountTexture, m_SkyManager.GetSkyReflection(hdCamera), gpuLightListOutput, ref prepassOutput, + shadowResult, cullingResults, customPassCullingResults, aovRequest, aovCustomPassBuffers); + + uiBuffer = RenderTransparentUI(m_RenderGraph, hdCamera, prepassOutput.depthBuffer); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) { @@ -257,10 +261,14 @@ void RecordRenderGraph(RenderRequest renderRequest, aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers); } - TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, cullingResults, hdCamera); + TextureHandle afterPostProcessBuffer = RenderAfterPostProcessObjects(m_RenderGraph, hdCamera, cullingResults, prepassOutput); + TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, uiBuffer, afterPostProcessBuffer, cullingResults, hdCamera); + + var xyMapping = GenerateDebugHDRxyMapping(m_RenderGraph, hdCamera, postProcessDest); GenerateDebugImageHistogram(m_RenderGraph, hdCamera, postProcessDest); PushFullScreenExposureDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); + PushFullScreenHDRDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); ResetCameraSizeForAfterPostProcess(m_RenderGraph, hdCamera, commandBuffer); @@ -281,6 +289,7 @@ void RecordRenderGraph(RenderRequest renderRequest, prepassOutput.depthPyramidTexture, colorPickerTexture, rayCountTexture, + xyMapping, gpuLightListOutput, shadowResult, cullingResults, @@ -290,7 +299,7 @@ void RecordRenderGraph(RenderRequest renderRequest, for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, viewIndex); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive()); } if (aovRequest.isValid) @@ -303,7 +312,7 @@ void RecordRenderGraph(RenderRequest renderRequest, { if (target.targetDepth != null) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, m_RenderGraph.ImportTexture(target.targetDepth), viewIndex); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, m_RenderGraph.ImportTexture(target.targetDepth), uiBuffer, afterPostProcessBuffer, viewIndex, outputsToHDR: false); } } @@ -317,6 +326,8 @@ void RecordRenderGraph(RenderRequest renderRequest, RenderWireOverlay(m_RenderGraph, hdCamera, backBuffer); RenderGizmos(m_RenderGraph, hdCamera, GizmoSubset.PostImageEffects); + + RenderScreenSpaceOverlayUI(m_RenderGraph, hdCamera, backBuffer); } } @@ -359,12 +370,16 @@ class FinalBlitPassData public int dstTexArraySlice; public Rect viewport; public Material blitMaterial; + public Vector4 hdrOutputParmeters; + public bool applyAfterPP; + public TextureHandle uiTexture; + public TextureHandle afterPostProcessTexture; public TextureHandle source; public TextureHandle destination; } - void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle source, TextureHandle destination, int viewIndex) + void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle source, TextureHandle destination, TextureHandle uiTexture, TextureHandle afterPostProcessTexture, int viewIndex, bool outputsToHDR) { using (var builder = renderGraph.AddRenderPass("Final Blit (Dev Build Only)", out var passData)) { @@ -383,27 +398,72 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH passData.flip = hdCamera.flipYMode == HDAdditionalCameraData.FlipYMode.ForceFlipY || hdCamera.isMainGameView; passData.blitMaterial = HDUtils.GetBlitMaterial(TextureXR.useTexArray ? TextureDimension.Tex2DArray : TextureDimension.Tex2D, singleSlice: passData.srcTexArraySlice >= 0); passData.source = builder.ReadTexture(source); + passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); passData.destination = builder.WriteTexture(destination); + passData.applyAfterPP = false; + + if (outputsToHDR) + { + passData.blitMaterial = m_FinalBlitWithOETF; + GetHDROutputParameters(m_Tonemapping, out passData.hdrOutputParmeters, out var unused); + passData.uiTexture = builder.ReadTexture(uiTexture); + passData.applyAfterPP = hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess) && !NeedHDRDebugMode(m_CurrentDebugDisplaySettings); + } + else + { + passData.hdrOutputParmeters = new Vector4(-1.0f, -1.0f, -1.0f, -1.0f); + } builder.SetRenderFunc( (FinalBlitPassData data, RenderGraphContext context) => { + var propertyBlock = context.renderGraphPool.GetTempMaterialPropertyBlock(); RTHandle sourceTexture = data.source; - // Here we can't use the viewport scale provided in hdCamera. The reason is that this scale is for internal rendering before post process with dynamic resolution factored in. - // Here the input texture is already at the viewport size but may be smaller than the RT itself (because of the RTHandle system) so we compute the scale specifically here. - var scaleBias = new Vector4((float)data.viewport.width / sourceTexture.rt.width, (float)data.viewport.height / sourceTexture.rt.height, 0.0f, 0.0f); - if (data.flip) + // We are in HDR mode so the final blit is different + if (data.hdrOutputParmeters.x >= 0) { - scaleBias.w = scaleBias.y; - scaleBias.y *= -1; + data.blitMaterial.SetInt(HDShaderIDs._NeedsFlip, data.flip ? 1 : 0); + propertyBlock.SetTexture(HDShaderIDs._UITexture, data.uiTexture); + propertyBlock.SetTexture(HDShaderIDs._InputTexture, sourceTexture); + + propertyBlock.SetVector(HDShaderIDs._HDROutputParams, data.hdrOutputParmeters); + + data.blitMaterial.shaderKeywords = null; + + if (data.hdrOutputParmeters.w == 1) + data.blitMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); + else + data.blitMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); + + if (data.applyAfterPP) + { + data.blitMaterial.EnableKeyword("APPLY_AFTER_POST"); + data.blitMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); + } + else + { + data.blitMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, TextureXR.GetBlackTexture()); + } } + else + { + // Here we can't use the viewport scale provided in hdCamera. The reason is that this scale is for internal rendering before post process with dynamic resolution factored in. + // Here the input texture is already at the viewport size but may be smaller than the RT itself (because of the RTHandle system) so we compute the scale specifically here. + var scaleBias = new Vector4((float)data.viewport.width / sourceTexture.rt.width, (float)data.viewport.height / sourceTexture.rt.height, 0.0f, 0.0f); - var propertyBlock = context.renderGraphPool.GetTempMaterialPropertyBlock(); - propertyBlock.SetTexture(HDShaderIDs._BlitTexture, sourceTexture); - propertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBias); - propertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, 0); - propertyBlock.SetInt(HDShaderIDs._BlitTexArraySlice, data.srcTexArraySlice); + if (data.flip) + { + scaleBias.w = scaleBias.y; + scaleBias.y *= -1; + } + + propertyBlock.SetTexture(HDShaderIDs._BlitTexture, sourceTexture); + propertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBias); + propertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, 0); + propertyBlock.SetInt(HDShaderIDs._BlitTexArraySlice, data.srcTexArraySlice); + + } HDUtils.DrawFullScreen(context.cmd, data.viewport, data.blitMaterial, data.destination, propertyBlock, 0, data.dstTexArraySlice); }); } @@ -811,6 +871,97 @@ void RenderForwardError(RenderGraph renderGraph, } } + class RenderOffscreenUIData + { + public Camera camera; + public FrameSettings frameSettings; + } + + TextureHandle CreateOffscreenUIBuffer(RenderGraph renderGraph, MSAASamples msaaSamples) + { + return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) + { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); + } + + TextureHandle RenderTransparentUI(RenderGraph renderGraph, + HDCamera hdCamera, + TextureHandle depthBuffer) + { + var output = renderGraph.defaultResources.blackTextureXR; + if (HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && !NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) + { + using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) + { + output = builder.UseColorBuffer(CreateOffscreenUIBuffer(renderGraph, hdCamera.msaaSamples), 0); + builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite); + + passData.camera = hdCamera.camera; + passData.frameSettings = hdCamera.frameSettings; + + builder.SetRenderFunc((RenderOffscreenUIData data, RenderGraphContext context) => + { + context.renderContext.ExecuteCommandBuffer(context.cmd); + context.cmd.Clear(); + context.renderContext.DrawUIOverlay(data.camera); + }); + } + } + + return output; + } + + class AfterPostProcessPassData + { + public ShaderVariablesGlobal globalCB; + public HDCamera hdCamera; + public RendererListHandle opaqueAfterPostprocessRL; + public RendererListHandle transparentAfterPostprocessRL; + } + + TextureHandle RenderAfterPostProcessObjects(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cullResults, in PrepassOutput prepassOutput) + { + if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + return renderGraph.defaultResources.blackTextureXR; + + // We render AfterPostProcess objects first into a separate buffer that will be composited in the final post process pass + using (var builder = renderGraph.AddRenderPass("After Post-Process Objects", out var passData, ProfilingSampler.Get(HDProfileId.AfterPostProcessingObjects))) + { + bool useDepthBuffer = !hdCamera.RequiresCameraJitter() && hdCamera.frameSettings.IsEnabled(FrameSettingsField.ZTestAfterPostProcessTAA); + + passData.globalCB = m_ShaderVariablesGlobalCB; + passData.hdCamera = hdCamera; + passData.opaqueAfterPostprocessRL = builder.UseRendererList(renderGraph.CreateRendererList( + CreateOpaqueRendererListDesc(cullResults, hdCamera.camera, HDShaderPassNames.s_ForwardOnlyName, renderQueueRange: HDRenderQueue.k_RenderQueue_AfterPostProcessOpaque))); + passData.transparentAfterPostprocessRL = builder.UseRendererList(renderGraph.CreateRendererList( + CreateTransparentRendererListDesc(cullResults, hdCamera.camera, HDShaderPassNames.s_ForwardOnlyName, renderQueueRange: HDRenderQueue.k_RenderQueue_AfterPostProcessTransparent))); + + var output = builder.UseColorBuffer(renderGraph.CreateTexture( + new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, clearBuffer = true, clearColor = Color.black, name = "OffScreen AfterPostProcess" }), 0); + if (useDepthBuffer) + builder.UseDepthBuffer(prepassOutput.resolvedDepthBuffer, DepthAccess.ReadWrite); + + // If the pass is culled at runtime from the RendererList API, set the appropriate fall-back for the output + // Here we need an opaque black texture as default (alpha = 1) due to the way the output of this pass is composed with the post-process output (see FinalPass.shader) + output.SetFallBackResource(renderGraph.defaultResources.blackTextureXR); + + builder.SetRenderFunc( + (AfterPostProcessPassData data, RenderGraphContext ctx) => + { + UpdateOffscreenRenderingConstants(ref data.globalCB, true, 1.0f); + ConstantBuffer.PushGlobal(ctx.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal); + + DrawOpaqueRendererList(ctx.renderContext, ctx.cmd, data.hdCamera.frameSettings, data.opaqueAfterPostprocessRL); + // Setup off-screen transparency here + DrawTransparentRendererList(ctx.renderContext, ctx.cmd, data.hdCamera.frameSettings, data.transparentAfterPostprocessRL); + + UpdateOffscreenRenderingConstants(ref data.globalCB, false, 1.0f); + ConstantBuffer.PushGlobal(ctx.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal); + }); + + return output; + } + } + void RenderForwardTransparent(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, @@ -1879,6 +2030,31 @@ void RenderWireOverlay(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle #endif } + class RenderScreenSpaceOverlayData + { + public Camera camera; + } + + void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) + { + if (!HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) + { + using (var builder = renderGraph.AddRenderPass("Screen Space Overlay UI", out var passData)) + { + builder.WriteTexture(colorBuffer); + passData.camera = hdCamera.camera; + + builder.SetRenderFunc( + (RenderScreenSpaceOverlayData data, RenderGraphContext ctx) => + { + ctx.renderContext.ExecuteCommandBuffer(ctx.cmd); + ctx.cmd.Clear(); + ctx.renderContext.DrawUIOverlay(data.camera); + }); + } + } + } + static void UpdateOffscreenRenderingConstants(ref ShaderVariablesGlobal cb, bool enabled, float factor) { cb._OffScreenRendering = enabled ? 1u : 0u; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 37ace55b3cb..0f748a2b9d9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -107,6 +107,7 @@ internal static HDRenderPipeline currentPipeline int m_SsrAccumulateKernel = -1; Material m_ApplyDistortionMaterial; + Material m_FinalBlitWithOETF; Material m_ClearStencilBufferMaterial; @@ -198,6 +199,31 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } + static bool HDROutputIsActive() + { + // TODO: Until we can test it, disable on Mac. + return SystemInfo.graphicsDeviceType != GraphicsDeviceType.Metal && HDROutputSettings.main.active; + } + + void SetHDRState(HDCamera camera) + { +#if UNITY_EDITOR + bool hdrInPlayerSettings = UnityEditor.PlayerSettings.useHDRDisplay; + if (hdrInPlayerSettings && HDROutputSettings.main.available) + { + if (camera.camera.cameraType != CameraType.Game) + HDROutputSettings.main.RequestHDRModeChange(false); + else + HDROutputSettings.main.RequestHDRModeChange(true); + } +#endif + // Make sure HDR auto tonemap is off + if (HDROutputSettings.main.active) + { + HDROutputSettings.main.automaticHDRTonemapping = false; + } + } + readonly SkyManager m_SkyManager = new SkyManager(); internal SkyManager skyManager { get { return m_SkyManager; } } @@ -348,6 +374,8 @@ public HDRenderPipeline(HDRenderPipelineAsset asset) m_UpsampleTransparency = CoreUtils.CreateEngineMaterial(defaultResources.shaders.upsampleTransparentPS); m_ApplyDistortionMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.applyDistortionPS); + m_FinalBlitWithOETF = CoreUtils.CreateEngineMaterial(defaultResources.shaders.compositeUIAndOETFApplyPS); + m_ClearStencilBufferMaterial = CoreUtils.CreateEngineMaterial(defaultResources.shaders.clearStencilBufferPS); @@ -498,7 +526,7 @@ void SetRenderingFeatures() GraphicsSettings.lightsUseColorTemperature = true; m_PreviousSRPBatcher = GraphicsSettings.useScriptableRenderPipelineBatching; GraphicsSettings.useScriptableRenderPipelineBatching = m_Asset.enableSRPBatcher; -#if UNITY_2020_2_OR_NEWER +#if UNITY_2020_2_OR_NEWER m_PreviousDefaultRenderingLayerMask = GraphicsSettings.defaultRenderingLayerMask; GraphicsSettings.defaultRenderingLayerMask = ShaderVariablesGlobal.DefaultRenderingLayerMask; #endif @@ -539,6 +567,8 @@ void SetRenderingFeatures() autoDefaultReflectionProbeBaking = false , enlightenLightmapper = false + , + rendersUIOverlay = true }; Lightmapping.SetDelegate(GlobalIlluminationUtils.hdLightsDelegate); @@ -715,6 +745,7 @@ protected override void Dispose(bool disposing) CoreUtils.Destroy(m_UpsampleTransparency); CoreUtils.Destroy(m_ApplyDistortionMaterial); CoreUtils.Destroy(m_ClearStencilBufferMaterial); + CoreUtils.Destroy(m_FinalBlitWithOETF); m_XRSystem.Cleanup(); m_SkyManager.Cleanup(); @@ -1024,6 +1055,7 @@ public struct Target struct HDCullingResults { public CullingResults cullingResults; + public CullingResults uiCullingResults; public CullingResults? customPassCullingResults; public HDProbeCullingResults hdProbeCullingResults; public DecalSystem.CullResult decalCullResults; @@ -1273,7 +1305,9 @@ protected override void Render(ScriptableRenderContext renderContext, Camera[] c } if (needCulling) + { skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, ref cullingResults); + } } if (additionalCameraData.hasCustomRender && additionalCameraData.fullscreenPassthrough) @@ -1950,6 +1984,7 @@ AOVRequestData aovRequest var camera = hdCamera.camera; var cullingResults = renderRequest.cullingResults.cullingResults; var customPassCullingResults = renderRequest.cullingResults.customPassCullingResults ?? cullingResults; + var uiCullingResults = renderRequest.cullingResults.uiCullingResults; var hdProbeCullingResults = renderRequest.cullingResults.hdProbeCullingResults; var decalCullingResults = renderRequest.cullingResults.decalCullResults; var target = renderRequest.target; @@ -1957,6 +1992,8 @@ AOVRequestData aovRequest // Updates RTHandle hdCamera.BeginRender(cmd); + SetHDRState(hdCamera); + if (m_RayTracingSupported) { // This call need to happen once per camera diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs index e8c40b1074a..47942161a84 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -191,6 +191,7 @@ public override Material defaultParticleMaterial public override Material defaultTerrainMaterial => globalSettings?.renderPipelineEditorResources?.materials.defaultTerrainMat; + // Array structure that allow us to manipulate the set of defines that the HD render pipeline needs List defineArray = new List(); @@ -217,7 +218,6 @@ bool UpdateDefineList(bool flagValue, string defineMacroValue) } #endif - /// /// Indicates if virtual texturing is currently enabled for this render pipeline instance. /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs index ece9bd67617..c1e493164f2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs @@ -23,6 +23,12 @@ enum LensAttenuationMode PerfectLens } + enum ColorGradingSpace + { + AcesCg = 0, + sRGB // Legacy. + } + /// /// High Definition Render Pipeline's Global Settings. /// Global settings are unique per Render Pipeline type. In HD, Global Settings contain: @@ -776,6 +782,9 @@ internal void ResetRenderingLayerNames(bool lightLayers, bool decalLayers) [SerializeField] internal LensAttenuationMode lensAttenuationMode; + [SerializeField] + internal ColorGradingSpace colorGradingSpace; + [SerializeField] internal DiffusionProfileSettings[] diffusionProfileSettingsList = new DiffusionProfileSettings[0]; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs index d3697c36efa..780c2acff0b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -27,6 +27,8 @@ public sealed class ShaderResources public Shader debugColorPickerPS; [Reload("Runtime/Debug/DebugExposure.Shader")] public Shader debugExposurePS; + [Reload("Runtime/Debug/DebugHDR.Shader")] + public Shader debugHDRPS; [Reload("Runtime/Debug/DebugLightVolumes.Shader")] public Shader debugLightVolumePS; [Reload("Runtime/Debug/DebugLightVolumes.compute")] @@ -257,6 +259,8 @@ public sealed class ShaderResources public ComputeShader applyExposureCS; [Reload("Runtime/PostProcessing/Shaders/DebugHistogramImage.compute")] public ComputeShader debugImageHistogramCS; + [Reload("Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute")] + public ComputeShader debugHDRxyMappingCS; [Reload("Runtime/PostProcessing/Shaders/UberPost.compute")] public ComputeShader uberPostCS; [Reload("Runtime/PostProcessing/Shaders/LutBuilder3D.compute")] @@ -319,6 +323,8 @@ public sealed class ShaderResources public ComputeShader lensFlareMergeOcclusionCS; [Reload("Runtime/PostProcessing/Shaders/DLSSBiasColorMask.shader")] public Shader DLSSBiasColorMaskPS; + [Reload("Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader")] + public Shader compositeUIAndOETFApplyPS; // Physically based DoF [Reload("Runtime/PostProcessing/Shaders/DoFCircleOfConfusion.compute")] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index fc48b23ea79..47cca90533d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -783,6 +783,9 @@ static class HDShaderIDs public static readonly int _HistogramExposureParams = Shader.PropertyToID("_HistogramExposureParams"); public static readonly int _HistogramBuffer = Shader.PropertyToID("_HistogramBuffer"); public static readonly int _FullImageHistogram = Shader.PropertyToID("_FullImageHistogram"); + public static readonly int _xyBuffer = Shader.PropertyToID("_xyBuffer"); + public static readonly int _HDRxyBufferDebugParams = Shader.PropertyToID("_HDRxyBufferDebugParams"); + public static readonly int _HDRDebugParams = Shader.PropertyToID("_HDRDebugParams"); public static readonly int _AdaptationParams = Shader.PropertyToID("_AdaptationParams"); public static readonly int _ExposureCurveTexture = Shader.PropertyToID("_ExposureCurveTexture"); public static readonly int _ExposureWeightMask = Shader.PropertyToID("_ExposureWeightMask"); @@ -940,6 +943,10 @@ static class HDShaderIDs public static readonly int _DitherParams = Shader.PropertyToID("_DitherParams"); public static readonly int _KeepAlpha = Shader.PropertyToID("_KeepAlpha"); public static readonly int _UVTransform = Shader.PropertyToID("_UVTransform"); + public static readonly int _UITexture = Shader.PropertyToID("_UITexture"); + public static readonly int _HDROutputParams = Shader.PropertyToID("_HDROutputParams"); + public static readonly int _HDROutputParams2 = Shader.PropertyToID("_HDROutputParams2"); + public static readonly int _NeedsFlip = Shader.PropertyToID("_NeedsFlip"); public static readonly int _MotionVecAndDepth = Shader.PropertyToID("_MotionVecAndDepth"); public static readonly int _TileMinMaxMotionVec = Shader.PropertyToID("_TileMinMaxMotionVec"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset index 8ecefd75dc0..0107104b82a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -23,10 +23,9 @@ MonoBehaviour: debugColorPickerPS: {fileID: 4800000, guid: 8137b807709e178498f22ed710864bb0, type: 3} debugExposurePS: {fileID: 4800000, guid: 0ef322534f047a34c96d29419d56d17a, type: 3} - debugLightVolumePS: {fileID: 4800000, guid: 8e706c0e71fcec34a8f5c9713e5e2943, - type: 3} - debugLightVolumeCS: {fileID: 7200000, guid: f5d5d21faef5cf445ac2c5d8ff9c4184, - type: 3} + debugHDRPS: {fileID: 4800000, guid: 9bc5229549892084da43ad706d84f1bc, type: 3} + debugLightVolumePS: {fileID: 4800000, guid: 8e706c0e71fcec34a8f5c9713e5e2943, type: 3} + debugLightVolumeCS: {fileID: 7200000, guid: f5d5d21faef5cf445ac2c5d8ff9c4184, type: 3} debugBlitQuad: {fileID: 4800000, guid: cf5ca5b6ef18b3f429ed707ee9ceac9f, type: 3} debugViewVirtualTexturingBlit: {fileID: 4800000, guid: 55d195396b03b804eb78c92d468e3c8e, type: 3} @@ -176,8 +175,8 @@ MonoBehaviour: histogramExposureCS: {fileID: 7200000, guid: 222da48299136f34b8e3fb75ae9f8ac7, type: 3} applyExposureCS: {fileID: 7200000, guid: 1a6fea1dc099b984d8f2b27d504dc096, type: 3} - debugImageHistogramCS: {fileID: 7200000, guid: 52cc17ef5a5ffc443a5c142f9b745a85, - type: 3} + debugImageHistogramCS: {fileID: 7200000, guid: 52cc17ef5a5ffc443a5c142f9b745a85, type: 3} + debugHDRxyMappingCS: {fileID: 7200000, guid: f055d2983d992b64494f1a03fc725cde, type: 3} uberPostCS: {fileID: 7200000, guid: f1bf52f7c71bffd4f91e6cd90d12a4f7, type: 3} lutBuilder3DCS: {fileID: 7200000, guid: 37f2b1b0ecd6f1c439e4c1b4f2fdb524, type: 3} depthOfFieldKernelCS: {fileID: 7200000, guid: 7869415cc3e4eaa4d82ac21a752a2780, @@ -224,6 +223,7 @@ MonoBehaviour: lensFlareDataDrivenPS: {fileID: 4800000, guid: 85330b3de0cfebc4ba78b2d61b1a2899, type: 3} lensFlareMergeOcclusionCS: {fileID: 7200000, guid: 07492750f384d9a4da9aaf5d2feeed4a, type: 3} DLSSBiasColorMaskPS: {fileID: 4800000, guid: 017a05924c0b0484ca29717ed0c60343, type: 3} + compositeUIAndOETFApplyPS: {fileID: 4800000, guid: 08b7ad21d2b8e9142b730b22d7355821, type: 3} dofCircleOfConfusion: {fileID: 7200000, guid: 75332b7b315c80d4babe506820aa0bfd, type: 3} dofGatherCS: {fileID: 7200000, guid: 1e6b16a7970a1494db74b1d3d007d1cc, type: 3} dofCoCMinMaxCS: {fileID: 7200000, guid: c70dd492c3d2fe94589d6ca8d4e37915, type: 3}