From 49a0b756dcf848b5a68f6b5215ae1fb28a5ccb65 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 6 Sep 2021 17:26:02 +0200 Subject: [PATCH 01/65] First pass of porting (some UI work - not all) and porting the hlsl header with functions --- .../ShaderLibrary/ACES.hlsl | 12 +- .../ShaderLibrary/Color.hlsl | 5 + .../RenderPipeline/HDRenderPipelineUI.Skin.cs | 1 + .../RenderPipeline/HDRenderPipelineUI.cs | 1 + .../SerializedRenderPipelineSettings.cs | 5 +- .../HDRenderPipelineEditorResources.asset | 8 +- .../Runtime/Material/UI.meta | 8 + .../Runtime/Material/UI/DefaultUI.shader | 150 ++++++++ .../Runtime/Material/UI/DefaultUI.shader.meta | 10 + .../PostProcessing/Shaders/FinalPass.shader | 6 + .../PostProcessing/Shaders/HDROutput.hlsl | 326 ++++++++++++++++++ .../Shaders/HDROutput.hlsl.meta | 7 + .../Shaders/LutBuilder3D.compute | 9 +- .../Runtime/RenderPipeline/HDProfileId.cs | 1 + .../HDRenderPipeline.PostProcess.cs | 4 + .../RenderPipeline/HDRenderPipeline.cs | 54 ++- .../RenderPipeline/HDRenderPipelineAsset.cs | 5 + .../HDRenderPipelineEditorResources.cs | 2 + .../Settings/RenderPipelineSettings.cs | 5 + .../Material/DefaultHDUIMaterial.mat | 41 +++ .../Material/DefaultHDUIMaterial.mat.meta | 8 + 21 files changed, 650 insertions(+), 18 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Material/UI.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat create mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index 8e602342207..8fd5f3589b2 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -600,10 +600,16 @@ half3 RRT(half3 aces) rgbPost.y = segmented_spline_c5_fwd(rgbPre.y); rgbPost.z = segmented_spline_c5_fwd(rgbPre.z); +#ifndef HDR_OUTPUT // --- RGB rendering space to OCES --- // - half3 rgbOces = mul(AP1_2_AP0_MAT, rgbPost); - - return rgbOces; + half3 outputVal = mul(AP1_2_AP0_MAT, rgbPost); +#else + // We output to Rec2020 here for practicality with the rest of the HDR pipeline. We do it here instead of later from ACEScg (AP0) + // since AP1 is a wider gamut than AP0 and it includes Rec2020 while AP0 doesn't. + const half3x3 AP1_2_REC2020_MAT = mul(XYZ_2_REC2020_MAT, AP1_2_XYZ_MAT); + half3 outputVal = mul(AP1_2_REC2020_MAT, rgbPost); +#endif + return outputVal; } // diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index 9c28334eb82..f2a79db8e90 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -654,8 +654,13 @@ float3 AcesTonemap(float3 aces) #if TONEMAPPING_USE_FULL_ACES float3 oces = RRT(aces); +#ifndef HDR_OUTPUT float3 odt = ODT_RGBmonitor_100nits_dim(oces); return odt; +#else + // We operate in 2020 and we don't need to apply the ODT here since it is applied at final pass stage. + return oces; +#endif #else diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs index 25a54bca747..80c66fd89e5 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs @@ -153,6 +153,7 @@ public class Styles public static readonly GUIContent rayTracingMSAAUnsupported = EditorGUIUtility.TrTextContent("When Ray tracing is enabled in asset, MSAA is not supported. Please refer to the documentation."); public static readonly GUIContent maximumLODLevel = EditorGUIUtility.TrTextContent("Maximum LOD Level"); public static readonly GUIContent LODBias = EditorGUIUtility.TrTextContent("LOD Bias"); + public static readonly GUIContent UILayer = EditorGUIUtility.TrTextContent("UI Layer", "TODO_FCC ADD BETTER TOOLTIP. Layer used by UI elements. UI need to use this layer to be handled properly with HDR Output."); public static readonly GUIContent supportRuntimeDebugDisplayContentLabel = EditorGUIUtility.TrTextContent("Runtime Debug Shaders", "When disabled, all debug display shader variants are removed when you build for the Unity Player. This decreases build time, but prevents the use of Rendering Debugger in Player builds."); public static readonly GUIContent supportProbeVolumeContent = EditorGUIUtility.TrTextContent("Enable", "When enabled, HDRP allocates Shader variants and memory for probe volume based GI. This allows you to use probe volumes in your Unity Project."); public static readonly GUIContent probeVolumeMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "Determines the width and height of the textures used to store GI data from probes. Note that the textures also have a fixed depth dimension."); diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index de9c36ef549..e10bf5805a8 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -861,6 +861,7 @@ static void Drawer_SectionRenderingUnsorted(SerializedHDRenderPipelineAsset seri --EditorGUI.indentLevel; } + EditorGUILayout.PropertyField(serialized.renderPipelineSettings.uiLayer, Styles.UILayer); EditorGUILayout.PropertyField(serialized.renderPipelineSettings.supportRayTracing, Styles.supportRaytracing); using (new EditorGUI.DisabledScope(!serialized.renderPipelineSettings.supportRayTracing.boolValue)) { 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 41308d7d4e7..cd3aeb19006 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; @@ -54,7 +53,7 @@ class SerializedRenderPipelineSettings internal SerializedProperty supportProbeVolume; internal SerializedProperty probeVolumeTextureSize; internal SerializedProperty probeVolumeSHBands; - + public SerializedProperty uiLayer; public SerializedGlobalLightLoopSettings lightLoopSettings; public SerializedHDShadowInitParameters hdShadowInitParams; @@ -111,7 +110,7 @@ public SerializedRenderPipelineSettings(SerializedProperty root) supportProbeVolume = root.Find((RenderPipelineSettings s) => s.supportProbeVolume); probeVolumeTextureSize = root.Find((RenderPipelineSettings s) => s.probeVolumeMemoryBudget); probeVolumeSHBands = root.Find((RenderPipelineSettings s) => s.probeVolumeSHBands); - + uiLayer = root.Find((RenderPipelineSettings s) => s.uiLayer); 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..41b2ec6587c 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset @@ -20,23 +20,19 @@ 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} defaultDecalMat: {fileID: 2100000, guid: 500e733574922d04ea961553b1b26a63, type: 2} defaultParticleMat: {fileID: 2100000, guid: b739a3f02ff77bf48b7636e64c3e3b4c, type: 2} defaultTerrainMat: {fileID: 2100000, guid: 22ff8771d87ef27429e670136399094b, type: 2} + defaultUIMat: {fileID: 2100000, guid: 0b4a88fad3f0a6440a0434e38f80ebab, type: 2} GUITextureBlit2SRGB: {fileID: 2100000, guid: 6e95c04e4e686554e8bed96ee69f690c, type: 2} shaderGraphs: 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/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/Material/UI/DefaultUI.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader new file mode 100644 index 00000000000..5ad0867a96f --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader @@ -0,0 +1,150 @@ +Shader "HDRP/DefaultUI" +{ + HLSLINCLUDE + CBUFFER_START(cb) + int _UISrcColorBlend; + int _UIDstColorBlend; + int _UISrcAlphaBlend; + int _UIDstAlphaBlend; + CBUFFER_END + ENDHLSL + + Properties + { + [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} + _Color("Tint", Color) = (1,1,1,1) + + _StencilComp("Stencil Comparison", Float) = 8 + _Stencil("Stencil ID", Float) = 0 + _StencilOp("Stencil Operation", Float) = 0 + _StencilWriteMask("Stencil Write Mask", Float) = 255 + _StencilReadMask("Stencil Read Mask", Float) = 255 + _SrcBlend("_SrcBlend", Float) = 1.0 + _DstBlend("_DstBlend", Float) = 0.0 + _AlphaSrcBlend("_AlphaSrcBlend", Float) = 1.0 + _AlphaDstBlend("_AlphaDstBlend", Float) = 0.0 + + _ColorMask("Color Mask", Float) = 15 + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + Stencil + { + Ref[_Stencil] + Comp[_StencilComp] + Pass[_StencilOp] + ReadMask[_StencilReadMask] + WriteMask[_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest[unity_GUIZTestMode] + //Blend One OneMinusSrcAlpha + // TODO_FCC: Comment back in when ready to test UI and HDR. + Blend [_SrcBlend] [_DstBlend], [_AlphaSrcBlend] [_AlphaDstBlend] + + ColorMask[_ColorMask] + + Pass + { + Name "Default" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + + #pragma multi_compile_local _ UNITY_UI_CLIP_RECT + #pragma multi_compile_local _ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + half4 mask : TEXCOORD2; + UNITY_VERTEX_OUTPUT_STEREO + }; + + sampler2D _MainTex; + fixed4 _Color; + fixed4 _TextureSampleAdd; + float4 _ClipRect; + float4 _MainTex_ST; + float _UIMaskSoftnessX; + float _UIMaskSoftnessY; + + v2f vert(appdata_t v) + { + v2f OUT; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + float4 vPosition = UnityObjectToClipPos(v.vertex); + OUT.worldPosition = v.vertex; + OUT.vertex = vPosition; + + float2 pixelSize = vPosition.w; + pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); + + float4 clampedRect = clamp(_ClipRect, -2e10, 2e10); + float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy); + OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex); + OUT.mask = half4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy))); + + OUT.color = v.color * _Color; + return OUT; + } + + fixed4 frag(v2f IN) : SV_Target + { + //Round up the alpha color coming from the interpolator (to 1.0/256.0 steps) + //The incoming alpha could have numerical instability, which makes it very sensible to + //HDR color transparency blend, when it blends with the world's texture. + const half alphaPrecision = half(0xff); + const half invAlphaPrecision = half(1.0 / alphaPrecision); + IN.color.a = round(IN.color.a * alphaPrecision)*invAlphaPrecision; + + half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd); + + #ifdef UNITY_UI_CLIP_RECT + half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw); + color.a *= m.x * m.y; + #endif + + #ifdef UNITY_UI_ALPHACLIP + clip(color.a - 0.001); + #endif + + color.rgb *= color.a; + + return color; + } + ENDCG + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta new file mode 100644 index 00000000000..2290a24ed31 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e5e91acae3155814cadad67bde39f914 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + 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..460116124aa 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,11 @@ 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 + + // TODO_FCC: If HDR_OUTPUT, we entered this pass with an input color that is *not* range mapped and is in Rec2020 color space. + // So need to call HDRMapping(color, maxNit, minNit). + // If we need to composite UI, we need to do it in linear. #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 @@ -109,6 +114,7 @@ Shader "Hidden/HDRP/FinalPass" #endif //FXAA // Saturate is only needed for dither or grain to work. Otherwise we don't saturate because output might be HDR + // TODO_FCC: How to handle this in HDR Output? #if defined(GRAIN) || defined(DITHER) outColor = saturate(outColor); #endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl new file mode 100644 index 00000000000..e575f4c75da --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -0,0 +1,326 @@ +// Important! This file assumes Color.hlsl has been already included. + +// TEMP_REMOVE_NOTES_FCC: +// - I think at the moment our grading output is in sRGB so we'll need here to rotate back to BT 2020 effectively losing lots of colors, what if we do the opposite? What if we output the grading to BT 2020 and then rotate for the sRGB? For perf? +// TODO_FCC: Decide what to do with the UI (where to put it at least) + + +// Attack plan: +// - Do all the grading and tone mapping in Rec2020 (well, at least do final rotation to Rec2020). Or maybe AP1 since we already have it from the tonemapper? +// - We reach the Final pass where we do the display mapping, in here: +// * If HDR: If we need to output to P3, rotate to Rec2020 to P3 (P3 is a subset), then in any case perform range reduction based min/max brightness given by user or manufacturer (or using decent defaults: 10 to 1000 nits?) with BT2390 EETF (as in CoD) . +// this requires moving to ICtCp color space and apply the curve on the I value of the ICtCp value. Then rotate back to Rec2020 + PQ. Probably the whole thing can be LUTed. [https://www.shadertoy.com/view/ldKcz3] +// - * If SDR: Do range reduction here (using this https://www.desmos.com/calculator/esjyfpsjvn from frostbite presentation), however keep in mind that we need to account for hue shift. Check slide 93 of frostbite presentation. + +// TODO_Perf: When full pipeline is done, try to LUT the most we can. + + +// TODOs: +// - We should tonemap in a rotated color space (i.e. BT2020) to get more out of it. We then rotate to Rec709 on SDR and not viceversa +// - Expose the paper white nit to user, a sensible range is 50 - 300. + +// 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 BT2020 and . +// 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). This is what is applied in camera and therefore what we need to use. +// 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 HDR 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. + +// Note: Ideally the pipeline should work in WCG, but this require more fundamental changes both to the rendering pipeline and the content authoring. As such we assume we start from Rec709 color gamut. +// However at some point we'd need to consider the eventuality of WCG aware content and add the option that assumes that the input color space is Rec2020. + +// -------------------------------- +// COLOR PRIMARIES ROTATION +// -------------------------------- +// 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 = + { + 0.627402, 0.329292, 0.043306, + 0.069095, 0.919544, 0.011360, + 0.016394, 0.088028, 0.895578 + }; + + return mul(Rec709ToRec2020Mat, Rec709Input); +} + +float3 RotateRec709ToP3(float3 Rec709Input) +{ + static const float3x3 Rec709ToP3Mat = + { + 0.822458, 0.177542, 0.000000, + 0.033193, 0.966807, 0.000000, + 0.017085, 0.072410, 0.910505 + }; + + return mul(Rec709ToP3Mat, Rec709Input); +} + +float3 RotateRec2020ToRec709(float3 Rec2020Input) +{ + static const float3x3 Rec2020ToRec709Mat = + { + 1.660496, -0.587656, -0.072840, + -0.124547, 1.132895, -0.008348, + -0.018154, -0.100597, 1.118751 + }; + return mul(Rec2020ToRec709Mat, Rec2020Input); +} + +// TODO_IMPORTANT: Verify this. +float3 RotateRec2020ToP3(float3 Rec2020Input) +{ + static const float3x3 Rec2020ToXYZMat = + { + 1.660496, -0.587656, -0.072840, + -0.124547, 1.132895, -0.008348, + -0.018154, -0.100597, 1.118751 + }; + + static const float3x3 XYZToP3D65Mat = + { + 2.4933963, -0.9313459, -0.4026945, + -0.8294868, 1.7626597, 0.0236246, + 0.0358507, -0.0761827, 0.9570140 + }; + + static const float3x3 Rec2020toP3Mat = mul(XYZToP3D65Mat, Rec2020ToXYZMat); + + return mul(Rec2020toP3Mat, Rec2020Input); +} + +// Ref: ICtCp Dolby white paper (https://www.dolby.com/us/en/technologies/dolby-vision/ictcp-white-paper.pdf) +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 RotateLMSToRec2020(float3 LMSInput) +{ + static const float3x3 LMSToRec2020Mat = + { + 3.43660669433308, -2.50645211865627, 0.0698454243232, + -0.79132955559892, 1.98360045179229, -0.1922708961934, + -0.02594989969059, -0.09891371471173, 1.1248636144023 + }; + + return mul(LMSToRec2020Mat, LMSInput); +} +float3 RotateRec709ToWCG(float3 Rec709Input) +{ +#ifdef WCG_REC2020 + return RotateRec709ToRec2020(Rec709Input); +#elif defined(WCG_P3) + return RotateRec709ToP3(Rec709Input); +#endif + // We should really reach this point. + return Rec709Input; +} + + +// -------------------------------- +// OETF +// -------------------------------- +// We need to apply the inverse of the display EOTF which we, for now, we always assume to be PQ. +// Various methods follow. + +// This is the accurate inverse of the PQ curve, it involves two pows therefore is leaning to the expensive end. +float3 AccuratePQInv(float3 inputCol) +{ + return LinearToPQ(inputCol); +} + +float AccuratePQInv(float x) +{ + return LinearToPQ(x); +} + + +// 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. +float3 PatryInvPQ(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/0n402k2syc ) in the full [0... 10 000] range, but still faster than reference +float3 GTSInvPQ(float3 inputCol) +{ + float3 k = pow((inputCol * 0.01), 0.1593017578125); + return (3.61972*(1e-8) + k * (0.00102859 + k * (-0.101284 + 2.05784 * k))) / + (0.0495245 + k * (0.135214 + k * (0.772669 + k))); +} + +// TODO: Fourth option would be implementing the curve as a LUT + +#define PRECISE_INV_PQ 0 +#define ISS_APPROX_INV_PQ 1 +#define GTS_APPROX_INV_PQ 2 +#define INV_PQ_CHOICE GTS_APPROX_INV_PQ + +float3 ApplyOETF(float3 inputCol) +{ +#if INV_PQ_CHOICE == PRECISE_INV_PQ + return AccuratePQInv(inputCol); +#elif INV_PQ_CHOICE == ISS_APPROX_INV_PQ + return PatryInvPQ(inputCol); +#elif INV_PQ_CHOICE == GTS_APPROX_INV_PQ + return GTSInvPQ(inputCol); +#endif +} + +// -------------------------------- +// Range reduction +// -------------------------------- +// Ref: [Malin 2018] HDR Display in Call of Duty +// Ref: [Fry 2017] High Dynamic Range Color Grading and Display in Frostbite +// We start from a signal that is assumed having 10k nits to the actual Target Display. +// In case of SDR this mean taking as input a linear signal and output a value in the [0...1] range using a piecewise function +// that starts linear and ends up with a exp curve as shoulder to compress highlights ( https://www.desmos.com/calculator/esjyfpsjvn ). +// In case of HDR we use BT2390 EETF as suggested in Ref: [Malin2018] HDR Display in Call of Duty + +// Ref: ICtCp Dolby white paper (https://www.dolby.com/us/en/technologies/dolby-vision/ictcp-white-paper.pdf) +float3 PQLMSToICtCp(float3 LMSInput) +{ + float3x3 PQLMSToICtCpMat = float3x3( + 0.5, 0.5, 0.0, + 1.613769, -3.323486, 1.709716, + 4.378174, -4.245605, -0.1325683 + ); + + return mul(PQLMSToICtCpMat, LMSInput); +} + +float3 ICtCpToPQLMS(float3 ICtCpInput) +{ + float3x3 ICtCpToPQLMSMat = float3x3( + 1.0, 0.008609, 0.111029, + 1.0, -0.008609, -0.111029, + 1.0, 0.560031, -0.320627 + ); + + return mul(ICtCpToPQLMSMat, ICtCpInput); +} + +float SDRRangeReduction(float val) +{ + float expShoulder = 1.0f - exp(-val); + // TODO_FCC: We should allow this to be set. + float linearSectionEnd = 0.33f; + + return val > linearSectionEnd ? expShoulder : val; +} + +float3 SDRRangeReduction(float3 val) +{ + return float3(SDRRangeReduction(val.x), SDRRangeReduction(val.y), SDRRangeReduction(val.z)); +} + + +float BT2390EETFHermite(float x, float kneeStart, float maxLum) +{ + float T = (x - kneeStart) / (1.0f - kneeStart); + float T2 = T * T; + float T3 = T2 * T; + + return (2 * T3 - 3 * T2 + 1) * kneeStart + (T3 - 2 * T2 + T) * (1 - kneeStart) + (-2 * T3 + 3 * T2) * maxLum; +} + +// TODO: Can we squash this all thing into a LUT? Probably so. +// Ref: BT2390 standard doc https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-3-2017-PDF-E.pdf +float3 HDRRangeReduction(float3 Rec2020Input, float minNit, float maxNit) +{ + // 1) Rec 2020 to LMS -> LMS to PQ -> PQ to ICtCp + float3 LMSVal = RotateRec2020ToLMS(Rec2020Input); + // For now accurate, TODO: Check if we can use the approx version. + float3 PQLMS = AccuratePQInv(LMSVal); + float3 ICtCp = PQLMSToICtCp(PQLMS); + + // 2) Apply EETF [ https://www.desmos.com/calculator/vgc7s0juzp ] + // TODO_FCC: Compute this two values on CPU + float minLumPQ = AccuratePQInv(minNit); + float maxLumPQ = AccuratePQInv(maxNit); + + float kneeStart = 1.5f * maxLumPQ - 0.5f; + float e2 = ICtCp.x < kneeStart ? ICtCp.x : BT2390EETFHermite(ICtCp.x, kneeStart, maxLumPQ); + + float intensityReduced = e2 + minLumPQ * PositivePow((1.0f - e2), 4); + // As mentioned by BT2390, we need to adjust saturation + float saturationScale = min(intensityReduced / ICtCp.x, ICtCp.x / intensityReduced); + + float3 newICtCp = float3(intensityReduced, ICtCp.xy * saturationScale); + + // 3) ICtCp to PQ -> PQ to LMS -> LMS to Rec 2020 + PQLMS = ICtCpToPQLMS(newICtCp); + LMSVal = PQToLinear(PQLMS); // TODO_FCC: Approx? + return RotateLMSToRec2020(LMSVal); +} + +// -------------------------------- +// Display mapping 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 the Rec 2020 color space. However we still provide options in case we get a Rec709 input, this will just rotate to Rec2020 and +// procede with the expected pipeline. + +float3 SDRMapping_NoRotation(float3 input, float huePreservingFraction) +{ + // As in [Fry 2017], we mix hue-preservation reduction and hue shifted reduction. + float maxChannel = Max3(input.x, input.y, input.z); + float reducedMax = SDRRangeReduction(maxChannel); + float3 reducedColHuePreserving = input * (reducedMax / maxChannel); + + // This is not hue preserving. + float3 rangePerChannelReduced = SDRRangeReduction(input); + + // NOTE: No OETF here since Unity handles it separately later on. + return lerp(rangePerChannelReduced, reducedColHuePreserving, huePreservingFraction); +} + +float3 SDRMapping(float3 Rec2020Input, float huePreservingFraction) +{ + // Move to the correct color space + float3 Rec709Val = RotateRec2020ToRec709(SDRMapping_NoRotation(Rec2020Input, huePreservingFraction)); + return Rec709Val; +} + +float3 HDRMapping(float3 Rec2020Input, float minNits, float maxNits) +{ + // First up we do range reduction + float3 reducedHDR = HDRRangeReduction(Rec2020Input, minNits, maxNits); + +#ifdef WCG_P3 + // The whole pipeline operates in Rec2020, if we need P3, we'll need to rotate now before going through the OETF + reducedHDR = RotateRec2020ToP3(reducedHDR); +#endif + + return ApplyOETF(reducedHDR); +} + +// Warning! This is never a good idea vs. the above, ideally the pipeline should always be working in the wider gamut +float3 HDRMappingFromRec709(float3 Rec709Input, float minNits, float maxNits) +{ + float3 rec2020Input = RotateRec709ToRec2020(Rec709Input); + return HDRMapping(rec2020Input, minNits, maxNits); +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl.meta new file mode 100644 index 00000000000..6ade4d23097 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/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/Runtime/PostProcessing/Shaders/LutBuilder3D.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute index 97389bd534b..1c163f53823 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,13 @@ -#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 _ HDR #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" + TEXTURE3D(_LogLut3D); RW_TEXTURE3D(float4, _OutputTexture); 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 c21d63a87f7..688462e38b6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -62,6 +62,7 @@ internal enum HDProfileId HDRenderPipelineRenderAOV, HDRenderPipelineAllRenderRequest, CullResultsCull, + UICullResults, CustomPassCullResultsCull, DisplayCookieAtlas, RenderWireFrame, 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 253c09549bc..c11fbaf16d8 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 @@ -3940,6 +3940,10 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) case TonemappingMode.Custom: passData.builderCS.EnableKeyword("TONEMAPPING_CUSTOM"); break; case TonemappingMode.External: passData.builderCS.EnableKeyword("TONEMAPPING_EXTERNAL"); break; } + if (HDROutputSettings.main.active) + { + passData.builderCS.EnableKeyword("HDR_OUTPUT"); + } } else { 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 740e2b8704c..c46f855902d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,6 +199,24 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } + internal void UpdateUIMaterialBlendMode() + { + if (HDROutputSettings.main.active) + { + m_Asset.defaultUIMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + m_Asset.defaultUIMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + m_Asset.defaultUIMaterial.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + m_Asset.defaultUIMaterial.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + } + else + { + m_Asset.defaultUIMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); + m_Asset.defaultUIMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + m_Asset.defaultUIMaterial.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One); + m_Asset.defaultUIMaterial.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + } + } + readonly SkyManager m_SkyManager = new SkyManager(); internal SkyManager skyManager { get { return m_SkyManager; } } @@ -535,6 +553,8 @@ void SetRenderingFeatures() autoDefaultReflectionProbeBaking = false , enlightenLightmapper = false + , + rendersUIOverlay = true }; Lightmapping.SetDelegate(GlobalIlluminationUtils.hdLightsDelegate); @@ -1011,6 +1031,7 @@ public struct Target struct HDCullingResults { public CullingResults cullingResults; + public CullingResults uiCullingResults; public CullingResults? customPassCullingResults; public HDProbeCullingResults hdProbeCullingResults; public DecalSystem.CullResult decalCullResults; @@ -1250,7 +1271,12 @@ protected override void Render(ScriptableRenderContext renderContext, Camera[] c } if (needCulling) - skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, ref cullingResults); + { + var uiLayerMask = HDROutputSettings.main.active ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; + // TODO_FCC For test, enable to see if it renders to separate without having HDR + // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; + skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, uiLayerMask, ref cullingResults); + } } if (additionalCameraData.hasCustomRender && additionalCameraData.fullscreenPassthrough) @@ -1537,6 +1563,10 @@ ref List renderDatas var _cullingResults = UnsafeGenericPool.Get(); _cullingResults.Reset(); + var uiLayerMask = HDROutputSettings.main.active ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; + // TODO_FCC For test, enable to see if it renders to separate without having HDR + // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; + if (!(TryCalculateFrameParameters( camera, XRSystem.emptyPass, @@ -1545,7 +1575,7 @@ ref List renderDatas out var cullingParameters ) && TryCull( - camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, + camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, uiLayerMask, ref _cullingResults ) )) @@ -1772,6 +1802,8 @@ ref _cullingResults RTHandles.SetReferenceSize(maxSize.x, maxSize.y); } + // If we are in HDR output mode we need to update the default UI blend mode accordingly + UpdateUIMaterialBlendMode(); // Execute render request graph, in reverse order for (int i = renderRequestIndicesToRender.Count - 1; i >= 0; --i) @@ -1927,6 +1959,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; @@ -2291,6 +2324,7 @@ static bool TryCull( SkyManager skyManager, ScriptableCullingParameters cullingParams, HDRenderPipelineAsset hdrp, + LayerMask uiLayerMask, ref HDCullingResults cullingResults ) { @@ -2346,6 +2380,13 @@ ref HDCullingResults cullingResults skyManager.UpdateCurrentSkySettings(hdCamera); skyManager.SetupAmbientProbe(hdCamera); + // TODO_FCC: Comment the following if condition to test. + uint castedLayerMask = (uint)(int)uiLayerMask; + if (HDROutputSettings.main.active) + { + cullingParams.cullingMask &= ~castedLayerMask; + } + if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing)) { OverrideCullingForRayTracing(hdCamera, camera, ref cullingParams); @@ -2364,6 +2405,15 @@ ref HDCullingResults cullingResults } } + + if (HDROutputSettings.main.active) + { + cullingParams.cullingMask = castedLayerMask; + using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.UICullResults))) + cullingResults.uiCullingResults = renderContext.Cull(ref cullingParams); + } + + if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.PlanarProbe) && hdProbeCullState.cullingGroup != null) HDProbeSystem.QueryCullResults(hdProbeCullState, ref cullingResults.hdProbeCullingResults); else 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..37c155b17eb 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,11 @@ public override Material defaultParticleMaterial public override Material defaultTerrainMaterial => globalSettings?.renderPipelineEditorResources?.materials.defaultTerrainMat; + /// HDRP default UI material. + // TODO_FCC: Enable when ready. + public override Material defaultUIMaterial + => globalSettings?.renderPipelineEditorResources?.materials.defaultUIMat; + // Array structure that allow us to manipulate the set of defines that the HD render pipeline needs List defineArray = new List(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs index d1cfd02d543..af7ef7d2b3a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs @@ -40,6 +40,8 @@ public sealed class MaterialResources public Material defaultParticleMat; [Reload("Runtime/RenderPipelineResources/Material/DefaultHDTerrainMaterial.mat")] public Material defaultTerrainMat; + [Reload("Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat")] + public Material defaultUIMat; [Reload("Editor/RenderPipelineResources/Material/GUITextureBlit2SRGB.mat")] public Material GUITextureBlit2SRGB; } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs index 85973fb3b1b..aa8af83c451 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs @@ -123,6 +123,8 @@ internal static RenderPipelineSettings NewDefault() supportProbeVolume = false, probeVolumeMemoryBudget = ProbeVolumeTextureMemoryBudget.MemoryBudgetMedium, probeVolumeSHBands = ProbeVolumeSHBands.SphericalHarmonicsL1, + + uiLayer = 1 << 5, // 5 by default is UI }; return settings; } @@ -371,6 +373,9 @@ public bool supportRuntimeDebugDisplay /// Global lighting quality settings. public GlobalLightingQualitySettings lightingQualitySettings; + //// TODO_FCC: Change to Global settings? + public LayerMask uiLayer; + #pragma warning disable 618 // Type or member is obsolete [Obsolete("For data migration")] internal bool m_ObsoleteincreaseSssSampleCount; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat new file mode 100644 index 00000000000..3e34564201b --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat @@ -0,0 +1,41 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: DefaultHDUIMaterial + m_Shader: {fileID: 4800000, guid: e5e91acae3155814cadad67bde39f914, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AlphaDstBlend: 10 + - _AlphaSrcBlend: 5 + - _ColorMask: 15 + - _DstBlend: 10 + - _SrcBlend: 5 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _UseUIAlphaClip: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta new file mode 100644 index 00000000000..0d7be6b04ab --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b4a88fad3f0a6440a0434e38f80ebab +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: From ac7619f5f63af5a9cddae9eddd24b37e71e1f43d Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 7 Sep 2021 10:56:27 +0200 Subject: [PATCH 02/65] Before experiments. --- .../HDRenderPipeline.RenderGraph.cs | 73 ++++++++++++++++++- .../Material/DefaultHDUIMaterial.mat | 4 +- 2 files changed, 74 insertions(+), 3 deletions(-) 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 356140a4e18..bb2babc3eae 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 @@ -33,6 +33,7 @@ void RecordRenderGraph(RenderRequest renderRequest, var camera = hdCamera.camera; var cullingResults = renderRequest.cullingResults.cullingResults; var customPassCullingResults = renderRequest.cullingResults.customPassCullingResults ?? cullingResults; + var uiCullingResult = renderRequest.cullingResults.uiCullingResults; bool msaa = hdCamera.msaaEnabled; var target = renderRequest.target; @@ -193,7 +194,7 @@ 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, uiCullingResult, aovRequest, aovCustomPassBuffers); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) { @@ -326,6 +327,8 @@ void RecordRenderGraph(RenderRequest renderRequest, RenderWireOverlay(m_RenderGraph, hdCamera, backBuffer); RenderGizmos(m_RenderGraph, hdCamera, GizmoSubset.PostImageEffects); + + RenderScreenSpaceOverlayUI(m_RenderGraph, hdCamera, backBuffer); } } @@ -806,6 +809,45 @@ void RenderForwardError(RenderGraph renderGraph, } } + class RenderOffscreenUIData + { + public Camera camera; + public RendererListHandle rendererList; + public FrameSettings frameSettings; + } + + TextureHandle CreateOffscreenUIBuffer(RenderGraph renderGraph, MSAASamples msaaSamples) + { + return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) + { colorFormat = GraphicsFormat.R8G8B8A8_UNorm, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); + } + + TextureHandle RenderTransparentUI(RenderGraph renderGraph, + HDCamera hdCamera, + CullingResults cullResults) + { + var output = renderGraph.defaultResources.blackTextureXR; + if (HDROutputSettings.main.active && SupportedRenderingFeatures.active.rendersUIOverlay) + { + using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.RenderForwardError))) + { + builder.AllowPassCulling(false); + + output = builder.UseColorBuffer(CreateOffscreenUIBuffer(renderGraph, hdCamera.msaaSamples), 0); + passData.camera = hdCamera.camera; + passData.rendererList = renderGraph.CreateRendererList(CreateTransparentRendererListDesc(cullResults, hdCamera.camera, m_AllTransparentPassNames, m_CurrentRendererConfigurationBakedLighting, HDRenderQueue.k_RenderQueue_AllTransparent)); + passData.frameSettings = hdCamera.frameSettings; + + builder.SetRenderFunc((RenderOffscreenUIData data, RenderGraphContext context) => + { + RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); + }); + } + } + + return output; + } + void RenderForwardTransparent(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, @@ -1107,6 +1149,7 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, ShadowResult shadowResult, CullingResults cullingResults, CullingResults customPassCullingResults, + CullingResults uiCullingResult, AOVRequestData aovRequest, List aovCustomPassBuffers) { @@ -1147,6 +1190,9 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, normalBuffer, prepassOutput, vtFeedbackBuffer, volumetricLighting, ssrLightingBuffer, currentColorPyramid, lightLists, shadowResult, cullingResults, false); ResetCameraMipBias(hdCamera); + // TODO_FCC: TMP, MOVE FROM HERE. + RenderTransparentUI(renderGraph, hdCamera, uiCullingResult); + colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer); // Render All forward error @@ -1901,6 +1947,31 @@ void RenderWireOverlay(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle #endif } + class RenderScreenSpaceOverlayData + { + public Camera camera; + } + + void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) + { + if (!HDROutputSettings.main.active && 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/RenderPipelineResources/Material/DefaultHDUIMaterial.mat b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat index 3e34564201b..a23089f0296 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat @@ -26,10 +26,10 @@ Material: m_Ints: [] m_Floats: - _AlphaDstBlend: 10 - - _AlphaSrcBlend: 5 + - _AlphaSrcBlend: 1 - _ColorMask: 15 - _DstBlend: 10 - - _SrcBlend: 5 + - _SrcBlend: 1 - _Stencil: 0 - _StencilComp: 8 - _StencilOp: 0 From f356e7eff216dedf39ede8981582c5351636eede Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 7 Sep 2021 15:18:28 +0200 Subject: [PATCH 03/65] Broken, but need to switch branch. --- .../PostProcessing/Shaders/FinalPass.shader | 7 +++++ .../Runtime/RenderPipeline/HDProfileId.cs | 1 + .../HDRenderPipeline.PostProcess.cs | 18 +++++++++-- .../HDRenderPipeline.RenderGraph.cs | 31 +++++++++++++------ .../RenderPipeline/HDRenderPipeline.cs | 22 ++++++++++--- .../RenderPipeline/HDStringConstants.cs | 1 + .../Material/DefaultHDUIMaterial.mat | 4 +-- 7 files changed, 65 insertions(+), 19 deletions(-) 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 460116124aa..9792abd9486 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 @@ -33,6 +33,8 @@ Shader "Hidden/HDRP/FinalPass" TEXTURE2D_ARRAY(_BlueNoiseTexture); TEXTURE2D_X(_AlphaTexture); + TEXTURE2D_X(_UITexture); + SAMPLER(sampler_LinearClamp); SAMPLER(sampler_LinearRepeat); @@ -158,6 +160,11 @@ Shader "Hidden/HDRP/FinalPass" outColor.xyz = afterPostColor.a * outColor.xyz + afterPostColor.xyz; #endif +#if 1 + float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); + outColor = uiValue.rgb + outColor * (1.0f - uiValue.a); +#endif + #if !defined(ENABLE_ALPHA) return float4(outColor, outAlpha); #else 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 688462e38b6..b7595b68176 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -177,6 +177,7 @@ internal enum HDProfileId // Misc VolumeUpdate, CustomPassVolumeUpdate, + OffscreenUIRendering, // XR XRMirrorView, 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 c11fbaf16d8..e9d61436561 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 @@ -433,6 +433,7 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, in PrepassOutput prepassOutput, TextureHandle inputColor, TextureHandle backBuffer, + TextureHandle uiBuffer, CullingResults cullResults, HDCamera hdCamera) { @@ -537,7 +538,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; @@ -3940,7 +3941,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) case TonemappingMode.Custom: passData.builderCS.EnableKeyword("TONEMAPPING_CUSTOM"); break; case TonemappingMode.External: passData.builderCS.EnableKeyword("TONEMAPPING_EXTERNAL"); break; } - if (HDROutputSettings.main.active) + if (TEST_HDR()) { passData.builderCS.EnableKeyword("HDR_OUTPUT"); } @@ -4772,10 +4773,11 @@ class FinalPassData 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))) { @@ -4898,6 +4900,16 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); + //if (TEST_HDR()) + //{ + // finalPassMaterial.EnableKeyword("HDR_OUTPUT"); + //} + //else + //{ + // finalPassMaterial.DisableKeyword("HDR_OUTPUT"); + //} + finalPassMaterial.SetTexture(HDShaderIDs._UITexture, uiBuffer); + finalPassMaterial.SetVector(HDShaderIDs._UVTransform, data.flipY ? new Vector4(1.0f, -1.0f, 0.0f, 1.0f) 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 bb2babc3eae..8203b43022b 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 @@ -95,6 +95,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 = TextureHandle.nullHandle; if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() && m_CurrentDebugDisplaySettings.IsFullScreenDebugPassEnabled()) { @@ -194,7 +195,8 @@ 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, uiCullingResult, aovRequest, aovCustomPassBuffers); + colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedNormalBuffer, vtFeedbackBuffer, currentColorPyramid, volumetricLighting, rayCountTexture, m_SkyManager.GetSkyReflection(hdCamera), gpuLightListOutput, ref prepassOutput, + shadowResult, cullingResults, customPassCullingResults, uiCullingResult, aovRequest, aovCustomPassBuffers, out uiBuffer); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) { @@ -267,7 +269,7 @@ void RecordRenderGraph(RenderRequest renderRequest, aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers); } - TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, cullingResults, hdCamera); + TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, uiBuffer, cullingResults, hdCamera); GenerateDebugImageHistogram(m_RenderGraph, hdCamera, postProcessDest); PushFullScreenExposureDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); @@ -822,25 +824,35 @@ TextureHandle CreateOffscreenUIBuffer(RenderGraph renderGraph, MSAASamples msaaS { colorFormat = GraphicsFormat.R8G8B8A8_UNorm, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); } + + // TODO_FCC: IMPORTANT! HANDLE OPAQUE UI, WRITE ON SAME BUFFER BUT BEFORE HAND? WE ARE ASSUME ALL UNLIT? TextureHandle RenderTransparentUI(RenderGraph renderGraph, HDCamera hdCamera, + TextureHandle depthBuffer, CullingResults cullResults) { var output = renderGraph.defaultResources.blackTextureXR; - if (HDROutputSettings.main.active && SupportedRenderingFeatures.active.rendersUIOverlay) + if (TEST_HDR() && SupportedRenderingFeatures.active.rendersUIOverlay) { - using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.RenderForwardError))) + using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { builder.AllowPassCulling(false); output = builder.UseColorBuffer(CreateOffscreenUIBuffer(renderGraph, hdCamera.msaaSamples), 0); + builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite); + passData.camera = hdCamera.camera; passData.rendererList = renderGraph.CreateRendererList(CreateTransparentRendererListDesc(cullResults, hdCamera.camera, m_AllTransparentPassNames, m_CurrentRendererConfigurationBakedLighting, HDRenderQueue.k_RenderQueue_AllTransparent)); + passData.rendererList = builder.UseRendererList(passData.rendererList); passData.frameSettings = hdCamera.frameSettings; builder.SetRenderFunc((RenderOffscreenUIData data, RenderGraphContext context) => { - RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); + // For V1 we only render screen space overlays offscreen. MAKE IT AN OPTION LATER? + // RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); + context.renderContext.ExecuteCommandBuffer(context.cmd); + context.cmd.Clear(); + context.renderContext.DrawUIOverlay(data.camera); }); } } @@ -1151,7 +1163,8 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, CullingResults customPassCullingResults, CullingResults uiCullingResult, AOVRequestData aovRequest, - List aovCustomPassBuffers) + List aovCustomPassBuffers, + out TextureHandle uiBuffer) { // Transparent (non recursive) objects that are rendered in front of transparent (recursive) require the recursive rendering to be executed for that pixel. // This means our flagging process needs to happen before the transparent depth prepass as we use the depth to discriminate pixels that do not need recursive rendering. @@ -1190,8 +1203,8 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, normalBuffer, prepassOutput, vtFeedbackBuffer, volumetricLighting, ssrLightingBuffer, currentColorPyramid, lightLists, shadowResult, cullingResults, false); ResetCameraMipBias(hdCamera); - // TODO_FCC: TMP, MOVE FROM HERE. - RenderTransparentUI(renderGraph, hdCamera, uiCullingResult); + // TODO_FCC: TMP, MOVE FROM HERE. ALSO CONSIDER THAT FOR V1 WE MIGHT WANT TO ONLY SEPARATE OVERLAYS? + uiBuffer = RenderTransparentUI(renderGraph, hdCamera, prepassOutput.depthBuffer, uiCullingResult); colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer); @@ -1954,7 +1967,7 @@ class RenderScreenSpaceOverlayData void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) { - if (!HDROutputSettings.main.active && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) + if (!TEST_HDR() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) { using (var builder = renderGraph.AddRenderPass("Screen Space Overlay UI", out var passData)) { 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 c46f855902d..fb01535a0e0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,9 +199,21 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } + // TODO_FCC: THIS IS NEEDED FOR TESTING, REPLACE WITH HDROutputSettings.main.active LATER + static bool TEST_HDR() + { + // + return true;// HDROutputSettings.main.active; + } + + static bool TEST_SEPARATEUICULLING() + { + return TEST_HDR() && false; + } + internal void UpdateUIMaterialBlendMode() { - if (HDROutputSettings.main.active) + if (TEST_HDR()) { m_Asset.defaultUIMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); m_Asset.defaultUIMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); @@ -1272,7 +1284,7 @@ protected override void Render(ScriptableRenderContext renderContext, Camera[] c if (needCulling) { - var uiLayerMask = HDROutputSettings.main.active ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; + var uiLayerMask = TEST_SEPARATEUICULLING() ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; // TODO_FCC For test, enable to see if it renders to separate without having HDR // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, uiLayerMask, ref cullingResults); @@ -1563,7 +1575,7 @@ ref List renderDatas var _cullingResults = UnsafeGenericPool.Get(); _cullingResults.Reset(); - var uiLayerMask = HDROutputSettings.main.active ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; + var uiLayerMask = TEST_SEPARATEUICULLING() ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; // TODO_FCC For test, enable to see if it renders to separate without having HDR // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; @@ -2382,7 +2394,7 @@ ref HDCullingResults cullingResults // TODO_FCC: Comment the following if condition to test. uint castedLayerMask = (uint)(int)uiLayerMask; - if (HDROutputSettings.main.active) + if (TEST_HDR()) { cullingParams.cullingMask &= ~castedLayerMask; } @@ -2406,7 +2418,7 @@ ref HDCullingResults cullingResults } - if (HDROutputSettings.main.active) + if (TEST_HDR()) { cullingParams.cullingMask = castedLayerMask; using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.UICullResults))) 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 e06e5d423c9..193913a8437 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -935,6 +935,7 @@ 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 _MotionVecAndDepth = Shader.PropertyToID("_MotionVecAndDepth"); public static readonly int _TileMinMaxMotionVec = Shader.PropertyToID("_TileMinMaxMotionVec"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat index a23089f0296..3e34564201b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat @@ -26,10 +26,10 @@ Material: m_Ints: [] m_Floats: - _AlphaDstBlend: 10 - - _AlphaSrcBlend: 1 + - _AlphaSrcBlend: 5 - _ColorMask: 15 - _DstBlend: 10 - - _SrcBlend: 1 + - _SrcBlend: 5 - _Stencil: 0 - _StencilComp: 8 - _StencilOp: 0 From d261d06a249712268c61b49753a993230f1f8216 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 16 Sep 2021 09:32:56 +0200 Subject: [PATCH 04/65] wut --- .../RenderPipeline/HDRenderPipeline.RenderGraph.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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 8203b43022b..f67be1021e5 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 @@ -95,7 +95,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 = TextureHandle.nullHandle; + TextureHandle uiBuffer = m_RenderGraph.defaultResources.blackTextureXR; if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() && m_CurrentDebugDisplaySettings.IsFullScreenDebugPassEnabled()) { @@ -196,7 +196,10 @@ void RecordRenderGraph(RenderRequest renderRequest, 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, uiCullingResult, aovRequest, aovCustomPassBuffers, out uiBuffer); + shadowResult, cullingResults, customPassCullingResults, uiCullingResult, aovRequest, aovCustomPassBuffers); + + // TODO_FCC: TMP, MOVE FROM HERE. ALSO CONSIDER THAT FOR V1 WE MIGHT WANT TO ONLY SEPARATE OVERLAYS? + uiBuffer = RenderTransparentUI(m_RenderGraph, hdCamera, prepassOutput.depthBuffer, uiCullingResult); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) { @@ -1163,8 +1166,7 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, CullingResults customPassCullingResults, CullingResults uiCullingResult, AOVRequestData aovRequest, - List aovCustomPassBuffers, - out TextureHandle uiBuffer) + List aovCustomPassBuffers) { // Transparent (non recursive) objects that are rendered in front of transparent (recursive) require the recursive rendering to be executed for that pixel. // This means our flagging process needs to happen before the transparent depth prepass as we use the depth to discriminate pixels that do not need recursive rendering. @@ -1203,9 +1205,6 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, normalBuffer, prepassOutput, vtFeedbackBuffer, volumetricLighting, ssrLightingBuffer, currentColorPyramid, lightLists, shadowResult, cullingResults, false); ResetCameraMipBias(hdCamera); - // TODO_FCC: TMP, MOVE FROM HERE. ALSO CONSIDER THAT FOR V1 WE MIGHT WANT TO ONLY SEPARATE OVERLAYS? - uiBuffer = RenderTransparentUI(renderGraph, hdCamera, prepassOutput.depthBuffer, uiCullingResult); - colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer); // Render All forward error From 513f1f08a986851ad474b24685adc62a4fb87c27 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 16 Sep 2021 12:17:05 +0200 Subject: [PATCH 05/65] Fix UX --- .../PostProcessing/Shaders/FinalPass.shader | 2 +- .../HDRenderPipeline.PostProcess.cs | 19 ++++++++++--------- .../HDRenderPipeline.RenderGraph.cs | 7 +++---- 3 files changed, 14 insertions(+), 14 deletions(-) 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 9792abd9486..77b36dc78f0 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 @@ -160,7 +160,7 @@ Shader "Hidden/HDRP/FinalPass" outColor.xyz = afterPostColor.a * outColor.xyz + afterPostColor.xyz; #endif -#if 1 +#if HDR_OUTPUT float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); outColor = uiValue.rgb + outColor * (1.0f - uiValue.a); #endif 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 e9d61436561..ca42c6d088c 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 @@ -4812,6 +4812,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); passData.alphaTexture = builder.ReadTexture(alphaTexture); passData.destination = builder.WriteTexture(finalRT); + passData.uiBuffer = builder.ReadTexture(uiBuffer); builder.SetRenderFunc( (FinalPassData data, RenderGraphContext ctx) => @@ -4900,15 +4901,15 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); - //if (TEST_HDR()) - //{ - // finalPassMaterial.EnableKeyword("HDR_OUTPUT"); - //} - //else - //{ - // finalPassMaterial.DisableKeyword("HDR_OUTPUT"); - //} - finalPassMaterial.SetTexture(HDShaderIDs._UITexture, uiBuffer); + if (TEST_HDR()) + { + finalPassMaterial.EnableKeyword("HDR_OUTPUT"); + } + else + { + finalPassMaterial.DisableKeyword("HDR_OUTPUT"); + } + finalPassMaterial.SetTexture(HDShaderIDs._UITexture, data.uiBuffer); finalPassMaterial.SetVector(HDShaderIDs._UVTransform, data.flipY 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 f67be1021e5..d4c67f79e52 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 @@ -839,8 +839,6 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, { using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { - builder.AllowPassCulling(false); - output = builder.UseColorBuffer(CreateOffscreenUIBuffer(renderGraph, hdCamera.msaaSamples), 0); builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite); @@ -851,8 +849,9 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, builder.SetRenderFunc((RenderOffscreenUIData data, RenderGraphContext context) => { - // For V1 we only render screen space overlays offscreen. MAKE IT AN OPTION LATER? - // RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); + // Do we want only overlays? If not do we want to disable TAA for this? How do we do? + // How do we handle exposure etc? For now disabled. But it works as a concept. + //RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); context.renderContext.ExecuteCommandBuffer(context.cmd); context.cmd.Clear(); context.renderContext.DrawUIOverlay(data.camera); From 23ee264d0d465401eb6fe3d185b644086ec4fc9b Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 17 Sep 2021 21:21:20 +0200 Subject: [PATCH 06/65] Fix error in BT2390 --- .../Runtime/PostProcessing/Shaders/HDROutput.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index e575f4c75da..ac1f07653a1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -267,7 +267,7 @@ float3 HDRRangeReduction(float3 Rec2020Input, float minNit, float maxNit) // As mentioned by BT2390, we need to adjust saturation float saturationScale = min(intensityReduced / ICtCp.x, ICtCp.x / intensityReduced); - float3 newICtCp = float3(intensityReduced, ICtCp.xy * saturationScale); + float3 newICtCp = float3(intensityReduced, ICtCp.yz * saturationScale); // 3) ICtCp to PQ -> PQ to LMS -> LMS to Rec 2020 PQLMS = ICtCpToPQLMS(newICtCp); From 62cbf4b1cb93157b404fff9c520f9a08dc8116b2 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 20 Sep 2021 17:15:33 +0200 Subject: [PATCH 07/65] Fix UI shader in player. --- .../Runtime/Material/UI/DefaultUI.shader | 7 ++----- .../RenderPipeline/HDRenderPipeline.cs | 21 +++++++++++-------- .../RenderPipeline/HDRenderPipelineAsset.cs | 2 +- .../HDRenderPipelineEditorResources.cs | 2 -- .../HDRenderPipelineRuntimeResources.cs | 2 ++ .../Material/DefaultHDUIMaterial.mat | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader index 5ad0867a96f..0dc627444e9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader @@ -53,10 +53,7 @@ Shader "HDRP/DefaultUI" Lighting Off ZWrite Off ZTest[unity_GUIZTestMode] - //Blend One OneMinusSrcAlpha - // TODO_FCC: Comment back in when ready to test UI and HDR. - Blend [_SrcBlend] [_DstBlend], [_AlphaSrcBlend] [_AlphaDstBlend] - + Blend [_UISrcColorBlend] [_UIDstColorBlend], [_UISrcAlphaBlend] [_UIDstAlphaBlend] ColorMask[_ColorMask] Pass @@ -69,7 +66,7 @@ Shader "HDRP/DefaultUI" #include "UnityCG.cginc" #include "UnityUI.cginc" - + #pragma enable_d3d11_debug_symbols #pragma multi_compile_local _ UNITY_UI_CLIP_RECT #pragma multi_compile_local _ UNITY_UI_ALPHACLIP 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 64336696b60..c8d5eb3d009 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -210,21 +210,22 @@ static bool TEST_SEPARATEUICULLING() return TEST_HDR() && false; } - internal void UpdateUIMaterialBlendMode() + internal void UpdateUIMaterialBlendMode(CommandBuffer cmd) { + // TODO: THIS DOESN'T WORK!defaultUIMaterial is editor only... We should find another way, likely a global variables via shader variables. if (TEST_HDR()) { - m_Asset.defaultUIMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); - m_Asset.defaultUIMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - m_Asset.defaultUIMaterial.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); - m_Asset.defaultUIMaterial.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + cmd.SetGlobalInt("_UISrcColorBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + cmd.SetGlobalInt("_UIDstColorBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + cmd.SetGlobalInt("_UISrcAlphaBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + cmd.SetGlobalInt("_UIDstAlphaBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); } else { - m_Asset.defaultUIMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); - m_Asset.defaultUIMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - m_Asset.defaultUIMaterial.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One); - m_Asset.defaultUIMaterial.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + cmd.SetGlobalInt("_UISrcColorBlend", (int)UnityEngine.Rendering.BlendMode.One); + cmd.SetGlobalInt("_UIDstColorBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + cmd.SetGlobalInt("_UISrcAlphaBlend", (int)UnityEngine.Rendering.BlendMode.One); + cmd.SetGlobalInt("_UIDstAlphaBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); } } @@ -1823,6 +1824,8 @@ ref _cullingResults var renderRequest = renderRequests[renderRequestIndex]; var cmd = CommandBufferPool.Get(""); + // If we are in HDR output mode we need to update the default UI blend mode accordingly + UpdateUIMaterialBlendMode(cmd); // TODO: Avoid the intermediate target and render directly into final target // CommandBuffer.Blit does not work on Cubemap faces 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 37c155b17eb..9f9a95324e8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -194,7 +194,7 @@ public override Material defaultTerrainMaterial /// HDRP default UI material. // TODO_FCC: Enable when ready. public override Material defaultUIMaterial - => globalSettings?.renderPipelineEditorResources?.materials.defaultUIMat; + => globalSettings?.renderPipelineResources?.materials.defaultUIMat; // Array structure that allow us to manipulate the set of defines that the HD render pipeline needs List defineArray = new List(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs index af7ef7d2b3a..d1cfd02d543 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineEditorResources.cs @@ -40,8 +40,6 @@ public sealed class MaterialResources public Material defaultParticleMat; [Reload("Runtime/RenderPipelineResources/Material/DefaultHDTerrainMaterial.mat")] public Material defaultTerrainMat; - [Reload("Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat")] - public Material defaultUIMat; [Reload("Editor/RenderPipelineResources/Material/GUITextureBlit2SRGB.mat")] public Material GUITextureBlit2SRGB; } 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 dfc76f6b674..ee5d2e0b8f1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -375,6 +375,8 @@ public IEnumerable GetAllComputeShaders() [Serializable, ReloadGroup] public sealed class MaterialResources { + [Reload("Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat")] + public Material defaultUIMat; } [Serializable, ReloadGroup] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat index 3e34564201b..a23089f0296 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat @@ -26,10 +26,10 @@ Material: m_Ints: [] m_Floats: - _AlphaDstBlend: 10 - - _AlphaSrcBlend: 5 + - _AlphaSrcBlend: 1 - _ColorMask: 15 - _DstBlend: 10 - - _SrcBlend: 5 + - _SrcBlend: 1 - _Stencil: 0 - _StencilComp: 8 - _StencilOp: 0 From a1b771c3171e1d82ec2fc8e12c37560b547a6ea6 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 22 Sep 2021 18:29:50 +0200 Subject: [PATCH 08/65] Sync point --- .../ShaderLibrary/Color.hlsl | 43 --- .../PostProcessing/Shaders/FinalPass.shader | 30 +- .../PostProcessing/Shaders/HDROutput.hlsl | 26 +- .../PostProcessing/Shaders/HDROutput_3.hlsl | 302 ++++++++++++++++++ .../Shaders/HDROutput_3.hlsl.meta | 7 + .../Shaders/LutBuilder3D.compute | 28 +- .../PostProcessing/Shaders/UberPost.compute | 2 +- .../RenderPipeline/HDRenderPipeline.cs | 31 +- .../RenderPipeline/HDRenderPipelineAsset.cs | 9 +- .../Runtime/RenderPipeline/Utility/HDUtils.cs | 3 +- .../HDRenderPipelineRuntimeResources.asset | 3 + 11 files changed, 426 insertions(+), 58 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index f2a79db8e90..25d72dffa67 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -334,49 +334,6 @@ float3 SoftLight(float3 base, float3 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 = -{ - 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 -}; - -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); -} - -real3 LinearToPQ(real3 x) -{ - return LinearToPQ(x, DEFAULT_MAX_PQ); -} - -real3 PQToLinear(real3 x, real maxPQValue) -{ - 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; -} - -real3 PQToLinear(real3 x) -{ - return PQToLinear(x, DEFAULT_MAX_PQ); -} - // Alexa LogC converters (El 1000) // See http://www.vocas.nl/webfm_send/964 // Max range is ~58.85666 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 77b36dc78f0..1b631cb3569 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 @@ -26,6 +26,17 @@ 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" +#ifdef HDR_OUTPUT + #define WCG_REC2020 // For now hard coded, eventually coming from settings. + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" + //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROUTPUT_FRESH.hlsl" + + //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" + // #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_2.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl" + //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_Outside.hlsl" +#endif + #pragma enable_d3d11_debug_symbols TEXTURE2D_X(_InputTexture); TEXTURE2D(_GrainTexture); @@ -161,8 +172,23 @@ Shader "Hidden/HDRP/FinalPass" #endif #if HDR_OUTPUT - float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); - outColor = uiValue.rgb + outColor * (1.0f - uiValue.a); + + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits + // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. + float hdrBoostFactor = 300; // TODO: Should come from user or from paperwhite nits. + //outColor.rgb = HDRMappingFromRec709(outColor.xyz*hdrBoostFactor, 0.005f, 10.0f); + //outColor.rgb = HDRMappingFromRec709(outColor.xyz, 0.005f, 10.0f); + outColor.rgb = HDRMappingFromRec709(outColor.rgb, hdrBoostFactor, 0.0f, 400.0f); + //rec2020 *= hdrBoostFactor; + //float3 tonemapped = Tonemap_HDR(rec2020); + //outColor.rgb = EOTF_(tonemapped); + + + //// This looks really bad now, so it is likely wrong code, will come back when making stuff more ordinate. + //float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); + //const float paperWhiteNits = 100.0f; // TODO: Have from UI + //uiValue.rgb = NormalizeUIForHDRComposition(uiValue.rgb, paperWhiteNits); + //outColor.rgb = uiValue.rgb + outColor.rgb * (1.0f - uiValue.a); #endif #if !defined(ENABLE_ALPHA) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index ac1f07653a1..36cf4394cce 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -175,8 +175,9 @@ float3 GTSInvPQ(float3 inputCol) #define PRECISE_INV_PQ 0 #define ISS_APPROX_INV_PQ 1 #define GTS_APPROX_INV_PQ 2 -#define INV_PQ_CHOICE GTS_APPROX_INV_PQ +#define INV_PQ_CHOICE PRECISE_INV_PQ +// START FROM HERE: ACCURATE ONE NEEDS SCALING BY MAX BRIGHTNESS. float3 ApplyOETF(float3 inputCol) { #if INV_PQ_CHOICE == PRECISE_INV_PQ @@ -324,3 +325,26 @@ float3 HDRMappingFromRec709(float3 Rec709Input, float minNits, float maxNits) float3 rec2020Input = RotateRec709ToRec2020(Rec709Input); return HDRMapping(rec2020Input, minNits, maxNits); } + +// -------------------------------- +// UI Composition functions +// -------------------------------- +// Traditionally UI is not authored to be TODO_FCC FILL + +// A bit verbose and optimizable. +float3 NormalizeUIForHDRComposition(float3 uiValue, float paperWhiteNits) +{ + + const float maxNits2084 = 10000.0f; // The standard set 10k nits as max. + const float hdrScalar = paperWhiteNits / maxNits2084; + float3 linearRec709 = uiValue;// pow(uiValue, 2.2); + float3 linearUIRec2020 = RotateRec709ToRec2020(linearRec709); + return AccuratePQInv(linearUIRec2020.rgb * hdrScalar * paperWhiteNits); + + + //// TODO: Do we need to move to linear? Is it linear? Is it gamma? Need to check on UIOverlay side. + //// Assuming linear? + //float3 normalizedUI = (linearUIRec2020 * (paperWhiteNits / maxNits2084)); + //// Now move to PQ + //return AccuratePQInv(normalizedUI); +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl new file mode 100644 index 00000000000..2744a0f9ad4 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl @@ -0,0 +1,302 @@ +// Important! This file assumes Color.hlsl has been already included. + +// 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 HDR 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. + + +// -------------------------------- +// Perceptual Quantizer (PQ) / ST 2084 +// -------------------------------- +// This section has a bunch of options, a few of them are accurate a bunch are not. +#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) + +float3 LinearToPQ(float3 value, float maxPQValue) +{ + value /= maxPQValue; + float3 Ym1 = PositivePow(value, PQ_N); + float3 n = (PQ_C1 + PQ_C2 * Ym1); + float3 d = (1.0f + PQ_C3 * Ym1); + return PositivePow(n / d, PQ_M); +} + +float3 LinearToPQ(float3 value) +{ + return LinearToPQ(value, MAX_PQ_VALUE); +} + +float3 PQToLinear(float3 value) +{ + const float3 Em2 = PositivePow(value, 1 / PQ_M); + const float3 X = (max(0.0, Em2 - PQ_C1)) / (PQ_C2 - PQ_C3 * Em2); + return pow(X, 1 / PQ_N); +} + +float3 PQToLinear(float3 value, float maxPQValue) +{ + return PQToLinear(value) * maxPQValue; +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// 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 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); +} + +// 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 RotateRec2020ToICtCp(float3 Rec2020) +{ + float3 lms = RotateRec2020ToLMS(Rec2020); + float3 PQLMS = LinearToPQ(max(0.0f, lms)); + return RotatePQLMSToICtCp(PQLMS); +} + +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 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 RotateICtCpToRec2020(float3 ICtCp) +{ + float3 PQLMS = RotateICtCpToPQLMS(ICtCp); + float3 LMS = PQToLinear(PQLMS, 10000.0); + float3 XYZ = RotateLMSToXYZ(LMS); + return RotateXYZToRec2020(XYZ); +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// EOTF +// -------------------------------- +// Note that 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/m6qi4llkcc +#define PRECISE_PQ 0 +#define ISS_APPROX_PQ 1 +#define GTS_APPROX_PQ 2 + +#define EOTF_CHOICE PRECISE_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 PatryApprox(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/0n402k2syc ) 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 GTSApprox(float3 inputCol) +{ + float3 k = pow((inputCol * 0.01), 0.1593017578125); + 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 EOTF(float3 inputCol) +{ +#if EOTF_CHOICE == PRECISE_PQ + return LinearToPQ(inputCol); +#elif EOTF_CHOICE == ISS_APPROX_PQ + return PatryApprox(inputCol * 0.01f); +#elif EOTF_CHOICE == GTS_APPROX_PQ + return GTSApprox(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 + +#define REINHARD 0 +#define BT2390 1 +#define RANGE_REDUCTION BT2390 + +// 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 see https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf + +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 Rec2020Input, float minNits, float maxNits) +{ + float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); +#if RANGE_REDUCTION == REINHARD + linearLuma = ReinhardTonemap(linearLuma, maxNits); +#elif RANGE_REDUCTION == BT2390 + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); +#endif + ICtCp.x = LinearToPQ(linearLuma); + + return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! + +} + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// 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 the Rec 2020 color space. However we still provide options in case we get a Rec709 input, this will just rotate to Rec2020 and +// procede with the expected pipeline. + +float3 HDRMappingFromRec2020(float3 Rec2020Input, float hdrBoost, float minNits, float maxNits) +{ + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits + // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. + float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); + return EOTF(reducedHDR); +} + +float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits) +{ + float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits + // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. + float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); + return EOTF(reducedHDR); +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta new file mode 100644 index 00000000000..323ad80d13c --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1927822c5d86a7e4e8aa5ae396a569d0 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: 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 1c163f53823..b8d5321d66d 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,16 @@ #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 _ HDR +#pragma multi_compile _ HDR_OUTPUT #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" +#ifdef HDR_OUTPUT +#define WCG_REC2020 // For now hard coded, eventually coming from settings. +//#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" +#endif TEXTURE3D(_LogLut3D); RW_TEXTURE3D(float4, _OutputTexture); @@ -227,6 +231,23 @@ float3 Tonemap(float3 colorLinear) return colorLinear; } + +float3 ProcessColorForHDR(float3 gradedColor) +{ +//#ifdef HDR_OUTPUT +// +// // TODO_FCC: Rotate to Rec2020 and all that jazz, but consider working directly in Rec2020 space instead of back and forth from LogC +// // Default assuming 1000 nits but come from options. +// float3 rec2020Input = RotateRec709ToRec2020(gradedColor); +// +// return HDRMappingFromRec709(gradedColor, 10, 400); +// return rec2020Input;// ApplyOETF(gradedColor); +//#else + return gradedColor; +//#endif +} + + // 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. @@ -254,7 +275,10 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) gradedColor = NeutralColorGrade(gradedColor); } - gradedColor = Tonemap(gradedColor); + // TODO_FCC: Better handling of tonemapping. + // gradedColor = Tonemap(gradedColor); + + //gradedColor = ProcessColorForHDR(gradedColor); _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..bc205faba03 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 @@ -222,7 +222,7 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID) float3 colorLutSpace = saturate(LinearToLogC(color.xyz)); // Color lookup in the LogC lut - color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); + //color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); } // Alpha mask 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 c8d5eb3d009..da0d13032a2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -201,8 +201,33 @@ internal int GetMaxScreenSpaceShadows() // TODO_FCC: THIS IS NEEDED FOR TESTING, REPLACE WITH HDROutputSettings.main.active LATER static bool TEST_HDR() { + if (HDROutputSettings.main.available) + { + Debug.Log("Available"); + } + + if (HDROutputSettings.main.available && SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) + { + HDROutputSettings.main.automaticHDRTonemapping = false; + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var gamut = HDROutputSettings.main.displayColorGamut; + var dst = HDROutputSettings.main.graphicsFormat; + + Debug.Log($" min {minNits} max {maxNits} {gamut} {dst}"); + + HDROutputSettings.main.RequestHDRModeChange(true); + } + //if (SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) + //{ + // Debug.Log("System info Available"); + //} + //if (HDROutputSettings.displays.Length > 0) + //{ + // Debug.Log("Display length more than 0"); + //} // - return true;// HDROutputSettings.main.active; + return HDROutputSettings.main.active; } static bool TEST_SEPARATEUICULLING() @@ -524,7 +549,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 @@ -1814,8 +1839,6 @@ ref _cullingResults RTHandles.SetReferenceSize(maxSize.x, maxSize.y); } - // If we are in HDR output mode we need to update the default UI blend mode accordingly - UpdateUIMaterialBlendMode(); // Execute render request graph, in reverse order for (int i = renderRequestIndicesToRender.Count - 1; i >= 0; --i) 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 9f9a95324e8..e541783b7b1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -191,10 +191,6 @@ public override Material defaultParticleMaterial public override Material defaultTerrainMaterial => globalSettings?.renderPipelineEditorResources?.materials.defaultTerrainMat; - /// HDRP default UI material. - // TODO_FCC: Enable when ready. - public override Material defaultUIMaterial - => globalSettings?.renderPipelineResources?.materials.defaultUIMat; // Array structure that allow us to manipulate the set of defines that the HD render pipeline needs List defineArray = new List(); @@ -223,6 +219,11 @@ bool UpdateDefineList(bool flagValue, string defineMacroValue) #endif + /// HDRP default UI material. + // TODO_FCC: Enable when ready. + public override Material defaultUIMaterial + => globalSettings?.renderPipelineResources?.materials.defaultUIMat; + /// /// Indicates if virtual texturing is currently enabled for this render pipeline instance. /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs index eab4bee53c9..b08d3005305 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs @@ -900,7 +900,8 @@ internal static bool PostProcessIsFinalPass(HDCamera hdCamera) // Post process pass is the final blit only when not in developer mode. // In developer mode, we support a range of debug rendering that needs to occur after post processes. // In order to simplify writing them, we don't Y-flip in the post process pass but add a final blit at the end of the frame. - return !Debug.isDebugBuild && !WillCustomPassBeExecuted(hdCamera, CustomPassInjectionPoint.AfterPostProcess); + // TODO_FCC: IN HDR THIS CANNOT BE TRUE! + return true;// !Debug.isDebugBuild && !WillCustomPassBeExecuted(hdCamera, CustomPassInjectionPoint.AfterPostProcess); } // These two convertion functions are used to store GUID assets inside materials, 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 17097924dd3..8514a0aba84 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -163,6 +163,9 @@ MonoBehaviour: bilateralUpsampleCS: {fileID: 7200000, guid: 68e831c555284d741b985e05369f0e63, type: 3} temporalFilterCS: {fileID: 7200000, guid: 741979ff70f7bd6489fbcb464280ecff, type: 3} diffuseDenoiserCS: {fileID: 7200000, guid: b4ed2382141619f40af1f743a84ccaea, type: 3} + defaultUIShader: {fileID: 4800000, guid: e5e91acae3155814cadad67bde39f914, type: 3} + materials: + defaultUIMat: {fileID: 2100000, guid: 0b4a88fad3f0a6440a0434e38f80ebab, type: 2} textures: debugFontTex: {fileID: 2800000, guid: a3ad2df0e49aaa341a3b3a80f93b3f66, type: 3} colorGradient: {fileID: 2800000, guid: 4ea52e665573c1644bf05dd9b11fd2a4, type: 3} From a6e7d7fdaefbd232549f7fe91b6b06052aa2a0ab Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 23 Sep 2021 12:32:47 +0200 Subject: [PATCH 09/65] Correct UI composition. --- .../PostProcessing/Shaders/FinalPass.shader | 25 ++++++++++--------- .../PostProcessing/Shaders/HDROutput_3.hlsl | 17 ++++++++++++- .../HDRenderPipeline.PostProcess.cs | 7 ++++++ .../RenderPipeline/HDStringConstants.cs | 1 + 4 files changed, 37 insertions(+), 13 deletions(-) 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 1b631cb3569..3311786d400 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 @@ -56,6 +56,15 @@ Shader "Hidden/HDRP/FinalPass" float4 _ViewPortSize; float _KeepAlpha; + // TODO_FCC: HDR RELATED STUFF, WILL NEED TO MOVE TO WHATEVER BUILDS THE LUT. + float4 _HDROutputParams; + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _IsRec2020 (int)(_HDROutputParams.w) == 0 + #define _IsRec709 (int)(_HDROutputParams.w) == 1 + #define _IsP3 (int)(_HDROutputParams.w) == 2 + struct Attributes { uint vertexID : SV_VertexID; @@ -175,20 +184,12 @@ Shader "Hidden/HDRP/FinalPass" // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float hdrBoostFactor = 300; // TODO: Should come from user or from paperwhite nits. - //outColor.rgb = HDRMappingFromRec709(outColor.xyz*hdrBoostFactor, 0.005f, 10.0f); - //outColor.rgb = HDRMappingFromRec709(outColor.xyz, 0.005f, 10.0f); - outColor.rgb = HDRMappingFromRec709(outColor.rgb, hdrBoostFactor, 0.0f, 400.0f); - //rec2020 *= hdrBoostFactor; - //float3 tonemapped = Tonemap_HDR(rec2020); - //outColor.rgb = EOTF_(tonemapped); - + float paperWhiteBoost = 1.5f;// ??????? Something like this should come from calibration, so probably allow to set via script. + outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite * paperWhiteBoost, _MinNits, _MaxNits); //// This looks really bad now, so it is likely wrong code, will come back when making stuff more ordinate. - //float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); - //const float paperWhiteNits = 100.0f; // TODO: Have from UI - //uiValue.rgb = NormalizeUIForHDRComposition(uiValue.rgb, paperWhiteNits); - //outColor.rgb = uiValue.rgb + outColor.rgb * (1.0f - uiValue.a); + float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); + outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * paperWhiteBoost); #endif #if !defined(ENABLE_ALPHA) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl index 2744a0f9ad4..91b620910d9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl @@ -149,7 +149,7 @@ float3 RotateICtCpToPQLMS(float3 ICtCp) float3 RotateICtCpToRec2020(float3 ICtCp) { float3 PQLMS = RotateICtCpToPQLMS(ICtCp); - float3 LMS = PQToLinear(PQLMS, 10000.0); + float3 LMS = PQToLinear(PQLMS, MAX_PQ_VALUE); float3 XYZ = RotateLMSToXYZ(LMS); return RotateXYZToRec2020(XYZ); } @@ -300,3 +300,18 @@ float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, f float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); return EOTF(reducedHDR); } + +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// UI Related functions +// -------------------------------- + +// Assumes UI is linear at this point ? Is it true? +float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) +{ + uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a)); + uiSample.rgb = LinearToPQ(uiSample.rgb, (MAX_PQ_VALUE / paperWhite)); + uiSample.rgb *= uiSample.a; + return uiSample.rgb + pqSceneColor.rgb * (1.0f - uiSample.a); +} 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 ca42c6d088c..9a459c624bb 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 @@ -4904,6 +4904,13 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo if (TEST_HDR()) { finalPassMaterial.EnableKeyword("HDR_OUTPUT"); + int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : + (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + + var a = HDROutputSettings.main.maxFullFrameToneMapLuminance; + + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, new Vector4(HDROutputSettings.main.minToneMapLuminance, HDROutputSettings.main.maxToneMapLuminance, HDROutputSettings.main.paperWhiteNits, colorGamut)); } else { 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 a15fd759704..1499aa6aa76 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -933,6 +933,7 @@ static class HDShaderIDs 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 _MotionVecAndDepth = Shader.PropertyToID("_MotionVecAndDepth"); public static readonly int _TileMinMaxMotionVec = Shader.PropertyToID("_TileMinMaxMotionVec"); From cc6dc5eff853e9d0049ccfae6e6889bee159ea50 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 24 Sep 2021 13:23:06 +0200 Subject: [PATCH 10/65] ACES workflow 1000nits --- .../ShaderLibrary/ACES.hlsl | 182 +++++++++++++----- .../Components/HDROutputOptions.cs | 44 +++++ .../Components/HDROutputOptions.cs.meta | 11 ++ .../PostProcessing/Shaders/FinalPass.shader | 24 ++- .../PostProcessing/Shaders/HDROutput_3.hlsl | 33 +++- .../Shaders/LutBuilder3D.compute | 2 +- .../PostProcessing/Shaders/UberPost.compute | 5 +- .../HDRenderPipeline.PostProcess.cs | 47 ++++- .../RenderPipeline/HDRenderPipeline.cs | 18 +- .../RenderPipeline/HDStringConstants.cs | 2 + 10 files changed, 307 insertions(+), 61 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index 8fd5f3589b2..5ead6a913a8 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -501,16 +501,70 @@ 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 +}; + +static 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 +}; +static 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 +}; + +static 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 +}; + +static 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 +}; +half segmented_spline_c9_fwd(half x, SegmentedSplineParams_c9 params) +{ const int N_KNOTS_LOW = 8; const int N_KNOTS_HIGH = 8; @@ -522,33 +576,33 @@ 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); @@ -600,15 +654,9 @@ half3 RRT(half3 aces) rgbPost.y = segmented_spline_c5_fwd(rgbPre.y); rgbPost.z = segmented_spline_c5_fwd(rgbPre.z); -#ifndef HDR_OUTPUT // --- RGB rendering space to OCES --- // half3 outputVal = mul(AP1_2_AP0_MAT, rgbPost); -#else - // We output to Rec2020 here for practicality with the rest of the HDR pipeline. We do it here instead of later from ACEScg (AP0) - // since AP1 is a wider gamut than AP0 and it includes Rec2020 while AP0 doesn't. - const half3x3 AP1_2_REC2020_MAT = mul(XYZ_2_REC2020_MAT, AP1_2_XYZ_MAT); - half3 outputVal = mul(AP1_2_REC2020_MAT, rgbPost); -#endif + return outputVal; } @@ -718,7 +766,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; @@ -773,9 +821,9 @@ half3 ODT_RGBmonitor_100nits_dim(half3 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); @@ -871,9 +919,9 @@ half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 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); @@ -981,9 +1029,9 @@ half3 ODT_Rec709_100nits_dim(half3 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); @@ -1073,9 +1121,9 @@ half3 ODT_Rec709_D60sim_100nits_dim(half3 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); @@ -1183,9 +1231,9 @@ half3 ODT_Rec2020_100nits_dim(half3 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); @@ -1265,9 +1313,9 @@ half3 ODT_P3DCI_48nits(half3 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); @@ -1326,6 +1374,54 @@ 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) +{ + // 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_Rec2020_1000nits_ToAP1(half3 oces) +{ + // 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; +} #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.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs new file mode 100644 index 00000000000..5bb9b30e765 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs @@ -0,0 +1,44 @@ +using System; + +namespace UnityEngine.Rendering.HighDefinition +{ + public enum RangeReductionMode + { + None = 0, + Reinhard = 1, + BT2390 = 2 + } + + [Serializable] + public sealed class RangeReductionModeParameter : VolumeParameter + { + /// + /// Creates a new instance. + /// + /// The initial value to store in the parameter. + /// The initial override state for the parameter. + public RangeReductionModeParameter(RangeReductionMode value, bool overrideState = false) : base(value, overrideState) { } + } + + + [Serializable, VolumeComponentMenuForRenderPipeline("Post-processing/HDROutputOptions", typeof(HDRenderPipeline))] + [HDRPHelpURLAttribute("HDR-Output-Options")] + public sealed class HDROutputOptions : VolumeComponent, IPostProcessComponent + { + public BoolParameter enable = new BoolParameter(true); + public RangeReductionModeParameter mode = new RangeReductionModeParameter(RangeReductionMode.Reinhard); + public BoolParameter detectPaperWhite = new BoolParameter(true); + public BoolParameter reduceOnlyLuminance = new BoolParameter(true); + public ClampedFloatParameter paperWhite = new ClampedFloatParameter(100.0f, 0.0f, 350.0f); + public BoolParameter detectLimits = new BoolParameter(true); + public ClampedFloatParameter minNits = new ClampedFloatParameter(0.0f, 0.0f, 10.0f); + public ClampedFloatParameter maxNits = new ClampedFloatParameter(1000.0f, 0.0f, 3000.0f); + + + public bool IsActive() + { + return enable.value; + } + + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta new file mode 100644 index 00000000000..adc9ce1cf2c --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27012304124a83d468527d92dea76b78 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 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 3311786d400..814e008109a 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 @@ -19,6 +19,7 @@ Shader "Hidden/HDRP/FinalPass" #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 +#define TEST_HDR_IMAGE 0 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" @@ -35,11 +36,15 @@ Shader "Hidden/HDRP/FinalPass" // #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_2.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl" //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_Outside.hlsl" +#undef GRAIN +#undef DITHER #endif #pragma enable_d3d11_debug_symbols TEXTURE2D_X(_InputTexture); TEXTURE2D(_GrainTexture); + TEXTURE2D(_HDRImageTest); + TEXTURE2D_X(_AfterPostProcessTexture); TEXTURE2D_ARRAY(_BlueNoiseTexture); TEXTURE2D_X(_AlphaTexture); @@ -58,12 +63,14 @@ Shader "Hidden/HDRP/FinalPass" // TODO_FCC: HDR RELATED STUFF, WILL NEED TO MOVE TO WHATEVER BUILDS THE LUT. float4 _HDROutputParams; + float4 _HDROutputParams2; #define _MinNits _HDROutputParams.x #define _MaxNits _HDROutputParams.y #define _PaperWhite _HDROutputParams.z #define _IsRec2020 (int)(_HDROutputParams.w) == 0 #define _IsRec709 (int)(_HDROutputParams.w) == 1 #define _IsP3 (int)(_HDROutputParams.w) == 2 + #define _RangeReductionMode (int)_HDROutputParams2.x struct Attributes { @@ -135,6 +142,10 @@ Shader "Hidden/HDRP/FinalPass" #endif #endif //FXAA +#if TEST_HDR_IMAGE == 1 + outColor.rgb = SAMPLE_TEXTURE2D(_HDRImageTest, s_linear_repeat_sampler, positionNDC).rgb; +#endif + // Saturate is only needed for dither or grain to work. Otherwise we don't saturate because output might be HDR // TODO_FCC: How to handle this in HDR Output? #if defined(GRAIN) || defined(DITHER) @@ -180,16 +191,21 @@ Shader "Hidden/HDRP/FinalPass" outColor.xyz = afterPostColor.a * outColor.xyz + afterPostColor.xyz; #endif -#if HDR_OUTPUT +#if HDR_OUTPUT // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float paperWhiteBoost = 1.5f;// ??????? Something like this should come from calibration, so probably allow to set via script. - outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite * paperWhiteBoost, _MinNits, _MaxNits); - + float paperWhiteBoost = 1;// ??????? Something like this should come from calibration, so probably allow to set via script AND via ux. + // outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite * paperWhiteBoost, _MinNits, _MaxNits, _RangeReductionMode); + outColor.rgb = HDRMappingFromRec709_ACES(outColor.rgb, _PaperWhite * paperWhiteBoost); //// This looks really bad now, so it is likely wrong code, will come back when making stuff more ordinate. float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * paperWhiteBoost); +#else +#if TEST_HDR_IMAGE == 1 + + outColor.rgb = NeutralTonemap(outColor.rgb); +#endif #endif #if !defined(ENABLE_ALPHA) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl index 91b620910d9..da8569edd47 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl @@ -270,9 +270,24 @@ float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits) ICtCp.x = LinearToPQ(linearLuma); return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! +} +float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits, int mode) +{ + float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); + if (mode == 1) + linearLuma = ReinhardTonemap(linearLuma, maxNits); + else if (mode == 2) + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); + + ICtCp.x = LinearToPQ(linearLuma); + + return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! } + // -------------------------------------------------------------------------------------------- // -------------------------------- @@ -292,15 +307,29 @@ float3 HDRMappingFromRec2020(float3 Rec2020Input, float hdrBoost, float minNits, return EOTF(reducedHDR); } -float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits) +float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode = 2) { float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); + float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits, reductionMode); return EOTF(reducedHDR); } + +float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost) +{ + float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); + float3 oces = RRT(aces); + float3 AP1ODT = ODT_Rec2020_1000nits_ToAP1(oces); + + const float3x3 AP1_2_Rec2020 = mul(XYZ_2_REC2020_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); + float3 linearODT = mul(AP1_2_Rec2020, AP1ODT); + + + return EOTF(linearODT); +} + // -------------------------------------------------------------------------------------------- // -------------------------------- 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 b8d5321d66d..2162164d112 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 @@ -276,7 +276,7 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) } // TODO_FCC: Better handling of tonemapping. - // gradedColor = Tonemap(gradedColor); + gradedColor = Tonemap(gradedColor); //gradedColor = ProcessColorForHDR(gradedColor); 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 bc205faba03..d81a71a2b20 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 @@ -14,6 +14,7 @@ #pragma multi_compile _ LENS_DISTORTION #pragma multi_compile _ ENABLE_ALPHA #pragma multi_compile _ GAMMA2_OUTPUT +#pragma multi_compile _ HDR_OUTPUT #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/PostProcessDefines.hlsl" @@ -221,8 +222,10 @@ 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); + 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/HDRenderPipeline.PostProcess.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index 9a459c624bb..43035a10b5d 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 @@ -4423,6 +4423,11 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle passData.uberPostCS.EnableKeyword("GAMMA2_OUTPUT"); } + if (TEST_HDR()) + { + passData.uberPostCS.EnableKeyword("HDR_OUTPUT"); + } + passData.outputColorLog = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode == FullScreenDebugMode.ColorLog; passData.width = postProcessViewportSize.x; passData.height = postProcessViewportSize.y; @@ -4770,6 +4775,11 @@ class FinalPassData public bool ditheringEnabled; + public Vector4 hdroutParameters; + public Vector4 hdroutParameters2; + + public TextureHandle inputTest; + public TextureHandle source; public TextureHandle afterPostProcessTexture; public TextureHandle alphaTexture; @@ -4814,6 +4824,33 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.destination = builder.WriteTexture(finalRT); passData.uiBuffer = builder.ReadTexture(uiBuffer); + if (TEST_HDR()) + { + int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : + (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + + var hdrOutput = hdCamera.volumeStack.GetComponent(); + + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var paperWhite = HDROutputSettings.main.paperWhiteNits; + int eetfMode = (int)hdrOutput.mode.value; + if (!hdrOutput.detectPaperWhite.value) + { + paperWhite = hdrOutput.paperWhite.value; + } + if (!hdrOutput.detectLimits.value) + { + minNits = (int)hdrOutput.minNits.value; + maxNits = (int)hdrOutput.maxNits.value; + } + + passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); + passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); + } + + builder.SetRenderFunc( (FinalPassData data, RenderGraphContext ctx) => { @@ -4823,6 +4860,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.shaderKeywords = null; finalPassMaterial.SetTexture(HDShaderIDs._InputTexture, data.source); + finalPassMaterial.SetTexture(HDShaderIDs._HDRImageTest, defaultResources.textures.testHDR); if (data.dynamicResIsOn) { @@ -4901,16 +4939,13 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); + // TODO: THIS IS ALL BAD, NEED TO MOVE AND MOST IMPORTANTLY AVOID CAPTURE. if (TEST_HDR()) { finalPassMaterial.EnableKeyword("HDR_OUTPUT"); - int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : - HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : - (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; - - var a = HDROutputSettings.main.maxFullFrameToneMapLuminance; + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdroutParameters); + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdroutParameters2); - finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, new Vector4(HDROutputSettings.main.minToneMapLuminance, HDROutputSettings.main.maxToneMapLuminance, HDROutputSettings.main.paperWhiteNits, colorGamut)); } else { 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 da0d13032a2..ff6341a19cd 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -198,12 +198,22 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } + static void SetHDROutputState(HDCamera camera) + { + var hdrOutput = camera.volumeStack.GetComponent(); + if (HDROutputSettings.main.available) + { + HDROutputSettings.main.automaticHDRTonemapping = false; + HDROutputSettings.main.RequestHDRModeChange(hdrOutput.enable.value); + } + } + // TODO_FCC: THIS IS NEEDED FOR TESTING, REPLACE WITH HDROutputSettings.main.active LATER static bool TEST_HDR() { if (HDROutputSettings.main.available) { - Debug.Log("Available"); + //Debug.Log("Available"); } if (HDROutputSettings.main.available && SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) @@ -214,9 +224,7 @@ static bool TEST_HDR() var gamut = HDROutputSettings.main.displayColorGamut; var dst = HDROutputSettings.main.graphicsFormat; - Debug.Log($" min {minNits} max {maxNits} {gamut} {dst}"); - - HDROutputSettings.main.RequestHDRModeChange(true); + // Debug.Log($" min {minNits} max {maxNits} {gamut} {dst}"); } //if (SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) //{ @@ -2004,6 +2012,8 @@ AOVRequestData aovRequest // Updates RTHandle hdCamera.BeginRender(cmd); + SetHDROutputState(hdCamera); + if (m_RayTracingSupported) { // This call need to happen once per camera 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 1499aa6aa76..dff8a9f5d81 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -934,6 +934,8 @@ static class HDShaderIDs 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 _HDRImageTest = Shader.PropertyToID("_HDRImageTest"); public static readonly int _MotionVecAndDepth = Shader.PropertyToID("_MotionVecAndDepth"); public static readonly int _TileMinMaxMotionVec = Shader.PropertyToID("_TileMinMaxMotionVec"); From f1ed59ff193a61b3929a13226ff49e4913a20214 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 24 Sep 2021 18:10:12 +0200 Subject: [PATCH 11/65] LUT workflow --- .../PostProcessing/Shaders/FinalPass.shader | 31 +- .../PostProcessing/Shaders/HDROutput.hlsl | 498 ++++++++++-------- .../PostProcessing/Shaders/HDROutput_3.hlsl | 346 ------------ .../Shaders/HDROutput_3.hlsl.meta | 7 - .../Shaders/LutBuilder3D.compute | 60 ++- .../PostProcessing/Shaders/UberPost.compute | 10 +- .../HDRenderPipeline.PostProcess.cs | 36 +- 7 files changed, 371 insertions(+), 617 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta 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 814e008109a..bc265983415 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 @@ -19,7 +19,6 @@ Shader "Hidden/HDRP/FinalPass" #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 -#define TEST_HDR_IMAGE 0 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" @@ -29,15 +28,9 @@ Shader "Hidden/HDRP/FinalPass" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl" #ifdef HDR_OUTPUT #define WCG_REC2020 // For now hard coded, eventually coming from settings. - #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" - //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROUTPUT_FRESH.hlsl" - - //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" - // #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_2.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl" - //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_Outside.hlsl" -#undef GRAIN -#undef DITHER + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" + #undef GRAIN + #undef DITHER #endif #pragma enable_d3d11_debug_symbols @@ -142,10 +135,6 @@ Shader "Hidden/HDRP/FinalPass" #endif #endif //FXAA -#if TEST_HDR_IMAGE == 1 - outColor.rgb = SAMPLE_TEXTURE2D(_HDRImageTest, s_linear_repeat_sampler, positionNDC).rgb; -#endif - // Saturate is only needed for dither or grain to work. Otherwise we don't saturate because output might be HDR // TODO_FCC: How to handle this in HDR Output? #if defined(GRAIN) || defined(DITHER) @@ -193,19 +182,9 @@ Shader "Hidden/HDRP/FinalPass" #if HDR_OUTPUT - // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits - // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float paperWhiteBoost = 1;// ??????? Something like this should come from calibration, so probably allow to set via script AND via ux. - // outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite * paperWhiteBoost, _MinNits, _MaxNits, _RangeReductionMode); - outColor.rgb = HDRMappingFromRec709_ACES(outColor.rgb, _PaperWhite * paperWhiteBoost); - //// This looks really bad now, so it is likely wrong code, will come back when making stuff more ordinate. float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); - outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * paperWhiteBoost); -#else -#if TEST_HDR_IMAGE == 1 - - outColor.rgb = NeutralTonemap(outColor.rgb); -#endif + float uiBoost = 1.0f; // TODO_FCC: Add from editor UI + outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * uiBoost); #endif #if !defined(ENABLE_ALPHA) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 36cf4394cce..f050187b4e3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -1,105 +1,121 @@ // Important! This file assumes Color.hlsl has been already included. -// TEMP_REMOVE_NOTES_FCC: -// - I think at the moment our grading output is in sRGB so we'll need here to rotate back to BT 2020 effectively losing lots of colors, what if we do the opposite? What if we output the grading to BT 2020 and then rotate for the sRGB? For perf? -// TODO_FCC: Decide what to do with the UI (where to put it at least) - - -// Attack plan: -// - Do all the grading and tone mapping in Rec2020 (well, at least do final rotation to Rec2020). Or maybe AP1 since we already have it from the tonemapper? -// - We reach the Final pass where we do the display mapping, in here: -// * If HDR: If we need to output to P3, rotate to Rec2020 to P3 (P3 is a subset), then in any case perform range reduction based min/max brightness given by user or manufacturer (or using decent defaults: 10 to 1000 nits?) with BT2390 EETF (as in CoD) . -// this requires moving to ICtCp color space and apply the curve on the I value of the ICtCp value. Then rotate back to Rec2020 + PQ. Probably the whole thing can be LUTed. [https://www.shadertoy.com/view/ldKcz3] -// - * If SDR: Do range reduction here (using this https://www.desmos.com/calculator/esjyfpsjvn from frostbite presentation), however keep in mind that we need to account for hue shift. Check slide 93 of frostbite presentation. - -// TODO_Perf: When full pipeline is done, try to LUT the most we can. - - -// TODOs: -// - We should tonemap in a rotated color space (i.e. BT2020) to get more out of it. We then rotate to Rec709 on SDR and not viceversa -// - Expose the paper white nit to user, a sensible range is 50 - 300. - // 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 BT2020 and . +// 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). This is what is applied in camera and therefore what we need to use. +// 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 HDR 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. -// Note: Ideally the pipeline should work in WCG, but this require more fundamental changes both to the rendering pipeline and the content authoring. As such we assume we start from Rec709 color gamut. -// However at some point we'd need to consider the eventuality of WCG aware content and add the option that assumes that the input color space is Rec2020. // -------------------------------- -// COLOR PRIMARIES ROTATION +// Perceptual Quantizer (PQ) / ST 2084 +// -------------------------------- +// This section has a bunch of options, a few of them are accurate a bunch are not. +#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 / PQ_M); + float X = (max(0.0, Em2 - PQ_C1)) / (PQ_C2 - PQ_C3 * Em2); + return pow(X, 1 / 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 = - { + 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 RotateRec709ToP3(float3 Rec709Input) -{ - static const float3x3 Rec709ToP3Mat = - { - 0.822458, 0.177542, 0.000000, - 0.033193, 0.966807, 0.000000, - 0.017085, 0.072410, 0.910505 - }; - - return mul(Rec709ToP3Mat, Rec709Input); -} - float3 RotateRec2020ToRec709(float3 Rec2020Input) { - static const float3x3 Rec2020ToRec709Mat = - { + 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); } -// TODO_IMPORTANT: Verify this. -float3 RotateRec2020ToP3(float3 Rec2020Input) -{ - static const float3x3 Rec2020ToXYZMat = - { - 1.660496, -0.587656, -0.072840, - -0.124547, 1.132895, -0.008348, - -0.018154, -0.100597, 1.118751 - }; - - static const float3x3 XYZToP3D65Mat = - { - 2.4933963, -0.9313459, -0.4026945, - -0.8294868, 1.7626597, 0.0236246, - 0.0358507, -0.0761827, 0.9570140 - }; - - static const float3x3 Rec2020toP3Mat = mul(XYZToP3D65Mat, Rec2020ToXYZMat); - - return mul(Rec2020toP3Mat, Rec2020Input); -} - -// Ref: ICtCp Dolby white paper (https://www.dolby.com/us/en/technologies/dolby-vision/ictcp-white-paper.pdf) float3 RotateRec2020ToLMS(float3 Rec2020Input) { static const float3x3 Rec2020ToLMSMat = @@ -112,50 +128,83 @@ float3 RotateRec2020ToLMS(float3 Rec2020Input) return mul(Rec2020ToLMSMat, Rec2020Input); } -float3 RotateLMSToRec2020(float3 LMSInput) +// 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 LMSToRec2020Mat = - { - 3.43660669433308, -2.50645211865627, 0.0698454243232, - -0.79132955559892, 1.98360045179229, -0.1922708961934, - -0.02594989969059, -0.09891371471173, 1.1248636144023 - }; + 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(LMSToRec2020Mat, LMSInput); + return mul(PQLMSToICtCpMat, LMSInput); } -float3 RotateRec709ToWCG(float3 Rec709Input) + +float3 RotateRec2020ToICtCp(float3 Rec2020) { -#ifdef WCG_REC2020 - return RotateRec709ToRec2020(Rec709Input); -#elif defined(WCG_P3) - return RotateRec709ToP3(Rec709Input); -#endif - // We should really reach this point. - return Rec709Input; + float3 lms = RotateRec2020ToLMS(Rec2020); + float3 PQLMS = LinearToPQ(max(0.0f, lms)); + return RotatePQLMSToICtCp(PQLMS); } +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); +} -// -------------------------------- -// OETF -// -------------------------------- -// We need to apply the inverse of the display EOTF which we, for now, we always assume to be PQ. -// Various methods follow. +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 + ); -// This is the accurate inverse of the PQ curve, it involves two pows therefore is leaning to the expensive end. -float3 AccuratePQInv(float3 inputCol) + return mul(XYZToRec2020Mat, XYZ); +} + +float3 RotateICtCpToPQLMS(float3 ICtCp) { - return LinearToPQ(inputCol); + 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); } -float AccuratePQInv(float x) +float3 RotateICtCpToRec2020(float3 ICtCp) { - return LinearToPQ(x); + float3 PQLMS = RotateICtCpToPQLMS(ICtCp); + float3 LMS = PQToLinear(PQLMS, MAX_PQ_VALUE); + float3 XYZ = RotateLMSToXYZ(LMS); + return RotateXYZToRec2020(XYZ); } +// -------------------------------------------------------------------------------------------- + +// -------------------------------- +// EOTF +// -------------------------------- +// Note that 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 EOTF_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. -float3 PatryInvPQ(float3 x) +// 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); @@ -163,121 +212,149 @@ float3 PatryInvPQ(float3 x) // 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/0n402k2syc ) in the full [0... 10 000] range, but still faster than reference -float3 GTSInvPQ(float3 inputCol) +// IMPORTANT! It requires the input to be scaled from [0 ... 10000] to [0...100]! +float3 GTSApproxLinToPQ(float3 inputCol) { - float3 k = pow((inputCol * 0.01), 0.1593017578125); + 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))); } -// TODO: Fourth option would be implementing the curve as a LUT - -#define PRECISE_INV_PQ 0 -#define ISS_APPROX_INV_PQ 1 -#define GTS_APPROX_INV_PQ 2 -#define INV_PQ_CHOICE PRECISE_INV_PQ +// IMPORTANT! This wants the input in [0...10000] range, if the method requires scaling, it is done inside this function. +float3 EOTF(float3 inputCol) +{ +#if EOTF_CHOICE == PRECISE_PQ + return LinearToPQ(inputCol); +#elif EOTF_CHOICE == ISS_APPROX_PQ + return PatryApproxLinToPQ(inputCol * 0.01f); +#elif EOTF_CHOICE == GTS_APPROX_PQ + return GTSApproxLinToPQ(inputCol * 0.01f); +#endif +} -// START FROM HERE: ACCURATE ONE NEEDS SCALING BY MAX BRIGHTNESS. -float3 ApplyOETF(float3 inputCol) +#define LIN_TO_PQ_FOR_LUT GTS_APPROX_PQ // GTS is close enough https://www.desmos.com/calculator/5jdfc4pgtk +float3 LinearToPQForLUT(float3 inputCol) { -#if INV_PQ_CHOICE == PRECISE_INV_PQ - return AccuratePQInv(inputCol); -#elif INV_PQ_CHOICE == ISS_APPROX_INV_PQ - return PatryInvPQ(inputCol); -#elif INV_PQ_CHOICE == GTS_APPROX_INV_PQ - return GTSInvPQ(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 // -------------------------------- -// Ref: [Malin 2018] HDR Display in Call of Duty -// Ref: [Fry 2017] High Dynamic Range Color Grading and Display in Frostbite -// We start from a signal that is assumed having 10k nits to the actual Target Display. -// In case of SDR this mean taking as input a linear signal and output a value in the [0...1] range using a piecewise function -// that starts linear and ends up with a exp curve as shoulder to compress highlights ( https://www.desmos.com/calculator/esjyfpsjvn ). -// In case of HDR we use BT2390 EETF as suggested in Ref: [Malin2018] HDR Display in Call of Duty - -// Ref: ICtCp Dolby white paper (https://www.dolby.com/us/en/technologies/dolby-vision/ictcp-white-paper.pdf) -float3 PQLMSToICtCp(float3 LMSInput) +// 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 REINHARD 0 +#define BT2390 1 +#define RANGE_REDUCTION BT2390 + +// Note this takes x being in [0...10k nits] +float ReinhardTonemap(float x, float peakValue) { - float3x3 PQLMSToICtCpMat = float3x3( - 0.5, 0.5, 0.0, - 1.613769, -3.323486, 1.709716, - 4.378174, -4.245605, -0.1325683 - ); - - return mul(PQLMSToICtCpMat, LMSInput); + float m = MAX_PQ_VALUE * peakValue / (MAX_PQ_VALUE - peakValue); + return x * m / (x + m); } -float3 ICtCpToPQLMS(float3 ICtCpInput) +/// BT2390 EETF Helper functions +float T(float A, float Ks) { - float3x3 ICtCpToPQLMSMat = float3x3( - 1.0, 0.008609, 0.111029, - 1.0, -0.008609, -0.111029, - 1.0, 0.560031, -0.320627 - ); - - return mul(ICtCpToPQLMSMat, ICtCpInput); + return (A - Ks) / (1.0f - Ks); } -float SDRRangeReduction(float val) +float P(float B, float Ks, float L_max) { - float expShoulder = 1.0f - exp(-val); - // TODO_FCC: We should allow this to be set. - float linearSectionEnd = 0.33f; + float TB2 = T(B, Ks) * T(B, Ks); + float TB3 = TB2 * T(B, Ks); - return val > linearSectionEnd ? expShoulder : val; + 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; } -float3 SDRRangeReduction(float3 val) + +// 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) { - return float3(SDRRangeReduction(val.x), SDRRangeReduction(val.y), SDRRangeReduction(val.z)); + 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); } -float BT2390EETFHermite(float x, float kneeStart, float maxLum) +float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits) { - float T = (x - kneeStart) / (1.0f - kneeStart); - float T2 = T * T; - float T3 = T2 * T; + float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); +#if RANGE_REDUCTION == REINHARD + linearLuma = ReinhardTonemap(linearLuma, maxNits); +#elif RANGE_REDUCTION == BT2390 + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); +#endif + ICtCp.x = LinearToPQ(linearLuma); - return (2 * T3 - 3 * T2 + 1) * kneeStart + (T3 - 2 * T2 + T) * (1 - kneeStart) + (-2 * T3 + 3 * T2) * maxLum; + + return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! } -// TODO: Can we squash this all thing into a LUT? Probably so. -// Ref: BT2390 standard doc https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-3-2017-PDF-E.pdf -float3 HDRRangeReduction(float3 Rec2020Input, float minNit, float maxNit) +float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits, int mode) { - // 1) Rec 2020 to LMS -> LMS to PQ -> PQ to ICtCp - float3 LMSVal = RotateRec2020ToLMS(Rec2020Input); - // For now accurate, TODO: Check if we can use the approx version. - float3 PQLMS = AccuratePQInv(LMSVal); - float3 ICtCp = PQLMSToICtCp(PQLMS); - - // 2) Apply EETF [ https://www.desmos.com/calculator/vgc7s0juzp ] - // TODO_FCC: Compute this two values on CPU - float minLumPQ = AccuratePQInv(minNit); - float maxLumPQ = AccuratePQInv(maxNit); - - float kneeStart = 1.5f * maxLumPQ - 0.5f; - float e2 = ICtCp.x < kneeStart ? ICtCp.x : BT2390EETFHermite(ICtCp.x, kneeStart, maxLumPQ); - - float intensityReduced = e2 + minLumPQ * PositivePow((1.0f - e2), 4); - // As mentioned by BT2390, we need to adjust saturation - float saturationScale = min(intensityReduced / ICtCp.x, ICtCp.x / intensityReduced); - - float3 newICtCp = float3(intensityReduced, ICtCp.yz * saturationScale); - - // 3) ICtCp to PQ -> PQ to LMS -> LMS to Rec 2020 - PQLMS = ICtCpToPQLMS(newICtCp); - LMSVal = PQToLinear(PQLMS); // TODO_FCC: Approx? - return RotateLMSToRec2020(LMSVal); + float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); + if (mode == 1) + linearLuma = ReinhardTonemap(linearLuma, maxNits); + else if (mode == 2) + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); + + ICtCp.x = LinearToPQ(linearLuma); + + if (mode == 3) + { + float3 outC = 0; + outC.x = BT2390EETF(Rec2020Input.x, minNits, maxNits); + outC.y = BT2390EETF(Rec2020Input.y, minNits, maxNits); + outC.z = BT2390EETF(Rec2020Input.z, minNits, maxNits); + return outC; + } + else if (mode == 4) + { + float3 outC = 0; + outC.x = ReinhardTonemap(Rec2020Input.x, maxNits); + outC.y = ReinhardTonemap(Rec2020Input.y, maxNits); + outC.z = ReinhardTonemap(Rec2020Input.z, maxNits); + return outC; + } + + return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! } + +// -------------------------------------------------------------------------------------------- + // -------------------------------- -// Display mapping functions +// 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* @@ -285,66 +362,51 @@ float3 HDRRangeReduction(float3 Rec2020Input, float minNit, float maxNit) // is in the Rec 2020 color space. However we still provide options in case we get a Rec709 input, this will just rotate to Rec2020 and // procede with the expected pipeline. -float3 SDRMapping_NoRotation(float3 input, float huePreservingFraction) +float3 HDRMappingFromRec2020(float3 Rec2020Input, float hdrBoost, float minNits, float maxNits) { - // As in [Fry 2017], we mix hue-preservation reduction and hue shifted reduction. - float maxChannel = Max3(input.x, input.y, input.z); - float reducedMax = SDRRangeReduction(maxChannel); - float3 reducedColHuePreserving = input * (reducedMax / maxChannel); - - // This is not hue preserving. - float3 rangePerChannelReduced = SDRRangeReduction(input); - - // NOTE: No OETF here since Unity handles it separately later on. - return lerp(rangePerChannelReduced, reducedColHuePreserving, huePreservingFraction); + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits + // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. + float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); + return EOTF(reducedHDR); } -float3 SDRMapping(float3 Rec2020Input, float huePreservingFraction) +float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode = 2) { - // Move to the correct color space - float3 Rec709Val = RotateRec2020ToRec709(SDRMapping_NoRotation(Rec2020Input, huePreservingFraction)); - return Rec709Val; + float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits + // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. + float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits, reductionMode); + return EOTF(reducedHDR); } -float3 HDRMapping(float3 Rec2020Input, float minNits, float maxNits) + +float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost) { - // First up we do range reduction - float3 reducedHDR = HDRRangeReduction(Rec2020Input, minNits, maxNits); + float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); + float3 oces = RRT(aces); + float3 AP1ODT = ODT_Rec2020_1000nits_ToAP1(oces); -#ifdef WCG_P3 - // The whole pipeline operates in Rec2020, if we need P3, we'll need to rotate now before going through the OETF - reducedHDR = RotateRec2020ToP3(reducedHDR); -#endif + const float3x3 AP1_2_Rec2020 = mul(XYZ_2_REC2020_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); + float3 linearODT = mul(AP1_2_Rec2020, AP1ODT); - return ApplyOETF(reducedHDR); -} -// Warning! This is never a good idea vs. the above, ideally the pipeline should always be working in the wider gamut -float3 HDRMappingFromRec709(float3 Rec709Input, float minNits, float maxNits) -{ - float3 rec2020Input = RotateRec709ToRec2020(Rec709Input); - return HDRMapping(rec2020Input, minNits, maxNits); + return EOTF(linearODT); } +// -------------------------------------------------------------------------------------------- + // -------------------------------- -// UI Composition functions +// UI Related functions // -------------------------------- -// Traditionally UI is not authored to be TODO_FCC FILL -// A bit verbose and optimizable. -float3 NormalizeUIForHDRComposition(float3 uiValue, float paperWhiteNits) +// Assumes UI is linear at this point ? Is it true? +float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) { - - const float maxNits2084 = 10000.0f; // The standard set 10k nits as max. - const float hdrScalar = paperWhiteNits / maxNits2084; - float3 linearRec709 = uiValue;// pow(uiValue, 2.2); - float3 linearUIRec2020 = RotateRec709ToRec2020(linearRec709); - return AccuratePQInv(linearUIRec2020.rgb * hdrScalar * paperWhiteNits); - - - //// TODO: Do we need to move to linear? Is it linear? Is it gamma? Need to check on UIOverlay side. - //// Assuming linear? - //float3 normalizedUI = (linearUIRec2020 * (paperWhiteNits / maxNits2084)); - //// Now move to PQ - //return AccuratePQInv(normalizedUI); + uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a)); + // TODO: Should we use an approximation here? + uiSample.rgb = LinearToPQ(uiSample.rgb, (MAX_PQ_VALUE / paperWhite)); + uiSample.rgb *= uiSample.a; + return uiSample.rgb + pqSceneColor.rgb * (1.0f - uiSample.a); } + +// -------------------------------------------------------------------------------------------- diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl deleted file mode 100644 index da8569edd47..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl +++ /dev/null @@ -1,346 +0,0 @@ -// Important! This file assumes Color.hlsl has been already included. - -// 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 HDR 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. - - -// -------------------------------- -// Perceptual Quantizer (PQ) / ST 2084 -// -------------------------------- -// This section has a bunch of options, a few of them are accurate a bunch are not. -#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) - -float3 LinearToPQ(float3 value, float maxPQValue) -{ - value /= maxPQValue; - float3 Ym1 = PositivePow(value, PQ_N); - float3 n = (PQ_C1 + PQ_C2 * Ym1); - float3 d = (1.0f + PQ_C3 * Ym1); - return PositivePow(n / d, PQ_M); -} - -float3 LinearToPQ(float3 value) -{ - return LinearToPQ(value, MAX_PQ_VALUE); -} - -float3 PQToLinear(float3 value) -{ - const float3 Em2 = PositivePow(value, 1 / PQ_M); - const float3 X = (max(0.0, Em2 - PQ_C1)) / (PQ_C2 - PQ_C3 * Em2); - return pow(X, 1 / PQ_N); -} - -float3 PQToLinear(float3 value, float maxPQValue) -{ - return PQToLinear(value) * maxPQValue; -} - -// -------------------------------------------------------------------------------------------- - -// -------------------------------- -// 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 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); -} - -// 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 RotateRec2020ToICtCp(float3 Rec2020) -{ - float3 lms = RotateRec2020ToLMS(Rec2020); - float3 PQLMS = LinearToPQ(max(0.0f, lms)); - return RotatePQLMSToICtCp(PQLMS); -} - -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 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 RotateICtCpToRec2020(float3 ICtCp) -{ - float3 PQLMS = RotateICtCpToPQLMS(ICtCp); - float3 LMS = PQToLinear(PQLMS, MAX_PQ_VALUE); - float3 XYZ = RotateLMSToXYZ(LMS); - return RotateXYZToRec2020(XYZ); -} - -// -------------------------------------------------------------------------------------------- - -// -------------------------------- -// EOTF -// -------------------------------- -// Note that 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/m6qi4llkcc -#define PRECISE_PQ 0 -#define ISS_APPROX_PQ 1 -#define GTS_APPROX_PQ 2 - -#define EOTF_CHOICE PRECISE_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 PatryApprox(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/0n402k2syc ) 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 GTSApprox(float3 inputCol) -{ - float3 k = pow((inputCol * 0.01), 0.1593017578125); - 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 EOTF(float3 inputCol) -{ -#if EOTF_CHOICE == PRECISE_PQ - return LinearToPQ(inputCol); -#elif EOTF_CHOICE == ISS_APPROX_PQ - return PatryApprox(inputCol * 0.01f); -#elif EOTF_CHOICE == GTS_APPROX_PQ - return GTSApprox(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 - -#define REINHARD 0 -#define BT2390 1 -#define RANGE_REDUCTION BT2390 - -// 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 see https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf - -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 Rec2020Input, float minNits, float maxNits) -{ - float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. - float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); -#if RANGE_REDUCTION == REINHARD - linearLuma = ReinhardTonemap(linearLuma, maxNits); -#elif RANGE_REDUCTION == BT2390 - linearLuma = BT2390EETF(linearLuma, minNits, maxNits); -#endif - ICtCp.x = LinearToPQ(linearLuma); - - return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! -} - -float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits, int mode) -{ - float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. - - float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); - if (mode == 1) - linearLuma = ReinhardTonemap(linearLuma, maxNits); - else if (mode == 2) - linearLuma = BT2390EETF(linearLuma, minNits, maxNits); - - ICtCp.x = LinearToPQ(linearLuma); - - return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! -} - - -// -------------------------------------------------------------------------------------------- - -// -------------------------------- -// 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 the Rec 2020 color space. However we still provide options in case we get a Rec709 input, this will just rotate to Rec2020 and -// procede with the expected pipeline. - -float3 HDRMappingFromRec2020(float3 Rec2020Input, float hdrBoost, float minNits, float maxNits) -{ - // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits - // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); - return EOTF(reducedHDR); -} - -float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode = 2) -{ - float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); - // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits - // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits, reductionMode); - return EOTF(reducedHDR); -} - - -float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost) -{ - float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); - float3 oces = RRT(aces); - float3 AP1ODT = ODT_Rec2020_1000nits_ToAP1(oces); - - const float3x3 AP1_2_Rec2020 = mul(XYZ_2_REC2020_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); - float3 linearODT = mul(AP1_2_Rec2020, AP1ODT); - - - return EOTF(linearODT); -} - -// -------------------------------------------------------------------------------------------- - -// -------------------------------- -// UI Related functions -// -------------------------------- - -// Assumes UI is linear at this point ? Is it true? -float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) -{ - uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a)); - uiSample.rgb = LinearToPQ(uiSample.rgb, (MAX_PQ_VALUE / paperWhite)); - uiSample.rgb *= uiSample.a; - return uiSample.rgb + pqSceneColor.rgb * (1.0f - uiSample.a); -} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta deleted file mode 100644 index 323ad80d13c..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput_3.hlsl.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1927822c5d86a7e4e8aa5ae396a569d0 -ShaderIncludeImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: 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 2162164d112..9704bd30f64 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 @@ -9,9 +9,8 @@ #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #ifdef HDR_OUTPUT #define WCG_REC2020 // For now hard coded, eventually coming from settings. -//#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" #endif - TEXTURE3D(_LogLut3D); RW_TEXTURE3D(float4, _OutputTexture); @@ -55,11 +54,23 @@ CBUFFER_START(cb0) float4 _MidSegmentB; float4 _ShoSegmentA; float4 _ShoSegmentB; + + // TODO_FCC: HDR RELATED STUFF, WILL NEED TO MOVE TO WHATEVER BUILDS THE LUT. + float4 _HDROutputParams; + float4 _HDROutputParams2; + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _IsRec2020 (int)(_HDROutputParams.w) == 0 + #define _IsRec709 (int)(_HDROutputParams.w) == 1 + #define _IsP3 (int)(_HDROutputParams.w) == 2 + #define _RangeReductionMode (int)_HDROutputParams2.x + CBUFFER_END float GetLuminance(float3 colorLinear) { - #if defined(TONEMAPPING_ACES) + #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) return AcesLuminance(colorLinear); #else return Luminance(colorLinear); @@ -76,7 +87,12 @@ float EvaluateCurve(TEXTURE2D(curve), float t) 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); @@ -84,7 +100,7 @@ float3 ColorGrade(float3 colorLutSpace) colorLinear = LMSToLinear(colorLMS); // Do contrast in log after white balance - #if defined(TONEMAPPING_ACES) + #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) float3 colorLog = ACES_to_ACEScc(unity_to_ACES(colorLinear)); #else float3 colorLog = LinearToLogC(colorLinear); @@ -92,7 +108,7 @@ float3 ColorGrade(float3 colorLutSpace) colorLog = (colorLog - ACEScc_MIDGRAY) * _HueSatCon.z + ACEScc_MIDGRAY; - #if defined(TONEMAPPING_ACES) + #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) colorLinear = ACES_to_ACEScg(ACEScc_to_ACES(colorLog)); #else colorLinear = LogCToLinear(colorLog); @@ -195,9 +211,14 @@ float3 ColorGrade(float3 colorLutSpace) 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) + #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) colorLinear = ACES_to_ACEScg(unity_to_ACES(colorLinear)); #endif @@ -234,17 +255,17 @@ float3 Tonemap(float3 colorLinear) float3 ProcessColorForHDR(float3 gradedColor) { -//#ifdef HDR_OUTPUT -// -// // TODO_FCC: Rotate to Rec2020 and all that jazz, but consider working directly in Rec2020 space instead of back and forth from LogC -// // Default assuming 1000 nits but come from options. -// float3 rec2020Input = RotateRec709ToRec2020(gradedColor); -// -// return HDRMappingFromRec709(gradedColor, 10, 400); -// return rec2020Input;// ApplyOETF(gradedColor); -//#else +#ifdef HDR_OUTPUT + // TODO_FCC: Rotate to Rec2020 and all that jazz, but consider working directly in Rec2020 space instead of back and forth from LogC + // Default assuming 1000 nits but come from options. +#if TONEMAPPING_ACES + return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite); +#else + return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode); +#endif +#else return gradedColor; -//#endif +#endif } @@ -260,6 +281,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 @@ -276,9 +298,11 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) } // TODO_FCC: Better handling of tonemapping. +#ifdef HDR_OUTPUT + gradedColor = ProcessColorForHDR(gradedColor); +#else gradedColor = Tonemap(gradedColor); - - //gradedColor = ProcessColorForHDR(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 d81a71a2b20..ae33b680e1d 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 @@ -17,6 +16,9 @@ #pragma multi_compile _ HDR_OUTPUT #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/PostProcessDefines.hlsl" +#ifdef HDR_OUTPUT +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" +#endif TEXTURE2D_X(_InputTexture); TEXTURE2D_X(_BloomTexture); @@ -225,6 +227,12 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID) #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. Consider maybe 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 } 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 43035a10b5d..aa64775e944 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 @@ -127,6 +127,7 @@ public PostProcessTextureAllocator() LiftGammaGain m_LiftGammaGain; ShadowsMidtonesHighlights m_ShadowsMidtonesHighlights; ColorCurves m_Curves; + HDROutputOptions m_HDROutput; FilmGrain m_FilmGrain; PathTracing m_PathTracing; @@ -335,6 +336,7 @@ void BeginPostProcessFrame(CommandBuffer cmd, HDCamera camera, HDRenderPipeline m_ChannelMixer = stack.GetComponent(); m_SplitToning = stack.GetComponent(); m_LiftGammaGain = stack.GetComponent(); + m_HDROutput = stack.GetComponent(); m_ShadowsMidtonesHighlights = stack.GetComponent(); m_Curves = stack.GetComponent(); m_FilmGrain = stack.GetComponent(); @@ -3909,6 +3911,9 @@ class ColorGradingPassData public Vector4 splitShadows; public Vector4 splitHighlights; + public Vector4 hdroutParameters; + public Vector4 hdroutParameters2; + public ColorCurves curves; public HableCurve hableCurve; @@ -3944,6 +3949,29 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) if (TEST_HDR()) { passData.builderCS.EnableKeyword("HDR_OUTPUT"); + int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : + (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var paperWhite = HDROutputSettings.main.paperWhiteNits; + int eetfMode = (int)m_HDROutput.mode.value; + if (!m_HDROutput.detectPaperWhite.value) + { + paperWhite = m_HDROutput.paperWhite.value; + } + if (!m_HDROutput.detectLimits.value) + { + minNits = (int)m_HDROutput.minNits.value; + maxNits = (int)m_HDROutput.maxNits.value; + } + if (!m_HDROutput.reduceOnlyLuminance.value) + { + eetfMode = m_HDROutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; + } + passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); + passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); } } else @@ -4177,6 +4205,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); @@ -4845,7 +4876,10 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo minNits = (int)hdrOutput.minNits.value; maxNits = (int)hdrOutput.maxNits.value; } - + if (!hdrOutput.reduceOnlyLuminance.value) + { + eetfMode = hdrOutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; + } passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); } From b2cc90a71f4f0009127f5715aa720f8de9b8282e Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 24 Sep 2021 19:48:31 +0200 Subject: [PATCH 12/65] Fix LUT behaviour. --- .../ShaderLibrary/ACES.hlsl | 155 ++++++++++++------ .../PostProcessing/Shaders/FinalPass.shader | 7 + .../PostProcessing/Shaders/HDROutput.hlsl | 30 ++-- .../Shaders/LutBuilder3D.compute | 5 +- .../PostProcessing/Shaders/UberPost.compute | 3 + .../HDRenderPipeline.PostProcess.cs | 55 ++++--- 6 files changed, 163 insertions(+), 92 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index 5ead6a913a8..dbab490e86e 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -512,57 +512,6 @@ struct SegmentedSplineParams_c9 float slopeHigh; // log-log slope of high linear extension }; -static 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 -}; -static 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 -}; - -static 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 -}; - -static 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 -}; - half segmented_spline_c9_fwd(half x, SegmentedSplineParams_c9 params) { const int N_KNOTS_LOW = 8; @@ -816,6 +765,19 @@ static const half ODT_SAT_FACTOR = 0.93; // half3 ODT_RGBmonitor_100nits_dim(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -914,6 +876,19 @@ half3 ODT_RGBmonitor_100nits_dim(half3 oces) // half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1024,6 +999,19 @@ half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) // half3 ODT_Rec709_100nits_dim(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1116,6 +1104,19 @@ half3 ODT_Rec709_100nits_dim(half3 oces) // half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1226,6 +1227,19 @@ half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) half3 ODT_Rec2020_100nits_dim(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1308,6 +1322,19 @@ half3 ODT_Rec2020_100nits_dim(half3 oces) // half3 ODT_P3DCI_48nits(half3 oces) { + 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1377,6 +1404,19 @@ half3 ODT_P3DCI_48nits(half3 oces) // 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 = + { + // 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1411,6 +1451,19 @@ half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) half3 ODT_Rec2020_1000nits_ToAP1(half3 oces) { + static 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 + }; + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); 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 bc265983415..b4c39c6f1a1 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 @@ -182,6 +182,13 @@ Shader "Hidden/HDRP/FinalPass" #if HDR_OUTPUT +#if !DEBUG_HDR_LUT_WORKFLOW + outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode); +#else + // Note that OETF needs to be called in final blit! If this is final blit it happens here, otherwise nah. + outColor.rgb = OETF(outColor.rgb); +#endif + float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); float uiBoost = 1.0f; // TODO_FCC: Add from editor UI outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * uiBoost); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index f050187b4e3..2a34b0de06d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -1,5 +1,7 @@ // Important! This file assumes Color.hlsl has been already included. +#define DEBUG_HDR_LUT_WORKFLOW 1 + // 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. @@ -190,16 +192,16 @@ float3 RotateICtCpToRec2020(float3 ICtCp) // -------------------------------------------------------------------------------------------- // -------------------------------- -// EOTF +// OETFs // -------------------------------- -// Note that the functions here are OETF, technically for applying the opposite of the PQ curve, we are mapping +// 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 EOTF_CHOICE GTS_APPROX_PQ +#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. @@ -221,13 +223,13 @@ float3 GTSApproxLinToPQ(float3 inputCol) } // IMPORTANT! This wants the input in [0...10000] range, if the method requires scaling, it is done inside this function. -float3 EOTF(float3 inputCol) +float3 OETF(float3 inputCol) { -#if EOTF_CHOICE == PRECISE_PQ +#if OETF_CHOICE == PRECISE_PQ return LinearToPQ(inputCol); -#elif EOTF_CHOICE == ISS_APPROX_PQ +#elif OETF_CHOICE == ISS_APPROX_PQ return PatryApproxLinToPQ(inputCol * 0.01f); -#elif EOTF_CHOICE == GTS_APPROX_PQ +#elif OETF_CHOICE == GTS_APPROX_PQ return GTSApproxLinToPQ(inputCol * 0.01f); #endif } @@ -367,20 +369,23 @@ float3 HDRMappingFromRec2020(float3 Rec2020Input, float hdrBoost, float minNits, // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); - return EOTF(reducedHDR); + return OETF(reducedHDR); } -float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode = 2) +float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode, bool skipOETF = false) { float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits, reductionMode); - return EOTF(reducedHDR); + + if (skipOETF) return reducedHDR; + + return OETF(reducedHDR); } -float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost) +float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOETF = false) { float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); float3 oces = RRT(aces); @@ -389,8 +394,9 @@ float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost) const float3x3 AP1_2_Rec2020 = mul(XYZ_2_REC2020_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT)); float3 linearODT = mul(AP1_2_Rec2020, AP1ODT); + if (skipOETF) return linearODT; - return EOTF(linearODT); + return OETF(linearODT); } // -------------------------------------------------------------------------------------------- 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 9704bd30f64..361ad8dd39f 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 @@ -25,6 +25,7 @@ TEXTURE2D(_CurveLumVsSat); SAMPLER(sampler_LogLut3D); SAMPLER(sampler_LinearClamp); +#pragma enable_d3d11_debug_symbols CBUFFER_START(cb0) float4 _Size; // x: lut_size, y: 1 / (lut_size - 1), zw: unused @@ -259,9 +260,9 @@ float3 ProcessColorForHDR(float3 gradedColor) // TODO_FCC: Rotate to Rec2020 and all that jazz, but consider working directly in Rec2020 space instead of back and forth from LogC // Default assuming 1000 nits but come from options. #if TONEMAPPING_ACES - return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite); + return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite, true); #else - return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode); + return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); #endif #else return gradedColor; 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 ae33b680e1d..a705a9190ab 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 @@ -231,8 +231,11 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID) // 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. Consider maybe using Patry if max nits is below 1400 // We multiply by 100 as in lut space 1 = 100 nits. +#if DEBUG_HDR_LUT_WORKFLOW colorLutSpace = LinearToPQForLUT(color.xyz * 100.0f); color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); +#endif + #endif } 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 aa64775e944..ae8733ac2f6 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 @@ -3946,39 +3946,40 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) case TonemappingMode.Custom: passData.builderCS.EnableKeyword("TONEMAPPING_CUSTOM"); break; case TonemappingMode.External: passData.builderCS.EnableKeyword("TONEMAPPING_EXTERNAL"); break; } - if (TEST_HDR()) - { - passData.builderCS.EnableKeyword("HDR_OUTPUT"); - int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : - HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : - (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; - - var minNits = HDROutputSettings.main.minToneMapLuminance; - var maxNits = HDROutputSettings.main.maxToneMapLuminance; - var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = (int)m_HDROutput.mode.value; - if (!m_HDROutput.detectPaperWhite.value) - { - paperWhite = m_HDROutput.paperWhite.value; - } - if (!m_HDROutput.detectLimits.value) - { - minNits = (int)m_HDROutput.minNits.value; - maxNits = (int)m_HDROutput.maxNits.value; - } - if (!m_HDROutput.reduceOnlyLuminance.value) - { - eetfMode = m_HDROutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; - } - passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); - passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); - } } else { passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } + if (TEST_HDR()) + { + passData.builderCS.EnableKeyword("HDR_OUTPUT"); + int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : + (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var paperWhite = HDROutputSettings.main.paperWhiteNits; + int eetfMode = (int)m_HDROutput.mode.value; + if (!m_HDROutput.detectPaperWhite.value) + { + paperWhite = m_HDROutput.paperWhite.value; + } + if (!m_HDROutput.detectLimits.value) + { + minNits = (int)m_HDROutput.minNits.value; + maxNits = (int)m_HDROutput.maxNits.value; + } + if (!m_HDROutput.reduceOnlyLuminance.value) + { + eetfMode = m_HDROutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; + } + passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); + passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); + } + passData.lutSize = m_LutSize; //passData.colorFilter; From 411f3077d2926366aa3c36464261b07d8215a093 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 27 Sep 2021 11:19:31 +0200 Subject: [PATCH 13/65] Fix final blit --- .../Shaders/CompositeWithUIAndOETF.shader | 86 +++++++++++++++++++ .../CompositeWithUIAndOETF.shader.meta | 10 +++ .../PostProcessing/Shaders/FinalPass.shader | 8 +- .../PostProcessing/Shaders/HDROutput.hlsl | 8 +- .../Shaders/LutBuilder3D.compute | 1 - .../HDRenderPipeline.PostProcess.cs | 7 +- .../HDRenderPipeline.RenderGraph.cs | 73 +++++++++++++--- .../RenderPipeline/HDRenderPipeline.cs | 4 + .../HDRenderPipelineRuntimeResources.cs | 2 + .../RenderPipeline/HDStringConstants.cs | 1 - .../Runtime/RenderPipeline/Utility/HDUtils.cs | 3 +- .../HDRenderPipelineRuntimeResources.asset | 2 +- 12 files changed, 171 insertions(+), 34 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader.meta 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..d08b4ae5548 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -0,0 +1,86 @@ +Shader "Hidden/HDRP/CompositeUI" +{ + HLSLINCLUDE + + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + #pragma editor_sync_compilation + + #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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" + + TEXTURE2D_X(_InputTexture); + TEXTURE2D_X(_UITexture); + + CBUFFER_START(cb) + float4 _HDROutputParams; + CBUFFER_END + + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _IsRec2020 (int)(_HDROutputParams.w) == 0 + #define _IsRec709 (int)(_HDROutputParams.w) == 1 + #define _IsP3 (int)(_HDROutputParams.w) == 2 + + 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; + // We need to flip y + uv.y = 1.0f - uv.y; + + float4 sceneColor = SAMPLE_TEXTURE2D_X(_InputTexture, s_point_clamp_sampler, uv); + + sceneColor.rgb = OETF(sceneColor.rgb); + + float4 uiSample = SAMPLE_TEXTURE2D_X(_UITexture, s_point_clamp_sampler, uv); + float uiBoost = 1.0f; // TODO_FCC: Add from editor UI + sceneColor.rgb = SceneUIComposition(uiSample, sceneColor.rgb, _PaperWhite * uiBoost); + + return sceneColor; + } + 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/FinalPass.shader b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FinalPass.shader index b4c39c6f1a1..be3815721fc 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 @@ -13,10 +13,6 @@ Shader "Hidden/HDRP/FinalPass" #pragma multi_compile_local_fragment _ APPLY_AFTER_POST #pragma multi_compile_local _ HDR_OUTPUT - // TODO_FCC: If HDR_OUTPUT, we entered this pass with an input color that is *not* range mapped and is in Rec2020 color space. - // So need to call HDRMapping(color, maxNit, minNit). - // If we need to composite UI, we need to do it in linear. - #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 @@ -29,8 +25,6 @@ Shader "Hidden/HDRP/FinalPass" #ifdef HDR_OUTPUT #define WCG_REC2020 // For now hard coded, eventually coming from settings. #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" - #undef GRAIN - #undef DITHER #endif #pragma enable_d3d11_debug_symbols @@ -181,7 +175,7 @@ Shader "Hidden/HDRP/FinalPass" #endif -#if HDR_OUTPUT +#if HDR_OUTPUT // All of this needs to be done at the very final blit. #if !DEBUG_HDR_LUT_WORKFLOW outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode); #else diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 2a34b0de06d..c597ac97e41 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -59,9 +59,9 @@ float3 LinearToPQ(float3 value) float PQToLinear(float value) { - float Em2 = PositivePow(value, 1 / PQ_M); + float Em2 = PositivePow(value, 1.0f / PQ_M); float X = (max(0.0, Em2 - PQ_C1)) / (PQ_C2 - PQ_C3 * Em2); - return pow(X, 1 / PQ_N); + return PositivePow(X, 1.0f / PQ_N); } float PQToLinear(float value, float maxPQValue) @@ -213,7 +213,7 @@ float3 PatryApproxLinToPQ(float3 x) } // 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/0n402k2syc ) in the full [0... 10 000] range, but still faster than reference +// 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) { @@ -234,7 +234,7 @@ float3 OETF(float3 inputCol) #endif } -#define LIN_TO_PQ_FOR_LUT GTS_APPROX_PQ // GTS is close enough https://www.desmos.com/calculator/5jdfc4pgtk +#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 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 361ad8dd39f..201e677cca8 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 @@ -25,7 +25,6 @@ TEXTURE2D(_CurveLumVsSat); SAMPLER(sampler_LogLut3D); SAMPLER(sampler_LinearClamp); -#pragma enable_d3d11_debug_symbols CBUFFER_START(cb0) float4 _Size; // x: lut_size, y: 1 / (lut_size - 1), zw: unused 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 ae8733ac2f6..20b5fa2ce93 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 @@ -4839,7 +4839,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.viewportSize = postProcessViewportSize; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS; + passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !TEST_HDR(); if (m_FilmGrain.type.value != FilmGrainLookup.Custom) passData.filmGrainTexture = defaultResources.textures.filmGrainTex[(int)m_FilmGrain.type.value]; else @@ -4848,7 +4848,7 @@ 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 && !TEST_HDR(); passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); @@ -4895,7 +4895,6 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.shaderKeywords = null; finalPassMaterial.SetTexture(HDShaderIDs._InputTexture, data.source); - finalPassMaterial.SetTexture(HDShaderIDs._HDRImageTest, defaultResources.textures.testHDR); if (data.dynamicResIsOn) { @@ -4975,7 +4974,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); // TODO: THIS IS ALL BAD, NEED TO MOVE AND MOST IMPORTANTLY AVOID CAPTURE. - if (TEST_HDR()) + if (TEST_HDR() && HDUtils.PostProcessIsFinalPass(data.hdCamera)) { finalPassMaterial.EnableKeyword("HDR_OUTPUT"); finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdroutParameters); 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 33c58709744..5ad5c6f3250 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 @@ -305,7 +305,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, viewIndex, TEST_HDR()); } if (aovRequest.isValid) @@ -318,7 +318,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, viewIndex, outputsToHDR: false); } } @@ -367,12 +367,14 @@ class FinalBlitPassData public int dstTexArraySlice; public Rect viewport; public Material blitMaterial; + public Vector4 hdrOutputParmeters; + public TextureHandle uiTexture; 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, int viewIndex, bool outputsToHDR) { using (var builder = renderGraph.AddRenderPass("Final Blit (Dev Build Only)", out var passData)) { @@ -393,25 +395,68 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH passData.source = builder.ReadTexture(source); passData.destination = builder.WriteTexture(destination); + if (outputsToHDR) + { + passData.blitMaterial = m_FinalBlitWithOETF; + int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : + HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : + (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + + var hdrOutput = hdCamera.volumeStack.GetComponent(); + + var minNits = HDROutputSettings.main.minToneMapLuminance; + var maxNits = HDROutputSettings.main.maxToneMapLuminance; + var paperWhite = HDROutputSettings.main.paperWhiteNits; + if (!hdrOutput.detectPaperWhite.value) + { + paperWhite = hdrOutput.paperWhite.value; + } + if (!hdrOutput.detectLimits.value) + { + minNits = (int)hdrOutput.minNits.value; + maxNits = (int)hdrOutput.maxNits.value; + } + passData.hdrOutputParmeters = new Vector4(minNits, maxNits, paperWhite, colorGamut); + + passData.uiTexture = builder.ReadTexture(uiTexture); + } + 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; + propertyBlock.SetTexture(HDShaderIDs._UITexture, data.uiTexture); + propertyBlock.SetTexture(HDShaderIDs._InputTexture, sourceTexture); + + propertyBlock.SetVector(HDShaderIDs._HDROutputParams, data.hdrOutputParmeters); } + 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); }); } 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 ff6341a19cd..de00a0db8a3 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; @@ -410,6 +411,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); @@ -770,6 +773,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(); 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 ee5d2e0b8f1..a5a3c24284d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -315,6 +315,8 @@ public sealed class ShaderResources public Shader lensFlareDataDrivenPS; [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 dff8a9f5d81..562617ec6e9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -935,7 +935,6 @@ static class HDShaderIDs 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 _HDRImageTest = Shader.PropertyToID("_HDRImageTest"); 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/RenderPipeline/Utility/HDUtils.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs index b08d3005305..eab4bee53c9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs @@ -900,8 +900,7 @@ internal static bool PostProcessIsFinalPass(HDCamera hdCamera) // Post process pass is the final blit only when not in developer mode. // In developer mode, we support a range of debug rendering that needs to occur after post processes. // In order to simplify writing them, we don't Y-flip in the post process pass but add a final blit at the end of the frame. - // TODO_FCC: IN HDR THIS CANNOT BE TRUE! - return true;// !Debug.isDebugBuild && !WillCustomPassBeExecuted(hdCamera, CustomPassInjectionPoint.AfterPostProcess); + return !Debug.isDebugBuild && !WillCustomPassBeExecuted(hdCamera, CustomPassInjectionPoint.AfterPostProcess); } // These two convertion functions are used to store GUID assets inside materials, 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 8514a0aba84..4427fe202b6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -148,6 +148,7 @@ MonoBehaviour: temporalAntialiasingPS: {fileID: 4800000, guid: 3dd9fd928fdb83743b1f27d15df22179, type: 3} lensFlareDataDrivenPS: {fileID: 4800000, guid: 85330b3de0cfebc4ba78b2d61b1a2899, 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} @@ -163,7 +164,6 @@ MonoBehaviour: bilateralUpsampleCS: {fileID: 7200000, guid: 68e831c555284d741b985e05369f0e63, type: 3} temporalFilterCS: {fileID: 7200000, guid: 741979ff70f7bd6489fbcb464280ecff, type: 3} diffuseDenoiserCS: {fileID: 7200000, guid: b4ed2382141619f40af1f743a84ccaea, type: 3} - defaultUIShader: {fileID: 4800000, guid: e5e91acae3155814cadad67bde39f914, type: 3} materials: defaultUIMat: {fileID: 2100000, guid: 0b4a88fad3f0a6440a0434e38f80ebab, type: 2} textures: From 9e55936a29b2af2e70e0062bae8d1118c82cebab Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 27 Sep 2021 11:33:48 +0200 Subject: [PATCH 14/65] Remove LUT debug switch, always debug --- .../Runtime/PostProcessing/Shaders/FinalPass.shader | 6 +----- .../Runtime/PostProcessing/Shaders/HDROutput.hlsl | 2 -- .../Runtime/PostProcessing/Shaders/UberPost.compute | 5 +---- 3 files changed, 2 insertions(+), 11 deletions(-) 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 be3815721fc..48b493843ee 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 @@ -176,12 +176,8 @@ Shader "Hidden/HDRP/FinalPass" #if HDR_OUTPUT // All of this needs to be done at the very final blit. -#if !DEBUG_HDR_LUT_WORKFLOW - outColor.rgb = HDRMappingFromRec709(outColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode); -#else - // Note that OETF needs to be called in final blit! If this is final blit it happens here, otherwise nah. + outColor.rgb = OETF(outColor.rgb); -#endif float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); float uiBoost = 1.0f; // TODO_FCC: Add from editor UI diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index c597ac97e41..3f8e7fc8ddd 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -1,7 +1,5 @@ // Important! This file assumes Color.hlsl has been already included. -#define DEBUG_HDR_LUT_WORKFLOW 1 - // 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. 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 a705a9190ab..d6b23111e1e 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 @@ -229,13 +229,10 @@ void Uber(uint3 dispatchThreadId : SV_DispatchThreadID) 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. Consider maybe using Patry if max nits is below 1400 + // 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. -#if DEBUG_HDR_LUT_WORKFLOW colorLutSpace = LinearToPQForLUT(color.xyz * 100.0f); color.xyz = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); -#endif - #endif } From f1ba317c0482ce0c0455e81747501e50dbb0e2c3 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 28 Sep 2021 10:05:11 +0200 Subject: [PATCH 15/65] scRGB support --- .../ShaderLibrary/ACES.hlsl | 2 +- .../ShaderLibrary/Color.hlsl | 5 - .../Shaders/CompositeWithUIAndOETF.shader | 7 +- .../PostProcessing/Shaders/FinalPass.shader | 7 +- .../PostProcessing/Shaders/HDROutput.hlsl | 193 +++++++++++++----- .../Shaders/LutBuilder3D.compute | 5 +- .../PostProcessing/Shaders/UberPost.compute | 4 +- 7 files changed, 159 insertions(+), 64 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index dbab490e86e..d405387cf8b 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -1449,7 +1449,7 @@ half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) return linearCV; } -half3 ODT_Rec2020_1000nits_ToAP1(half3 oces) +half3 ODT_1000nits_ToAP1(half3 oces) { static const SegmentedSplineParams_c9 ODT_1000nits = { diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index 25d72dffa67..75556f2d65b 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -611,13 +611,8 @@ float3 AcesTonemap(float3 aces) #if TONEMAPPING_USE_FULL_ACES float3 oces = RRT(aces); -#ifndef HDR_OUTPUT float3 odt = ODT_RGBmonitor_100nits_dim(oces); return odt; -#else - // We operate in 2020 and we don't need to apply the ODT here since it is applied at final pass stage. - return oces; -#endif #else 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 index d08b4ae5548..a1ee36c2f5c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -5,6 +5,7 @@ Shader "Hidden/HDRP/CompositeUI" #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 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" @@ -57,12 +58,12 @@ Shader "Hidden/HDRP/CompositeUI" uv.y = 1.0f - uv.y; float4 sceneColor = SAMPLE_TEXTURE2D_X(_InputTexture, s_point_clamp_sampler, uv); - sceneColor.rgb = OETF(sceneColor.rgb); - float4 uiSample = SAMPLE_TEXTURE2D_X(_UITexture, s_point_clamp_sampler, uv); + float4 uiValue = SAMPLE_TEXTURE2D_X(_UITexture, s_point_clamp_sampler, uv); + float uiBoost = 1.0f; // TODO_FCC: Add from editor UI - sceneColor.rgb = SceneUIComposition(uiSample, sceneColor.rgb, _PaperWhite * uiBoost); + sceneColor.rgb = SceneUIComposition(uiValue, sceneColor.rgb, _PaperWhite * uiBoost); return sceneColor; } 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 48b493843ee..b16605e7f2b 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,7 +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 + #pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #pragma multi_compile_local_fragment _ CATMULL_ROM_4 BYPASS #define DEBUG_UPSCALE_POINT 0 @@ -22,8 +22,7 @@ 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" -#ifdef HDR_OUTPUT - #define WCG_REC2020 // For now hard coded, eventually coming from settings. +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" #endif #pragma enable_d3d11_debug_symbols @@ -175,7 +174,7 @@ Shader "Hidden/HDRP/FinalPass" #endif -#if HDR_OUTPUT // All of this needs to be done at the very final blit. +#ifdef HDR_OUTPUT // All of this needs to be done at the very final blit. outColor.rgb = OETF(outColor.rgb); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 3f8e7fc8ddd..68b2ff1db36 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -1,5 +1,9 @@ // Important! This file assumes Color.hlsl has been already included. +#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. @@ -12,8 +16,8 @@ // 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 HDR 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. - +// 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 @@ -116,6 +120,24 @@ float3 RotateRec2020ToRec709(float3 Rec2020Input) 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 = @@ -128,6 +150,17 @@ float3 RotateRec2020ToLMS(float3 Rec2020Input) 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) { @@ -140,6 +173,12 @@ float3 RotatePQLMSToICtCp(float3 LMSInput) 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); @@ -147,6 +186,17 @@ float3 RotateRec2020ToICtCp(float3 Rec2020) 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( @@ -168,6 +218,12 @@ float3 RotateXYZToRec2020(float3 XYZ) return mul(XYZToRec2020Mat, XYZ); } +float3 RotateXYZToRec709(float3 XYZ) +{ + return mul(XYZ_2_REC709_MAT, XYZ); +} + + float3 RotateICtCpToPQLMS(float3 ICtCp) { static const float3x3 ICtCpToPQLMSMat = float3x3( @@ -179,12 +235,30 @@ float3 RotateICtCpToPQLMS(float3 ICtCp) return mul(ICtCpToPQLMSMat, ICtCp); } -float3 RotateICtCpToRec2020(float3 ICtCp) +float3 RotateICtCpToXYZ(float3 ICtCp) { float3 PQLMS = RotateICtCpToPQLMS(ICtCp); float3 LMS = PQToLinear(PQLMS, MAX_PQ_VALUE); - float3 XYZ = RotateLMSToXYZ(LMS); - return RotateXYZToRec2020(XYZ); + 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); +#endif } // -------------------------------------------------------------------------------------------- @@ -223,13 +297,20 @@ float3 GTSApproxLinToPQ(float3 inputCol) // IMPORTANT! This wants the input in [0...10000] range, if the method requires scaling, it is done inside this function. float3 OETF(float3 inputCol) { -#if OETF_CHOICE == PRECISE_PQ +#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 + #elif OETF_CHOICE == ISS_APPROX_PQ return PatryApproxLinToPQ(inputCol * 0.01f); -#elif OETF_CHOICE == GTS_APPROX_PQ + #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 @@ -303,9 +384,9 @@ float BT2390EETF(float x, float minLimit, float maxLimit) } -float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits) +float3 PerformRangeReduction(float3 input, float minNits, float maxNits) { - float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + float3 ICtCp = RotateOutputSpaceToICtCp(input); // This is in PQ space. float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); #if RANGE_REDUCTION == REINHARD linearLuma = ReinhardTonemap(linearLuma, maxNits); @@ -315,39 +396,45 @@ float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits) ICtCp.x = LinearToPQ(linearLuma); - return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! + return RotateICtCpToOutputSpace(ICtCp); // This moves back to linear too! } -float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits, int mode) +float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mode) { - float3 ICtCp = RotateRec2020ToICtCp(Rec2020Input); // This is in PQ space. + if (mode < 3) // Only luminance. + { + float3 ICtCp = RotateOutputSpaceToICtCp(input); // This is in PQ space. - float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); - if (mode == 1) - linearLuma = ReinhardTonemap(linearLuma, maxNits); - else if (mode == 2) - linearLuma = BT2390EETF(linearLuma, minNits, maxNits); + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); + if (mode == 1) + linearLuma = ReinhardTonemap(linearLuma, maxNits); + else if (mode == 2) + linearLuma = BT2390EETF(linearLuma, minNits, maxNits); - ICtCp.x = LinearToPQ(linearLuma); + ICtCp.x = LinearToPQ(linearLuma); - if (mode == 3) - { - float3 outC = 0; - outC.x = BT2390EETF(Rec2020Input.x, minNits, maxNits); - outC.y = BT2390EETF(Rec2020Input.y, minNits, maxNits); - outC.z = BT2390EETF(Rec2020Input.z, minNits, maxNits); - return outC; + return RotateICtCpToOutputSpace(ICtCp); // This moves back to linear too! } - else if (mode == 4) + else { - float3 outC = 0; - outC.x = ReinhardTonemap(Rec2020Input.x, maxNits); - outC.y = ReinhardTonemap(Rec2020Input.y, maxNits); - outC.z = ReinhardTonemap(Rec2020Input.z, maxNits); - return outC; + if (mode == 3) + { + float3 outC = 0; + outC.x = BT2390EETF(input.x, minNits, maxNits); + outC.y = BT2390EETF(input.y, minNits, maxNits); + outC.z = BT2390EETF(input.z, minNits, maxNits); + return outC; + } + else if (mode == 4) + { + float3 outC = 0; + outC.x = ReinhardTonemap(input.x, maxNits); + outC.y = ReinhardTonemap(input.y, maxNits); + outC.z = ReinhardTonemap(input.z, maxNits); + return outC; + } } - - return RotateICtCpToRec2020(ICtCp); // This moves back to linear too! + return 0; } @@ -359,23 +446,24 @@ float3 PerformRangeReduction(float3 Rec2020Input, float minNits, float maxNits, // 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 the Rec 2020 color space. However we still provide options in case we get a Rec709 input, this will just rotate to Rec2020 and -// procede with the expected pipeline. +// 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 hdrBoost, float minNits, float maxNits) { + float3 outputSpaceInput = RotateRec2020ToOutputSpace(Rec2020Input); + // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * hdrBoost, minNits, maxNits); return OETF(reducedHDR); } float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode, bool skipOETF = false) { - float3 Rec2020Input = RotateRec709ToRec2020(Rec709Input); + float3 outputSpaceInput = RotateRec709ToOutputSpace(Rec709Input); // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(Rec2020Input * hdrBoost, minNits, maxNits, reductionMode); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * hdrBoost, minNits, maxNits, reductionMode); if (skipOETF) return reducedHDR; @@ -387,11 +475,16 @@ float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOE { float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); float3 oces = RRT(aces); - float3 AP1ODT = ODT_Rec2020_1000nits_ToAP1(oces); + float3 AP1ODT = ODT_1000nits_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)); - float3 linearODT = mul(AP1_2_Rec2020, AP1ODT); - + linearODT = mul(AP1_2_Rec2020, AP1ODT); +#endif if (skipOETF) return linearODT; return OETF(linearODT); @@ -403,14 +496,22 @@ float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOE // UI Related functions // -------------------------------- -// Assumes UI is linear at this point ? Is it true? float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) { - uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a)); + // Undo the pre multiply. + uiSample.rgb = uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a); +#ifdef HDR_OUTPUT_SCRGB + uiSample.rgb = OETF(uiSample.rgb * paperWhite); + // TODO: At some point investigate this better. + float3 blendedVal = LinearToSRGB(uiSample.rgb) * uiSample.a + LinearToSRGB(pqSceneColor.rgb) * (1.0f - uiSample.a); + return SRGBToLinear(blendedVal); +#else + uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb); // TODO: Should we use an approximation here? uiSample.rgb = LinearToPQ(uiSample.rgb, (MAX_PQ_VALUE / paperWhite)); - uiSample.rgb *= uiSample.a; - return uiSample.rgb + pqSceneColor.rgb * (1.0f - uiSample.a); + return uiSample.rgb * uiSample.a + pqSceneColor.rgb * (1.0f - uiSample.a); +#endif + } // -------------------------------------------------------------------------------------------- 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 201e677cca8..eaab2cdd12f 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,14 +1,13 @@ #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 _ HDR_OUTPUT +#pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #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" -#ifdef HDR_OUTPUT -#define WCG_REC2020 // For now hard coded, eventually coming from settings. +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" #endif TEXTURE3D(_LogLut3D); 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 d6b23111e1e..0cab89ee34f 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 @@ -13,10 +13,10 @@ #pragma multi_compile _ LENS_DISTORTION #pragma multi_compile _ ENABLE_ALPHA #pragma multi_compile _ GAMMA2_OUTPUT -#pragma multi_compile _ HDR_OUTPUT +#pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/PostProcessDefines.hlsl" -#ifdef HDR_OUTPUT +#if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" #endif From 709dd89d01b4ee0cb027321e8d98cac52df6f7b8 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 28 Sep 2021 10:05:52 +0200 Subject: [PATCH 16/65] Miss some files with previous commit --- .../HDRenderPipeline.PostProcess.cs | 28 +++++++++++++------ .../HDRenderPipeline.RenderGraph.cs | 7 +++++ 2 files changed, 27 insertions(+), 8 deletions(-) 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 20b5fa2ce93..af77616a81e 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 @@ -3954,11 +3954,19 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) if (TEST_HDR()) { - passData.builderCS.EnableKeyword("HDR_OUTPUT"); int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; + if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + { + passData.builderCS.EnableKeyword("HDR_OUTPUT_SCRGB"); + } + else + { + passData.builderCS.EnableKeyword("HDR_OUTPUT_REC2020"); + } + var minNits = HDROutputSettings.main.minToneMapLuminance; var maxNits = HDROutputSettings.main.maxToneMapLuminance; var paperWhite = HDROutputSettings.main.paperWhiteNits; @@ -4457,7 +4465,7 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle if (TEST_HDR()) { - passData.uberPostCS.EnableKeyword("HDR_OUTPUT"); + passData.uberPostCS.EnableKeyword("HDR_OUTPUT_REC2020"); } passData.outputColorLog = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode == FullScreenDebugMode.ColorLog; @@ -4839,7 +4847,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.viewportSize = postProcessViewportSize; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !TEST_HDR(); + passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !TEST_HDR(); // 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 @@ -4976,15 +4984,19 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo // TODO: THIS IS ALL BAD, NEED TO MOVE AND MOST IMPORTANTLY AVOID CAPTURE. if (TEST_HDR() && HDUtils.PostProcessIsFinalPass(data.hdCamera)) { - finalPassMaterial.EnableKeyword("HDR_OUTPUT"); + if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + { + finalPassMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); + } + else + { + finalPassMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); + } finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdroutParameters); finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdroutParameters2); } - else - { - finalPassMaterial.DisableKeyword("HDR_OUTPUT"); - } + finalPassMaterial.SetTexture(HDShaderIDs._UITexture, data.uiBuffer); finalPassMaterial.SetVector(HDShaderIDs._UVTransform, 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 5ad5c6f3250..76404fa107b 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 @@ -438,6 +438,13 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH 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"); } else { From f117357764cadb20ab570983af6a4969b754d6ee Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 28 Sep 2021 13:50:38 +0200 Subject: [PATCH 17/65] Removing separate UI handling for now. --- .../Runtime/Material/UI/DefaultUI.shader | 147 ------------------ .../Runtime/Material/UI/DefaultUI.shader.meta | 10 -- .../PostProcessing/Shaders/HDROutput.hlsl | 3 +- .../HDRenderPipeline.RenderGraph.cs | 18 +-- .../RenderPipeline/HDRenderPipeline.cs | 54 +------ .../RenderPipeline/HDRenderPipelineAsset.cs | 6 - .../HDRenderPipelineRuntimeResources.cs | 2 - .../Material/DefaultHDUIMaterial.mat | 41 ----- .../Material/DefaultHDUIMaterial.mat.meta | 8 - 9 files changed, 8 insertions(+), 281 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader deleted file mode 100644 index 0dc627444e9..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader +++ /dev/null @@ -1,147 +0,0 @@ -Shader "HDRP/DefaultUI" -{ - HLSLINCLUDE - CBUFFER_START(cb) - int _UISrcColorBlend; - int _UIDstColorBlend; - int _UISrcAlphaBlend; - int _UIDstAlphaBlend; - CBUFFER_END - ENDHLSL - - Properties - { - [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} - _Color("Tint", Color) = (1,1,1,1) - - _StencilComp("Stencil Comparison", Float) = 8 - _Stencil("Stencil ID", Float) = 0 - _StencilOp("Stencil Operation", Float) = 0 - _StencilWriteMask("Stencil Write Mask", Float) = 255 - _StencilReadMask("Stencil Read Mask", Float) = 255 - _SrcBlend("_SrcBlend", Float) = 1.0 - _DstBlend("_DstBlend", Float) = 0.0 - _AlphaSrcBlend("_AlphaSrcBlend", Float) = 1.0 - _AlphaDstBlend("_AlphaDstBlend", Float) = 0.0 - - _ColorMask("Color Mask", Float) = 15 - - [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0 - } - - SubShader - { - Tags - { - "Queue" = "Transparent" - "IgnoreProjector" = "True" - "RenderType" = "Transparent" - "PreviewType" = "Plane" - "CanUseSpriteAtlas" = "True" - } - - Stencil - { - Ref[_Stencil] - Comp[_StencilComp] - Pass[_StencilOp] - ReadMask[_StencilReadMask] - WriteMask[_StencilWriteMask] - } - - Cull Off - Lighting Off - ZWrite Off - ZTest[unity_GUIZTestMode] - Blend [_UISrcColorBlend] [_UIDstColorBlend], [_UISrcAlphaBlend] [_UIDstAlphaBlend] - ColorMask[_ColorMask] - - Pass - { - Name "Default" - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - #pragma target 2.0 - - #include "UnityCG.cginc" - #include "UnityUI.cginc" - #pragma enable_d3d11_debug_symbols - #pragma multi_compile_local _ UNITY_UI_CLIP_RECT - #pragma multi_compile_local _ UNITY_UI_ALPHACLIP - - struct appdata_t - { - float4 vertex : POSITION; - float4 color : COLOR; - float2 texcoord : TEXCOORD0; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct v2f - { - float4 vertex : SV_POSITION; - fixed4 color : COLOR; - float2 texcoord : TEXCOORD0; - float4 worldPosition : TEXCOORD1; - half4 mask : TEXCOORD2; - UNITY_VERTEX_OUTPUT_STEREO - }; - - sampler2D _MainTex; - fixed4 _Color; - fixed4 _TextureSampleAdd; - float4 _ClipRect; - float4 _MainTex_ST; - float _UIMaskSoftnessX; - float _UIMaskSoftnessY; - - v2f vert(appdata_t v) - { - v2f OUT; - UNITY_SETUP_INSTANCE_ID(v); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); - float4 vPosition = UnityObjectToClipPos(v.vertex); - OUT.worldPosition = v.vertex; - OUT.vertex = vPosition; - - float2 pixelSize = vPosition.w; - pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); - - float4 clampedRect = clamp(_ClipRect, -2e10, 2e10); - float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy); - OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex); - OUT.mask = half4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy))); - - OUT.color = v.color * _Color; - return OUT; - } - - fixed4 frag(v2f IN) : SV_Target - { - //Round up the alpha color coming from the interpolator (to 1.0/256.0 steps) - //The incoming alpha could have numerical instability, which makes it very sensible to - //HDR color transparency blend, when it blends with the world's texture. - const half alphaPrecision = half(0xff); - const half invAlphaPrecision = half(1.0 / alphaPrecision); - IN.color.a = round(IN.color.a * alphaPrecision)*invAlphaPrecision; - - half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd); - - #ifdef UNITY_UI_CLIP_RECT - half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw); - color.a *= m.x * m.y; - #endif - - #ifdef UNITY_UI_ALPHACLIP - clip(color.a - 0.001); - #endif - - color.rgb *= color.a; - - return color; - } - ENDCG - } - } -} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta deleted file mode 100644 index 2290a24ed31..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/UI/DefaultUI.shader.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: e5e91acae3155814cadad67bde39f914 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - preprocessorOverride: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 68b2ff1db36..3000811128d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -499,7 +499,8 @@ float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOE float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) { // Undo the pre multiply. - uiSample.rgb = uiSample.rgb / (uiSample.a == 0.0 ? 1.0 : uiSample.a); + uiSample.rgb = uiSample.rgb / (uiSample.a == 0.0f ? 1.0 : uiSample.a); + #ifdef HDR_OUTPUT_SCRGB uiSample.rgb = OETF(uiSample.rgb * paperWhite); // TODO: At some point investigate this better. 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 76404fa107b..5556e7c400f 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 @@ -33,7 +33,6 @@ void RecordRenderGraph(RenderRequest renderRequest, var camera = hdCamera.camera; var cullingResults = renderRequest.cullingResults.cullingResults; var customPassCullingResults = renderRequest.cullingResults.customPassCullingResults ?? cullingResults; - var uiCullingResult = renderRequest.cullingResults.uiCullingResults; bool msaa = hdCamera.msaaEnabled; var target = renderRequest.target; @@ -196,10 +195,10 @@ void RecordRenderGraph(RenderRequest renderRequest, 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, uiCullingResult, aovRequest, aovCustomPassBuffers); + shadowResult, cullingResults, customPassCullingResults, aovRequest, aovCustomPassBuffers); // TODO_FCC: TMP, MOVE FROM HERE. ALSO CONSIDER THAT FOR V1 WE MIGHT WANT TO ONLY SEPARATE OVERLAYS? - uiBuffer = RenderTransparentUI(m_RenderGraph, hdCamera, prepassOutput.depthBuffer, uiCullingResult); + uiBuffer = RenderTransparentUI(m_RenderGraph, hdCamera, prepassOutput.depthBuffer); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) { @@ -874,22 +873,19 @@ void RenderForwardError(RenderGraph renderGraph, class RenderOffscreenUIData { public Camera camera; - public RendererListHandle rendererList; public FrameSettings frameSettings; } TextureHandle CreateOffscreenUIBuffer(RenderGraph renderGraph, MSAASamples msaaSamples) { return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) - { colorFormat = GraphicsFormat.R8G8B8A8_UNorm, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); + { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); } - // TODO_FCC: IMPORTANT! HANDLE OPAQUE UI, WRITE ON SAME BUFFER BUT BEFORE HAND? WE ARE ASSUME ALL UNLIT? TextureHandle RenderTransparentUI(RenderGraph renderGraph, HDCamera hdCamera, - TextureHandle depthBuffer, - CullingResults cullResults) + TextureHandle depthBuffer) { var output = renderGraph.defaultResources.blackTextureXR; if (TEST_HDR() && SupportedRenderingFeatures.active.rendersUIOverlay) @@ -900,15 +896,10 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite); passData.camera = hdCamera.camera; - passData.rendererList = renderGraph.CreateRendererList(CreateTransparentRendererListDesc(cullResults, hdCamera.camera, m_AllTransparentPassNames, m_CurrentRendererConfigurationBakedLighting, HDRenderQueue.k_RenderQueue_AllTransparent)); - passData.rendererList = builder.UseRendererList(passData.rendererList); passData.frameSettings = hdCamera.frameSettings; builder.SetRenderFunc((RenderOffscreenUIData data, RenderGraphContext context) => { - // Do we want only overlays? If not do we want to disable TAA for this? How do we do? - // How do we handle exposure etc? For now disabled. But it works as a concept. - //RenderForwardRendererList(data.frameSettings, data.rendererList, false, context.renderContext, context.cmd); context.renderContext.ExecuteCommandBuffer(context.cmd); context.cmd.Clear(); context.renderContext.DrawUIOverlay(data.camera); @@ -1220,7 +1211,6 @@ TextureHandle RenderTransparency(RenderGraph renderGraph, ShadowResult shadowResult, CullingResults cullingResults, CullingResults customPassCullingResults, - CullingResults uiCullingResult, AOVRequestData aovRequest, List aovCustomPassBuffers) { 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 de00a0db8a3..509a67ceea6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -239,30 +239,6 @@ static bool TEST_HDR() return HDROutputSettings.main.active; } - static bool TEST_SEPARATEUICULLING() - { - return TEST_HDR() && false; - } - - internal void UpdateUIMaterialBlendMode(CommandBuffer cmd) - { - // TODO: THIS DOESN'T WORK!defaultUIMaterial is editor only... We should find another way, likely a global variables via shader variables. - if (TEST_HDR()) - { - cmd.SetGlobalInt("_UISrcColorBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); - cmd.SetGlobalInt("_UIDstColorBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - cmd.SetGlobalInt("_UISrcAlphaBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); - cmd.SetGlobalInt("_UIDstAlphaBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - } - else - { - cmd.SetGlobalInt("_UISrcColorBlend", (int)UnityEngine.Rendering.BlendMode.One); - cmd.SetGlobalInt("_UIDstColorBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - cmd.SetGlobalInt("_UISrcAlphaBlend", (int)UnityEngine.Rendering.BlendMode.One); - cmd.SetGlobalInt("_UIDstAlphaBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); - } - } - readonly SkyManager m_SkyManager = new SkyManager(); internal SkyManager skyManager { get { return m_SkyManager; } } @@ -1321,10 +1297,7 @@ protected override void Render(ScriptableRenderContext renderContext, Camera[] c if (needCulling) { - var uiLayerMask = TEST_SEPARATEUICULLING() ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; - // TODO_FCC For test, enable to see if it renders to separate without having HDR - // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; - skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, uiLayerMask, ref cullingResults); + skipRequest = !TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, ref cullingResults); } } @@ -1612,10 +1585,6 @@ ref List renderDatas var _cullingResults = UnsafeGenericPool.Get(); _cullingResults.Reset(); - var uiLayerMask = TEST_SEPARATEUICULLING() ? m_Asset.currentPlatformRenderPipelineSettings.uiLayer : (LayerMask)0; - // TODO_FCC For test, enable to see if it renders to separate without having HDR - // uiLayerMask = m_Asset.currentPlatformRenderPipelineSettings.uiLayer; - if (!(TryCalculateFrameParameters( camera, XRSystem.emptyPass, @@ -1624,7 +1593,7 @@ ref List renderDatas out var cullingParameters ) && TryCull( - camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, uiLayerMask, + camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, ref _cullingResults ) )) @@ -1859,8 +1828,6 @@ ref _cullingResults var renderRequest = renderRequests[renderRequestIndex]; var cmd = CommandBufferPool.Get(""); - // If we are in HDR output mode we need to update the default UI blend mode accordingly - UpdateUIMaterialBlendMode(cmd); // TODO: Avoid the intermediate target and render directly into final target // CommandBuffer.Blit does not work on Cubemap faces @@ -2375,7 +2342,6 @@ static bool TryCull( SkyManager skyManager, ScriptableCullingParameters cullingParams, HDRenderPipelineAsset hdrp, - LayerMask uiLayerMask, ref HDCullingResults cullingResults ) { @@ -2431,13 +2397,6 @@ ref HDCullingResults cullingResults skyManager.UpdateCurrentSkySettings(hdCamera); skyManager.SetupAmbientProbe(hdCamera); - // TODO_FCC: Comment the following if condition to test. - uint castedLayerMask = (uint)(int)uiLayerMask; - if (TEST_HDR()) - { - cullingParams.cullingMask &= ~castedLayerMask; - } - if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing)) { OverrideCullingForRayTracing(hdCamera, camera, ref cullingParams); @@ -2456,15 +2415,6 @@ ref HDCullingResults cullingResults } } - - if (TEST_HDR()) - { - cullingParams.cullingMask = castedLayerMask; - using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.UICullResults))) - cullingResults.uiCullingResults = renderContext.Cull(ref cullingParams); - } - - if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.PlanarProbe) && hdProbeCullState.cullingGroup != null) HDProbeSystem.QueryCullResults(hdProbeCullState, ref cullingResults.hdProbeCullingResults); else 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 e541783b7b1..47942161a84 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -218,12 +218,6 @@ bool UpdateDefineList(bool flagValue, string defineMacroValue) } #endif - - /// HDRP default UI material. - // TODO_FCC: Enable when ready. - public override Material defaultUIMaterial - => globalSettings?.renderPipelineResources?.materials.defaultUIMat; - /// /// Indicates if virtual texturing is currently enabled for this render pipeline instance. /// 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 a5a3c24284d..1cccb3112fc 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -377,8 +377,6 @@ public IEnumerable GetAllComputeShaders() [Serializable, ReloadGroup] public sealed class MaterialResources { - [Reload("Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat")] - public Material defaultUIMat; } [Serializable, ReloadGroup] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat deleted file mode 100644 index a23089f0296..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat +++ /dev/null @@ -1,41 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!21 &2100000 -Material: - serializedVersion: 6 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: DefaultHDUIMaterial - m_Shader: {fileID: 4800000, guid: e5e91acae3155814cadad67bde39f914, type: 3} - m_ShaderKeywords: - m_LightmapFlags: 4 - m_EnableInstancingVariants: 0 - m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 - stringTagMap: {} - disabledShaderPasses: [] - m_SavedProperties: - serializedVersion: 3 - m_TexEnvs: - - _MainTex: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - m_Ints: [] - m_Floats: - - _AlphaDstBlend: 10 - - _AlphaSrcBlend: 1 - - _ColorMask: 15 - - _DstBlend: 10 - - _SrcBlend: 1 - - _Stencil: 0 - - _StencilComp: 8 - - _StencilOp: 0 - - _StencilReadMask: 255 - - _StencilWriteMask: 255 - - _UseUIAlphaClip: 0 - m_Colors: - - _Color: {r: 1, g: 1, b: 1, a: 1} - m_BuildTextureStacks: [] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta deleted file mode 100644 index 0d7be6b04ab..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDUIMaterial.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0b4a88fad3f0a6440a0434e38f80ebab -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: From c038fd88aef8b0996228bcd86bec0d7cb64fd758 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 28 Sep 2021 16:08:30 +0200 Subject: [PATCH 18/65] Proper handling of after post process. --- .../Shaders/CompositeWithUIAndOETF.shader | 21 +++-- .../PostProcessing/Shaders/FinalPass.shader | 18 +++-- .../PostProcessing/Shaders/HDROutput.hlsl | 22 +++--- .../HDRenderPipeline.PostProcess.cs | 67 +++------------- .../HDRenderPipeline.RenderGraph.cs | 76 +++++++++++++++++-- 5 files changed, 116 insertions(+), 88 deletions(-) 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 index a1ee36c2f5c..881f87b8911 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -6,6 +6,7 @@ Shader "Hidden/HDRP/CompositeUI" #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" @@ -14,6 +15,7 @@ Shader "Hidden/HDRP/CompositeUI" TEXTURE2D_X(_InputTexture); TEXTURE2D_X(_UITexture); + TEXTURE2D_X(_AfterPostProcessTexture); CBUFFER_START(cb) float4 _HDROutputParams; @@ -57,15 +59,20 @@ Shader "Hidden/HDRP/CompositeUI" // We need to flip y uv.y = 1.0f - uv.y; - float4 sceneColor = SAMPLE_TEXTURE2D_X(_InputTexture, s_point_clamp_sampler, uv); - sceneColor.rgb = OETF(sceneColor.rgb); + float4 outColor = SAMPLE_TEXTURE2D_X(_InputTexture, s_point_clamp_sampler, uv); + // Apply AfterPostProcess target + #if APPLY_AFTER_POST + float4 afterPostColor = SAMPLE_TEXTURE2D_X_LOD(_AfterPostProcessTexture, s_point_clamp_sampler, uv, 0); + 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 = SAMPLE_TEXTURE2D_X(_UITexture, s_point_clamp_sampler, uv); + float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, uv, 0); + outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite, _MaxNits); + outColor.rgb = OETF(outColor.rgb); - float uiBoost = 1.0f; // TODO_FCC: Add from editor UI - sceneColor.rgb = SceneUIComposition(uiValue, sceneColor.rgb, _PaperWhite * uiBoost); - - return sceneColor; + return outColor; } ENDHLSL 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 b16605e7f2b..4037149b285 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 @@ -169,19 +169,23 @@ 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 // All of this needs to be done at the very final blit. - - outColor.rgb = OETF(outColor.rgb); + #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); - float4 uiValue = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, positionNDC.xy * _RTHandleScale.xy, 0); - float uiBoost = 1.0f; // TODO_FCC: Add from editor UI - outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite * uiBoost); -#endif + outColor.rgb = OETF(outColor.rgb); + } + #endif #if !defined(ENABLE_ALPHA) return float4(outColor, outAlpha); diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 3000811128d..1a4d0507610 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -496,23 +496,23 @@ float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOE // UI Related functions // -------------------------------- -float3 SceneUIComposition(float4 uiSample, float3 pqSceneColor, float paperWhite) +float3 ProcessUIForHDR(float3 uiSample, float paperWhite, float maxNits) { - // Undo the pre multiply. - uiSample.rgb = uiSample.rgb / (uiSample.a == 0.0f ? 1.0 : uiSample.a); - #ifdef HDR_OUTPUT_SCRGB - uiSample.rgb = OETF(uiSample.rgb * paperWhite); - // TODO: At some point investigate this better. - float3 blendedVal = LinearToSRGB(uiSample.rgb) * uiSample.a + LinearToSRGB(pqSceneColor.rgb) * (1.0f - uiSample.a); - return SRGBToLinear(blendedVal); + uiSample.rgb = (uiSample.rgb * paperWhite); #else uiSample.rgb = RotateRec709ToRec2020(uiSample.rgb); - // TODO: Should we use an approximation here? - uiSample.rgb = LinearToPQ(uiSample.rgb, (MAX_PQ_VALUE / paperWhite)); - return uiSample.rgb * uiSample.a + pqSceneColor.rgb * (1.0f - uiSample.a); + 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); } // -------------------------------------------------------------------------------------------- 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 af77616a81e..0fa64fd7956 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 @@ -436,11 +436,11 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, 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" }); @@ -585,61 +585,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 { @@ -4981,8 +4926,9 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); + bool processHDR = TEST_HDR() && HDUtils.PostProcessIsFinalPass(data.hdCamera); // TODO: THIS IS ALL BAD, NEED TO MOVE AND MOST IMPORTANTLY AVOID CAPTURE. - if (TEST_HDR() && HDUtils.PostProcessIsFinalPass(data.hdCamera)) + if (processHDR) { if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -5018,7 +4964,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 (!TEST_HDR() && 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 5556e7c400f..7e4b4c1ea0e 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 @@ -271,7 +271,8 @@ void RecordRenderGraph(RenderRequest renderRequest, aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers); } - TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, uiBuffer, cullingResults, hdCamera); + TextureHandle afterPostProcessBuffer = RenderAfterPostProcessObjects(m_RenderGraph, hdCamera, cullingResults, prepassOutput); + TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, uiBuffer, afterPostProcessBuffer, cullingResults, hdCamera); GenerateDebugImageHistogram(m_RenderGraph, hdCamera, postProcessDest); PushFullScreenExposureDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); @@ -304,7 +305,7 @@ void RecordRenderGraph(RenderRequest renderRequest, for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, viewIndex, TEST_HDR()); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, TEST_HDR()); } if (aovRequest.isValid) @@ -317,7 +318,7 @@ void RecordRenderGraph(RenderRequest renderRequest, { if (target.targetDepth != null) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, m_RenderGraph.ImportTexture(target.targetDepth), uiBuffer, viewIndex, outputsToHDR: false); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, m_RenderGraph.ImportTexture(target.targetDepth), uiBuffer, afterPostProcessBuffer, viewIndex, outputsToHDR: false); } } @@ -368,12 +369,14 @@ class FinalBlitPassData public Material blitMaterial; public Vector4 hdrOutputParmeters; + public FrameSettings frameSettings; public TextureHandle uiTexture; + public TextureHandle afterPostProcessTexture; public TextureHandle source; public TextureHandle destination; } - void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle source, TextureHandle destination, TextureHandle uiTexture, int viewIndex, bool outputsToHDR) + 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)) { @@ -392,7 +395,9 @@ 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.frameSettings = hdCamera.frameSettings; if (outputsToHDR) { @@ -444,6 +449,16 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH data.blitMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); else data.blitMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); + + if (data.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + { + data.blitMaterial.EnableKeyword("APPLY_AFTER_POST"); + data.blitMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); + } + else + { + data.blitMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, TextureXR.GetBlackTexture()); + } } else { @@ -882,7 +897,6 @@ TextureHandle CreateOffscreenUIBuffer(RenderGraph renderGraph, MSAASamples msaaS { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, clearBuffer = true, clearColor = Color.clear, msaaSamples = msaaSamples, name = "UI Buffer" }); } - TextureHandle RenderTransparentUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthBuffer) @@ -910,6 +924,58 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, 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, From 461f4dfd4beabc4f3b6c2286d34c916e401bb803 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 28 Sep 2021 18:23:38 +0200 Subject: [PATCH 19/65] Move to tonemap volume component --- .../PostProcessing/TonemappingEditor.cs | 52 ++++++++++++++ .../Components/HDROutputOptions.cs | 44 ------------ .../Components/HDROutputOptions.cs.meta | 11 --- .../PostProcessing/Components/Tonemapping.cs | 70 +++++++++++++++++++ .../Shaders/CompositeWithUIAndOETF.shader | 3 - .../PostProcessing/Shaders/FinalPass.shader | 3 - .../PostProcessing/Shaders/HDROutput.hlsl | 19 +++-- .../Shaders/LutBuilder3D.compute | 3 - .../HDRenderPipeline.PostProcess.cs | 60 ++++++++-------- .../HDRenderPipeline.RenderGraph.cs | 26 ++++--- .../RenderPipeline/HDRenderPipeline.cs | 14 +--- 11 files changed, 175 insertions(+), 130 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta 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 5ad30ae48a3..e464448327b 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -20,6 +20,16 @@ sealed class TonemappingEditor : VolumeComponentEditor SerializedDataParameter m_LutTexture; SerializedDataParameter m_LutContribution; + // HDR Mode. + SerializedDataParameter m_NeutralHDRRangeReductionMode; + SerializedDataParameter m_HDRReduceLuminanceOnly; + SerializedDataParameter m_HDRDetectPaperWhite; + SerializedDataParameter m_HDRPaperwhite; + SerializedDataParameter m_HDRDetectNitLimits; + SerializedDataParameter m_HDRMinNits; + SerializedDataParameter m_HDRMaxNits; + public override bool hasAdditionalProperties => true; + // Curve drawing utilities readonly HableCurve m_HableCurve = new HableCurve(); Rect m_CurveRect; @@ -40,6 +50,14 @@ 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_HDRReduceLuminanceOnly = Unpack(o.Find(x => x.tonemapOnlyLuminance)); + 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_Material = new Material(Shader.Find("Hidden/HD PostProcessing/Editor/Custom Tonemapper Curve")); } @@ -54,6 +72,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 +145,38 @@ 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); } + + if (hdrInPlayerSettings) + { + EditorGUILayout.LabelField("HDR Output"); + int hdrTonemapMode = m_Mode.value.intValue; + if (m_Mode.value.intValue == (int)TonemappingMode.Custom || m_Mode.value.intValue == (int)TonemappingMode.External) + { + EditorGUILayout.HelpBox("The selected tonmapping mode is not supported in HDR Output mode. It will fall-back to neutral tonmapping when outputting to HDR devices.", MessageType.Warning); + hdrTonemapMode = (int)TonemappingMode.Neutral; + } + + if (hdrTonemapMode == (int)TonemappingMode.Neutral) + { + PropertyField(m_NeutralHDRRangeReductionMode); + PropertyField(m_HDRReduceLuminanceOnly); + 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--; + } + } } void CheckCurveRT(int width, int height) diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs deleted file mode 100644 index 5bb9b30e765..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace UnityEngine.Rendering.HighDefinition -{ - public enum RangeReductionMode - { - None = 0, - Reinhard = 1, - BT2390 = 2 - } - - [Serializable] - public sealed class RangeReductionModeParameter : VolumeParameter - { - /// - /// Creates a new instance. - /// - /// The initial value to store in the parameter. - /// The initial override state for the parameter. - public RangeReductionModeParameter(RangeReductionMode value, bool overrideState = false) : base(value, overrideState) { } - } - - - [Serializable, VolumeComponentMenuForRenderPipeline("Post-processing/HDROutputOptions", typeof(HDRenderPipeline))] - [HDRPHelpURLAttribute("HDR-Output-Options")] - public sealed class HDROutputOptions : VolumeComponent, IPostProcessComponent - { - public BoolParameter enable = new BoolParameter(true); - public RangeReductionModeParameter mode = new RangeReductionModeParameter(RangeReductionMode.Reinhard); - public BoolParameter detectPaperWhite = new BoolParameter(true); - public BoolParameter reduceOnlyLuminance = new BoolParameter(true); - public ClampedFloatParameter paperWhite = new ClampedFloatParameter(100.0f, 0.0f, 350.0f); - public BoolParameter detectLimits = new BoolParameter(true); - public ClampedFloatParameter minNits = new ClampedFloatParameter(0.0f, 0.0f, 10.0f); - public ClampedFloatParameter maxNits = new ClampedFloatParameter(1000.0f, 0.0f, 3000.0f); - - - public bool IsActive() - { - return enable.value; - } - - } -} diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta deleted file mode 100644 index adc9ce1cf2c..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/HDROutputOptions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 27012304124a83d468527d92dea76b78 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - 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 dbfd2d593b2..1451fcad725 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 @@ -37,6 +37,34 @@ 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 + } + + [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) { } + } + + /// /// A volume component that holds settings for the Tonemapping effect. /// @@ -110,6 +138,48 @@ 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); + + /// + /// Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact. + /// + [Tooltip("Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact.")] + public BoolParameter tonemapOnlyLuminance = new BoolParameter(true); + + /// + /// Whether to use values detected from the output device as paperwhite. This value will often will 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 will 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("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.")] + 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.0f with ACES Tonemap. + /// + [Tooltip("The minimum brightness (in nits) of the screen. Note that this is assumed to be 0.0f with ACES Tonemap.")] + public ClampedFloatParameter minNits = new ClampedFloatParameter(0.0f, 0.0f, 50.0f); + /// + /// The maximum brightness (in nits) of the screen. Note that this is assumed to be 1000.0f with ACES Tonemap. + /// + [Tooltip("The minimum brightness (in nits) of the screen. Note that this is assumed to be 0.0f with ACES Tonemap.")] + public ClampedFloatParameter maxNits = new ClampedFloatParameter(1000.0f, 0.0f, 5000.0f); + /// /// Tells if the effect needs to be rendered or not. /// 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 index 881f87b8911..faefc4d47fa 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -24,9 +24,6 @@ Shader "Hidden/HDRP/CompositeUI" #define _MinNits _HDROutputParams.x #define _MaxNits _HDROutputParams.y #define _PaperWhite _HDROutputParams.z - #define _IsRec2020 (int)(_HDROutputParams.w) == 0 - #define _IsRec709 (int)(_HDROutputParams.w) == 1 - #define _IsP3 (int)(_HDROutputParams.w) == 2 struct Attributes { 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 4037149b285..b9e2e217e72 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 @@ -53,9 +53,6 @@ Shader "Hidden/HDRP/FinalPass" #define _MinNits _HDROutputParams.x #define _MaxNits _HDROutputParams.y #define _PaperWhite _HDROutputParams.z - #define _IsRec2020 (int)(_HDROutputParams.w) == 0 - #define _IsRec709 (int)(_HDROutputParams.w) == 1 - #define _IsP3 (int)(_HDROutputParams.w) == 2 #define _RangeReductionMode (int)_HDROutputParams2.x struct Attributes diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl index 1a4d0507610..e9d029168e0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl @@ -417,22 +417,21 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mod } else { + float3 outC = 0; + if (mode == 3) { - float3 outC = 0; - outC.x = BT2390EETF(input.x, minNits, maxNits); - outC.y = BT2390EETF(input.y, minNits, maxNits); - outC.z = BT2390EETF(input.z, minNits, maxNits); - return outC; - } - else if (mode == 4) - { - float3 outC = 0; outC.x = ReinhardTonemap(input.x, maxNits); outC.y = ReinhardTonemap(input.y, maxNits); outC.z = ReinhardTonemap(input.z, maxNits); - return outC; } + else if (mode == 4) + { + outC.x = BT2390EETF(input.x, minNits, maxNits); + outC.y = BT2390EETF(input.y, minNits, maxNits); + outC.z = BT2390EETF(input.z, minNits, maxNits); + } + return outC; } return 0; } 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 eaab2cdd12f..93120e3f517 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 @@ -60,9 +60,6 @@ CBUFFER_START(cb0) #define _MinNits _HDROutputParams.x #define _MaxNits _HDROutputParams.y #define _PaperWhite _HDROutputParams.z - #define _IsRec2020 (int)(_HDROutputParams.w) == 0 - #define _IsRec709 (int)(_HDROutputParams.w) == 1 - #define _IsP3 (int)(_HDROutputParams.w) == 2 #define _RangeReductionMode (int)_HDROutputParams2.x CBUFFER_END 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 0fa64fd7956..79f390fcb19 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 @@ -127,7 +127,6 @@ public PostProcessTextureAllocator() LiftGammaGain m_LiftGammaGain; ShadowsMidtonesHighlights m_ShadowsMidtonesHighlights; ColorCurves m_Curves; - HDROutputOptions m_HDROutput; FilmGrain m_FilmGrain; PathTracing m_PathTracing; @@ -336,7 +335,6 @@ void BeginPostProcessFrame(CommandBuffer cmd, HDCamera camera, HDRenderPipeline m_ChannelMixer = stack.GetComponent(); m_SplitToning = stack.GetComponent(); m_LiftGammaGain = stack.GetComponent(); - m_HDROutput = stack.GetComponent(); m_ShadowsMidtonesHighlights = stack.GetComponent(); m_Curves = stack.GetComponent(); m_FilmGrain = stack.GetComponent(); @@ -3899,10 +3897,6 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) if (TEST_HDR()) { - int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : - HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : - (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; - if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { passData.builderCS.EnableKeyword("HDR_OUTPUT_SCRGB"); @@ -3915,22 +3909,26 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) var minNits = HDROutputSettings.main.minToneMapLuminance; var maxNits = HDROutputSettings.main.maxToneMapLuminance; var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = (int)m_HDROutput.mode.value; - if (!m_HDROutput.detectPaperWhite.value) + int eetfMode = 0; + if (m_Tonemapping.mode.value == TonemappingMode.Neutral || + m_Tonemapping.mode.value == TonemappingMode.Custom || + m_Tonemapping.mode.value == TonemappingMode.External) { - paperWhite = m_HDROutput.paperWhite.value; + eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + + ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); } - if (!m_HDROutput.detectLimits.value) + if (!m_Tonemapping.detectPaperWhite.value) { - minNits = (int)m_HDROutput.minNits.value; - maxNits = (int)m_HDROutput.maxNits.value; + paperWhite = m_Tonemapping.paperWhite.value; } - if (!m_HDROutput.reduceOnlyLuminance.value) + if (!m_Tonemapping.detectBrightnessLimits.value) { - eetfMode = m_HDROutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; + minNits = (int)m_Tonemapping.minNits.value; + maxNits = (int)m_Tonemapping.maxNits.value; } - passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); - passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); + + passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, 0); + passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); } passData.lutSize = m_LutSize; @@ -4811,31 +4809,29 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo if (TEST_HDR()) { - int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : - HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : - (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; - - var hdrOutput = hdCamera.volumeStack.GetComponent(); - var minNits = HDROutputSettings.main.minToneMapLuminance; var maxNits = HDROutputSettings.main.maxToneMapLuminance; var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = (int)hdrOutput.mode.value; - if (!hdrOutput.detectPaperWhite.value) + int eetfMode = 0; + if (m_Tonemapping.mode.value == TonemappingMode.Neutral || + m_Tonemapping.mode.value == TonemappingMode.Custom || + m_Tonemapping.mode.value == TonemappingMode.External) { - paperWhite = hdrOutput.paperWhite.value; + eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + + ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); } - if (!hdrOutput.detectLimits.value) + if (!m_Tonemapping.detectPaperWhite.value) { - minNits = (int)hdrOutput.minNits.value; - maxNits = (int)hdrOutput.maxNits.value; + paperWhite = m_Tonemapping.paperWhite.value; } - if (!hdrOutput.reduceOnlyLuminance.value) + if (!m_Tonemapping.detectBrightnessLimits.value) { - eetfMode = hdrOutput.mode.value == RangeReductionMode.Reinhard ? 4 : 3; + minNits = (int)m_Tonemapping.minNits.value; + maxNits = (int)m_Tonemapping.maxNits.value; } - passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, colorGamut); - passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, colorGamut); + + passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, 0); + passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); } 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 7e4b4c1ea0e..a130e1c3019 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 @@ -402,25 +402,29 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH if (outputsToHDR) { passData.blitMaterial = m_FinalBlitWithOETF; - int colorGamut = (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec2020 || HDROutputSettings.main.displayColorGamut == ColorGamut.HDR10) ? 0 : - HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : - (HDROutputSettings.main.displayColorGamut == ColorGamut.DisplayP3 || HDROutputSettings.main.displayColorGamut == ColorGamut.DolbyHDR) ? 2 : -1; - - var hdrOutput = hdCamera.volumeStack.GetComponent(); var minNits = HDROutputSettings.main.minToneMapLuminance; var maxNits = HDROutputSettings.main.maxToneMapLuminance; var paperWhite = HDROutputSettings.main.paperWhiteNits; - if (!hdrOutput.detectPaperWhite.value) + int eetfMode = 0; + if (m_Tonemapping.mode.value == TonemappingMode.Neutral || + m_Tonemapping.mode.value == TonemappingMode.Custom || + m_Tonemapping.mode.value == TonemappingMode.External) + { + eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + + ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); + } + if (!m_Tonemapping.detectPaperWhite.value) { - paperWhite = hdrOutput.paperWhite.value; + paperWhite = m_Tonemapping.paperWhite.value; } - if (!hdrOutput.detectLimits.value) + if (!m_Tonemapping.detectBrightnessLimits.value) { - minNits = (int)hdrOutput.minNits.value; - maxNits = (int)hdrOutput.maxNits.value; + minNits = (int)m_Tonemapping.minNits.value; + maxNits = (int)m_Tonemapping.maxNits.value; } - passData.hdrOutputParmeters = new Vector4(minNits, maxNits, paperWhite, colorGamut); + + passData.hdrOutputParmeters = new Vector4(minNits, maxNits, paperWhite, 0); passData.uiTexture = builder.ReadTexture(uiTexture); } 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 509a67ceea6..640bd13bb2a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,22 +199,12 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } - static void SetHDROutputState(HDCamera camera) - { - var hdrOutput = camera.volumeStack.GetComponent(); - if (HDROutputSettings.main.available) - { - HDROutputSettings.main.automaticHDRTonemapping = false; - HDROutputSettings.main.RequestHDRModeChange(hdrOutput.enable.value); - } - } - // TODO_FCC: THIS IS NEEDED FOR TESTING, REPLACE WITH HDROutputSettings.main.active LATER static bool TEST_HDR() { if (HDROutputSettings.main.available) { - //Debug.Log("Available"); + // Debug.Log("Available"); } if (HDROutputSettings.main.available && SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) @@ -1983,8 +1973,6 @@ AOVRequestData aovRequest // Updates RTHandle hdCamera.BeginRender(cmd); - SetHDROutputState(hdCamera); - if (m_RayTracingSupported) { // This call need to happen once per camera From b6d59025cdca80a134f3de7a82dc12144314183b Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 10:15:33 +0200 Subject: [PATCH 20/65] Cleanup and add ACES presets --- .../PostProcessing/HDROutputDefines.cs | 44 +++++++++ .../PostProcessing/HDROutputDefines.cs.hlsl | 20 ++++ .../HDROutputDefines.cs.hlsl.meta | 7 ++ .../PostProcessing/HDROutputDefines.cs.meta | 11 +++ .../ShaderLibrary/ACES.hlsl | 76 +++++++++++++-- .../ShaderLibrary}/HDROutput.hlsl | 94 +++++++++++-------- .../ShaderLibrary}/HDROutput.hlsl.meta | 0 .../PostProcessing/TonemappingEditor.cs | 7 ++ .../PostProcessing/Components/Tonemapping.cs | 42 ++++++++- .../Shaders/CompositeWithUIAndOETF.shader | 2 +- .../PostProcessing/Shaders/FinalPass.shader | 2 +- .../Shaders/LutBuilder3D.compute | 8 +- .../PostProcessing/Shaders/UberPost.compute | 2 +- .../HDRenderPipeline.PostProcess.cs | 88 ++++++++--------- .../HDRenderPipeline.RenderGraph.cs | 25 +---- 15 files changed, 298 insertions(+), 130 deletions(-) create mode 100644 com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs create mode 100644 com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl create mode 100644 com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl.meta create mode 100644 com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.meta rename {com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders => com.unity.render-pipelines.core/ShaderLibrary}/HDROutput.hlsl (88%) rename {com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders => com.unity.render-pipelines.core/ShaderLibrary}/HDROutput.hlsl.meta (100%) 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..de690be0716 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs @@ -0,0 +1,44 @@ +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 only on luminance. + /// + ReinhardLumaOnly, + /// + /// BT2390 Hermite spline EETF range reduction only on luminance. + /// + BT2390LumaOnly, + /// + /// 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..6e6ed3efa85 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl @@ -0,0 +1,20 @@ +// +// 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_LUMA_ONLY (1) +#define HDRRANGEREDUCTION_BT2390LUMA_ONLY (2) +#define HDRRANGEREDUCTION_REINHARD (3) +#define HDRRANGEREDUCTION_BT2390 (4) +#define HDRRANGEREDUCTION_ACES1000NITS (5) +#define HDRRANGEREDUCTION_ACES2000NITS (6) +#define HDRRANGEREDUCTION_ACES4000NITS (7) + + +#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 d405387cf8b..a4870622a3f 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -1324,15 +1324,13 @@ half3 ODT_P3DCI_48nits(half3 oces) { 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 + { -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) // 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) + half2(segmented_spline_c5_fwd(0.18 * exp2(-6.5)), 0.02), // {luminance, luminance} linear extension below this + half2(segmented_spline_c5_fwd(0.18), 4.8), // {luminance, luminance} + half2(segmented_spline_c5_fwd(0.18 * exp2(6.5)), 48.0), // {luminance, luminance} linear extension above this + 0.0, // log-log slope of low linear extension + 0.04 // log-log slope of high linear extension }; // OCES to RGB rendering space @@ -1401,6 +1399,8 @@ half3 ODT_P3DCI_48nits(half3 oces) return outputCV; } +// > 48 Nits from https://github.com/ampas/aces-dev/blob/dev/transforms/ctl/lib/ACESlib.Tonescales.ctl + // IMPORTANT: This will need transforming to the final output space after unlike the standard ODT. half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) { @@ -1417,6 +1417,8 @@ half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) 0.06 // slopeHigh }; + + // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1451,7 +1453,7 @@ half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) half3 ODT_1000nits_ToAP1(half3 oces) { - static const SegmentedSplineParams_c9 ODT_1000nits = + 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 }, @@ -1475,6 +1477,60 @@ half3 ODT_1000nits_ToAP1(half3 oces) return rgbPost; } + +half3 ODT_2000nits_ToAP1(half3 oces) +{ + 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 + }; + + // 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 = + { + // 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 + }; + + // 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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl similarity index 88% rename from com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl rename to com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index e9d029168e0..33ed09e5233 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -1,4 +1,8 @@ -// Important! This file assumes Color.hlsl has been already included. +// 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 @@ -335,9 +339,7 @@ float3 LinearToPQForLUT(float3 inputCol) // 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 REINHARD 0 -#define BT2390 1 -#define RANGE_REDUCTION BT2390 +#define RANGE_REDUCTION HDRRANGEREDUCTION_BT2390LUMA_ONLY // Note this takes x being in [0...10k nits] float ReinhardTonemap(float x, float peakValue) @@ -388,9 +390,9 @@ 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 == REINHARD +#if RANGE_REDUCTION == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY linearLuma = ReinhardTonemap(linearLuma, maxNits); -#elif RANGE_REDUCTION == BT2390 +#elif RANGE_REDUCTION == HDRRANGEREDUCTION_BT2390LUMA_ONLY linearLuma = BT2390EETF(linearLuma, minNits, maxNits); #endif ICtCp.x = LinearToPQ(linearLuma); @@ -401,39 +403,42 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits) float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mode) { - if (mode < 3) // Only luminance. + float3 outputValue = input; + if (mode == HDRRANGEREDUCTION_NONE) + { + outputValue = input; + } + else if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY || mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) { - float3 ICtCp = RotateOutputSpaceToICtCp(input); // This is in PQ space. + float3 ICtCp = RotateOutputSpaceToICtCp(input); float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); - if (mode == 1) + if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY) + { linearLuma = ReinhardTonemap(linearLuma, maxNits); - else if (mode == 2) + } + else if (mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) + { linearLuma = BT2390EETF(linearLuma, minNits, maxNits); + } ICtCp.x = LinearToPQ(linearLuma); - return RotateICtCpToOutputSpace(ICtCp); // This moves back to linear too! + outputValue = RotateICtCpToOutputSpace(ICtCp); } - else + else if (mode == HDRRANGEREDUCTION_REINHARD) { - float3 outC = 0; - - if (mode == 3) - { - outC.x = ReinhardTonemap(input.x, maxNits); - outC.y = ReinhardTonemap(input.y, maxNits); - outC.z = ReinhardTonemap(input.z, maxNits); - } - else if (mode == 4) - { - outC.x = BT2390EETF(input.x, minNits, maxNits); - outC.y = BT2390EETF(input.y, minNits, maxNits); - outC.z = BT2390EETF(input.z, minNits, maxNits); - } - return outC; + outputValue.x = ReinhardTonemap(input.x, maxNits); + outputValue.y = ReinhardTonemap(input.y, maxNits); + outputValue.z = ReinhardTonemap(input.z, maxNits); } - return 0; + else if (mode == HDRRANGEREDUCTION_BT2390) + { + outputValue.x = BT2390EETF(input.x, minNits, maxNits); + outputValue.y = BT2390EETF(input.y, minNits, maxNits); + outputValue.z = BT2390EETF(input.z, minNits, maxNits); + } + return outputValue; } @@ -447,22 +452,18 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mod // 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 hdrBoost, float minNits, float maxNits) +float3 HDRMappingFromRec2020(float3 Rec2020Input, float paperWhite, float minNits, float maxNits, int reductionMode) { float3 outputSpaceInput = RotateRec2020ToOutputSpace(Rec2020Input); - // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits - // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(outputSpaceInput * hdrBoost, minNits, maxNits); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode); return OETF(reducedHDR); } -float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, float maxNits, int reductionMode, bool skipOETF = false) +float3 HDRMappingFromRec709(float3 Rec709Input, float paperWhite, float minNits, float maxNits, int reductionMode, bool skipOETF = false) { float3 outputSpaceInput = RotateRec709ToOutputSpace(Rec709Input); - // The reason to have a boost factor is because the standard for SDR is peaking at 100nits, but televisions are typically 300nits - // and the colours get boosted. If we want equivalent look in HDR a similar boost needs to happen. It might look washed out otherwise. - float3 reducedHDR = PerformRangeReduction(outputSpaceInput * hdrBoost, minNits, maxNits, reductionMode); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode); if (skipOETF) return reducedHDR; @@ -470,11 +471,26 @@ float3 HDRMappingFromRec709(float3 Rec709Input, float hdrBoost, float minNits, f } -float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, bool skipOETF = false) +float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, int reductionMode, bool skipOETF = false) { float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); float3 oces = RRT(aces); - float3 AP1ODT = ODT_1000nits_ToAP1(oces); + + 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) @@ -515,3 +531,5 @@ float3 SceneUIComposition(float4 uiSample, float3 sceneColor, float paperWhite, } // -------------------------------------------------------------------------------------------- + +#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl.meta b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl.meta similarity index 100% rename from com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl.meta rename to com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl.meta 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 e464448327b..821ff34e952 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -28,6 +28,8 @@ sealed class TonemappingEditor : VolumeComponentEditor SerializedDataParameter m_HDRDetectNitLimits; SerializedDataParameter m_HDRMinNits; SerializedDataParameter m_HDRMaxNits; + SerializedDataParameter m_HDRAcesPreset; + public override bool hasAdditionalProperties => true; // Curve drawing utilities @@ -57,6 +59,7 @@ public override void OnEnable() 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_Material = new Material(Shader.Find("Hidden/HD PostProcessing/Editor/Custom Tonemapper Curve")); } @@ -176,6 +179,10 @@ public override void OnInspectorGUI() } EditorGUI.indentLevel--; } + if (hdrTonemapMode == (int)TonemappingMode.ACES) + { + PropertyField(m_HDRAcesPreset); + } } } 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 1451fcad725..c0f67e1ad5f 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 @@ -40,7 +40,6 @@ public enum TonemappingMode /// /// Available options for when HDR Output is enabled and Tonemap is set to Neutral. /// - /// public enum NeutralRangeReductionMode { /// @@ -53,6 +52,26 @@ public enum NeutralRangeReductionMode 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, + } + + [Serializable] public sealed class NeutralRangeReductionModeParameter : VolumeParameter { @@ -64,6 +83,16 @@ 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 HDRACESPresetParameter(HDRACESPreset value, bool overrideState = false) : base(value, overrideState) { } + } /// /// A volume component that holds settings for the Tonemapping effect. @@ -143,11 +172,16 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent /// /// 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); + /// /// Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact. /// @@ -170,10 +204,10 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent [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.0f with ACES Tonemap. + /// 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.0f with ACES Tonemap.")] - public ClampedFloatParameter minNits = new ClampedFloatParameter(0.0f, 0.0f, 50.0f); + 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 1000.0f with ACES Tonemap. /// 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 index faefc4d47fa..a9c40011463 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -11,7 +11,7 @@ Shader "Hidden/HDRP/CompositeUI" #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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" TEXTURE2D_X(_InputTexture); TEXTURE2D_X(_UITexture); 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 b9e2e217e72..ad27a5ed564 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 @@ -23,7 +23,7 @@ Shader "Hidden/HDRP/FinalPass" #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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" #endif #pragma enable_d3d11_debug_symbols 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 93120e3f517..4c7bbe76da1 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 @@ -8,7 +8,7 @@ #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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" #endif TEXTURE3D(_LogLut3D); RW_TEXTURE3D(float4, _OutputTexture); @@ -252,13 +252,13 @@ float3 Tonemap(float3 colorLinear) float3 ProcessColorForHDR(float3 gradedColor) { #ifdef HDR_OUTPUT - // TODO_FCC: Rotate to Rec2020 and all that jazz, but consider working directly in Rec2020 space instead of back and forth from LogC - // Default assuming 1000 nits but come from options. + #if TONEMAPPING_ACES - return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite, true); + return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); #else return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); #endif + #else return gradedColor; #endif 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 0cab89ee34f..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 @@ -17,7 +17,7 @@ #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.high-definition/Runtime/PostProcessing/Shaders/HDROutput.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" #endif TEXTURE2D_X(_InputTexture); 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 79f390fcb19..6720abff242 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 @@ -3472,7 +3472,6 @@ private void SetCurrentResolutionGroup(RenderGraph renderGraph, HDCamera camera, #endregion - #region Panini Projection Vector2 CalcViewExtents(HDCamera camera) { @@ -3906,29 +3905,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) passData.builderCS.EnableKeyword("HDR_OUTPUT_REC2020"); } - var minNits = HDROutputSettings.main.minToneMapLuminance; - var maxNits = HDROutputSettings.main.maxToneMapLuminance; - var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = 0; - if (m_Tonemapping.mode.value == TonemappingMode.Neutral || - m_Tonemapping.mode.value == TonemappingMode.Custom || - m_Tonemapping.mode.value == TonemappingMode.External) - { - eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + - ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); - } - if (!m_Tonemapping.detectPaperWhite.value) - { - paperWhite = m_Tonemapping.paperWhite.value; - } - if (!m_Tonemapping.detectBrightnessLimits.value) - { - minNits = (int)m_Tonemapping.minNits.value; - maxNits = (int)m_Tonemapping.maxNits.value; - } - - passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, 0); - passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); + GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); } passData.lutSize = m_LutSize; @@ -3988,6 +3965,45 @@ public 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; + if (tonemappingComponent.mode.value == TonemappingMode.Neutral || + tonemappingComponent.mode.value == TonemappingMode.Custom || + tonemappingComponent.mode.value == TonemappingMode.External) + { + bool luminanceOnly = tonemappingComponent.tonemapOnlyLuminance.value; + if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.BT2390) + { + eetfMode = luminanceOnly ? (int)HDRRangeReduction.BT2390LumaOnly : (int)HDRRangeReduction.BT2390; + } + if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.Reinhard) + { + eetfMode = luminanceOnly ? (int)HDRRangeReduction.ReinhardLumaOnly : (int)HDRRangeReduction.Reinhard; + } + } + if (tonemappingComponent.mode.value == 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, 0); + hdrOutputParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); + } + void ComputeShadowsMidtonesHighlights(out Vector4 shadows, out Vector4 midtones, out Vector4 highlights, out Vector4 limits) { float weight; @@ -4809,29 +4825,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo if (TEST_HDR()) { - var minNits = HDROutputSettings.main.minToneMapLuminance; - var maxNits = HDROutputSettings.main.maxToneMapLuminance; - var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = 0; - if (m_Tonemapping.mode.value == TonemappingMode.Neutral || - m_Tonemapping.mode.value == TonemappingMode.Custom || - m_Tonemapping.mode.value == TonemappingMode.External) - { - eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + - ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); - } - if (!m_Tonemapping.detectPaperWhite.value) - { - paperWhite = m_Tonemapping.paperWhite.value; - } - if (!m_Tonemapping.detectBrightnessLimits.value) - { - minNits = (int)m_Tonemapping.minNits.value; - maxNits = (int)m_Tonemapping.maxNits.value; - } - - passData.hdroutParameters = new Vector4(minNits, maxNits, paperWhite, 0); - passData.hdroutParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); + GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); } 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 a130e1c3019..bd70f8629d1 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 @@ -402,30 +402,7 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH if (outputsToHDR) { passData.blitMaterial = m_FinalBlitWithOETF; - - var minNits = HDROutputSettings.main.minToneMapLuminance; - var maxNits = HDROutputSettings.main.maxToneMapLuminance; - var paperWhite = HDROutputSettings.main.paperWhiteNits; - int eetfMode = 0; - if (m_Tonemapping.mode.value == TonemappingMode.Neutral || - m_Tonemapping.mode.value == TonemappingMode.Custom || - m_Tonemapping.mode.value == TonemappingMode.External) - { - eetfMode = (int)m_Tonemapping.neutralHDRRangeReductionMode.value + - ((m_Tonemapping.tonemapOnlyLuminance.value) ? 0 : 2); - } - if (!m_Tonemapping.detectPaperWhite.value) - { - paperWhite = m_Tonemapping.paperWhite.value; - } - if (!m_Tonemapping.detectBrightnessLimits.value) - { - minNits = (int)m_Tonemapping.minNits.value; - maxNits = (int)m_Tonemapping.maxNits.value; - } - - passData.hdrOutputParmeters = new Vector4(minNits, maxNits, paperWhite, 0); - + GetHDROutputParameters(m_Tonemapping, out passData.hdrOutputParmeters, out var unused); passData.uiTexture = builder.ReadTexture(uiTexture); } else From 01e4a94e8d1fa176258f84ca64cd3a6b373d4458 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 10:43:40 +0200 Subject: [PATCH 21/65] Rename test function --- .../HDRenderPipeline.PostProcess.cs | 26 ++++++++++++------- .../HDRenderPipeline.RenderGraph.cs | 6 ++--- .../RenderPipeline/HDRenderPipeline.cs | 11 +++++--- 3 files changed, 27 insertions(+), 16 deletions(-) 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 6720abff242..3d083bd81e4 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 @@ -3894,9 +3894,9 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } - if (TEST_HDR()) + if (HDROutputIsActive()) { - if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { passData.builderCS.EnableKeyword("HDR_OUTPUT_SCRGB"); } @@ -4422,9 +4422,16 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle passData.uberPostCS.EnableKeyword("GAMMA2_OUTPUT"); } - if (TEST_HDR()) + if (HDROutputIsActive()) { - passData.uberPostCS.EnableKeyword("HDR_OUTPUT_REC2020"); + 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; @@ -4806,7 +4813,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.viewportSize = postProcessViewportSize; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !TEST_HDR(); // TODO: Investigate how to make grain work with HDR. + 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 @@ -4815,7 +4822,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.filmGrainResponse = m_FilmGrain.response.value; // Dithering - passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !TEST_HDR(); + passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(); passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); @@ -4823,7 +4830,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.destination = builder.WriteTexture(finalRT); passData.uiBuffer = builder.ReadTexture(uiBuffer); - if (TEST_HDR()) + if (HDROutputIsActive()) { GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); } @@ -4916,8 +4923,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); - bool processHDR = TEST_HDR() && HDUtils.PostProcessIsFinalPass(data.hdCamera); - // TODO: THIS IS ALL BAD, NEED TO MOVE AND MOST IMPORTANTLY AVOID CAPTURE. + bool processHDR = HDROutputIsActive() && HDUtils.PostProcessIsFinalPass(data.hdCamera); if (processHDR) { if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) @@ -4959,7 +4965,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.EnableKeyword("APPLY_AFTER_POST"); finalPassMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); } - else if (!TEST_HDR() && data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + 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 bd70f8629d1..88e2127a6cc 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 @@ -305,7 +305,7 @@ void RecordRenderGraph(RenderRequest renderRequest, for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, TEST_HDR()); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive()); } if (aovRequest.isValid) @@ -883,7 +883,7 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, TextureHandle depthBuffer) { var output = renderGraph.defaultResources.blackTextureXR; - if (TEST_HDR() && SupportedRenderingFeatures.active.rendersUIOverlay) + if (HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay) { using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { @@ -2059,7 +2059,7 @@ class RenderScreenSpaceOverlayData void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) { - if (!TEST_HDR() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) + if (!HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) { using (var builder = renderGraph.AddRenderPass("Screen Space Overlay UI", out var passData)) { 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 640bd13bb2a..e68c28822e5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,8 +199,7 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } - // TODO_FCC: THIS IS NEEDED FOR TESTING, REPLACE WITH HDROutputSettings.main.active LATER - static bool TEST_HDR() + static bool HDROutputIsActive() { if (HDROutputSettings.main.available) { @@ -209,7 +208,7 @@ static bool TEST_HDR() if (HDROutputSettings.main.available && SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) { - HDROutputSettings.main.automaticHDRTonemapping = false; + // HDROutputSettings.main.automaticHDRTonemapping = false; var minNits = HDROutputSettings.main.minToneMapLuminance; var maxNits = HDROutputSettings.main.maxToneMapLuminance; var gamut = HDROutputSettings.main.displayColorGamut; @@ -1789,6 +1788,12 @@ ref _cullingResults using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.HDRenderPipelineAllRenderRequest))) { + // Make sure HDR auto tonemap is off + if (HDROutputSettings.main.active) + { + HDROutputSettings.main.automaticHDRTonemapping = false; + } + // Warm up the RTHandle system so that it gets init to the maximum resolution available (avoiding to call multiple resizes // that can lead to high memory spike as the memory release is delayed while the creation is immediate). { From acc3428f1543510e66a74109cac5c4c7e1a04bae Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 11:41:10 +0200 Subject: [PATCH 22/65] Small cleanup --- .../Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs | 1 - .../Editor/RenderPipeline/HDRenderPipelineUI.cs | 1 - .../Settings/SerializedRenderPipelineSettings.cs | 2 -- .../Runtime/PostProcessing/Shaders/FinalPass.shader | 2 -- .../Runtime/PostProcessing/Shaders/LutBuilder3D.compute | 2 -- .../Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs | 1 - .../RenderPipeline/Settings/RenderPipelineSettings.cs | 5 ----- 7 files changed, 14 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs index 32827a02aa4..e31fed264e0 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs @@ -153,7 +153,6 @@ public class Styles public static readonly GUIContent rayTracingMSAAUnsupported = EditorGUIUtility.TrTextContent("When Ray tracing is enabled in asset, MSAA is not supported. Please refer to the documentation."); public static readonly GUIContent maximumLODLevel = EditorGUIUtility.TrTextContent("Maximum LOD Level"); public static readonly GUIContent LODBias = EditorGUIUtility.TrTextContent("LOD Bias"); - public static readonly GUIContent UILayer = EditorGUIUtility.TrTextContent("UI Layer", "TODO_FCC ADD BETTER TOOLTIP. Layer used by UI elements. UI need to use this layer to be handled properly with HDR Output."); public static readonly GUIContent supportRuntimeDebugDisplayContentLabel = EditorGUIUtility.TrTextContent("Runtime Debug Shaders", "When disabled, all debug display shader variants are removed when you build for the Unity Player. This decreases build time, but prevents the use of Rendering Debugger in Player builds."); public static readonly GUIContent supportProbeVolumeContent = EditorGUIUtility.TrTextContent("Enable", "When enabled, HDRP allocates Shader variants and memory for probe volume based GI. This allows you to use probe volumes in your Unity Project."); public static readonly GUIContent probeVolumeMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "Determines the width and height of the textures used to store GI data from probes. Note that the textures also have a fixed depth dimension."); diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index b2de35b52f6..61e4c1213b7 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -865,7 +865,6 @@ static void Drawer_SectionRenderingUnsorted(SerializedHDRenderPipelineAsset seri --EditorGUI.indentLevel; } - EditorGUILayout.PropertyField(serialized.renderPipelineSettings.uiLayer, Styles.UILayer); EditorGUILayout.PropertyField(serialized.renderPipelineSettings.supportRayTracing, Styles.supportRaytracing); using (new EditorGUI.DisabledScope(!serialized.renderPipelineSettings.supportRayTracing.boolValue)) { 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 cd3aeb19006..0816109e943 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 @@ -53,7 +53,6 @@ class SerializedRenderPipelineSettings internal SerializedProperty supportProbeVolume; internal SerializedProperty probeVolumeTextureSize; internal SerializedProperty probeVolumeSHBands; - public SerializedProperty uiLayer; public SerializedGlobalLightLoopSettings lightLoopSettings; public SerializedHDShadowInitParameters hdShadowInitParams; @@ -110,7 +109,6 @@ public SerializedRenderPipelineSettings(SerializedProperty root) supportProbeVolume = root.Find((RenderPipelineSettings s) => s.supportProbeVolume); probeVolumeTextureSize = root.Find((RenderPipelineSettings s) => s.probeVolumeMemoryBudget); probeVolumeSHBands = root.Find((RenderPipelineSettings s) => s.probeVolumeSHBands); - uiLayer = root.Find((RenderPipelineSettings s) => s.uiLayer); supportRayTracing = root.Find((RenderPipelineSettings s) => s.supportRayTracing); supportedRayTracingMode = root.Find((RenderPipelineSettings s) => s.supportedRayTracingMode); 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 ad27a5ed564..ce10a9581a6 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 @@ -47,7 +47,6 @@ Shader "Hidden/HDRP/FinalPass" float4 _ViewPortSize; float _KeepAlpha; - // TODO_FCC: HDR RELATED STUFF, WILL NEED TO MOVE TO WHATEVER BUILDS THE LUT. float4 _HDROutputParams; float4 _HDROutputParams2; #define _MinNits _HDROutputParams.x @@ -126,7 +125,6 @@ Shader "Hidden/HDRP/FinalPass" #endif //FXAA // Saturate is only needed for dither or grain to work. Otherwise we don't saturate because output might be HDR - // TODO_FCC: How to handle this in HDR Output? #if defined(GRAIN) || defined(DITHER) outColor = saturate(outColor); #endif 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 4c7bbe76da1..80ecd9753e3 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 @@ -54,7 +54,6 @@ CBUFFER_START(cb0) float4 _ShoSegmentA; float4 _ShoSegmentB; - // TODO_FCC: HDR RELATED STUFF, WILL NEED TO MOVE TO WHATEVER BUILDS THE LUT. float4 _HDROutputParams; float4 _HDROutputParams2; #define _MinNits _HDROutputParams.x @@ -293,7 +292,6 @@ void KBuild(uint3 dispatchThreadId : SV_DispatchThreadID) gradedColor = NeutralColorGrade(gradedColor); } - // TODO_FCC: Better handling of tonemapping. #ifdef HDR_OUTPUT gradedColor = ProcessColorForHDR(gradedColor); #else 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 88e2127a6cc..a0182a54bcf 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 @@ -197,7 +197,6 @@ void RecordRenderGraph(RenderRequest renderRequest, colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedNormalBuffer, vtFeedbackBuffer, currentColorPyramid, volumetricLighting, rayCountTexture, m_SkyManager.GetSkyReflection(hdCamera), gpuLightListOutput, ref prepassOutput, shadowResult, cullingResults, customPassCullingResults, aovRequest, aovCustomPassBuffers); - // TODO_FCC: TMP, MOVE FROM HERE. ALSO CONSIDER THAT FOR V1 WE MIGHT WANT TO ONLY SEPARATE OVERLAYS? uiBuffer = RenderTransparentUI(m_RenderGraph, hdCamera, prepassOutput.depthBuffer); if (NeedMotionVectorForTransparent(hdCamera.frameSettings)) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs index aa8af83c451..85973fb3b1b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs @@ -123,8 +123,6 @@ internal static RenderPipelineSettings NewDefault() supportProbeVolume = false, probeVolumeMemoryBudget = ProbeVolumeTextureMemoryBudget.MemoryBudgetMedium, probeVolumeSHBands = ProbeVolumeSHBands.SphericalHarmonicsL1, - - uiLayer = 1 << 5, // 5 by default is UI }; return settings; } @@ -373,9 +371,6 @@ public bool supportRuntimeDebugDisplay /// Global lighting quality settings. public GlobalLightingQualitySettings lightingQualitySettings; - //// TODO_FCC: Change to Global settings? - public LayerMask uiLayer; - #pragma warning disable 618 // Type or member is obsolete [Obsolete("For data migration")] internal bool m_ObsoleteincreaseSssSampleCount; From 3f84e43451247e9569f8ab42078d9089421c0fd3 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 12:21:29 +0200 Subject: [PATCH 23/65] Fix issue with scRGB not being properly set. --- .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3d083bd81e4..bd20ba23935 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 @@ -4000,7 +4000,7 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out maxNits = (int)tonemappingComponent.maxNits.value; } - hdrOutputParameters1 = new Vector4(minNits, maxNits, paperWhite, 0); + hdrOutputParameters1 = new Vector4(minNits, maxNits, paperWhite, HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : 2); hdrOutputParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); } From f9f98baf52e7f51804150097fec7dede0f9703a9 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 19:24:47 +0200 Subject: [PATCH 24/65] Add some skeleton for debug (still not done) - fix issues in scene view. --- .../ShaderLibrary/HDROutput.hlsl | 22 +- .../Runtime/Debug/DebugDisplay.cs | 44 ++- .../Runtime/Debug/DebugHDR.shader | 342 ++++++++++++++++++ .../Runtime/Debug/DebugHDR.shader.meta | 10 + .../Runtime/Debug/LightingDebug.cs | 12 + .../Shaders/DebugHDRxyMapping.compute | 43 +++ .../Shaders/DebugHDRxyMapping.compute.meta | 8 + .../RenderPipeline/HDRenderPipeline.Debug.cs | 65 ++++ .../HDRenderPipeline.PostProcess.cs | 19 +- .../HDRenderPipeline.RenderGraph.cs | 8 +- .../RenderPipeline/HDRenderPipeline.cs | 25 +- .../HDRenderPipelineRuntimeResources.cs | 2 + .../HDRenderPipelineRuntimeResources.asset | 3 +- 13 files changed, 579 insertions(+), 24 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute create mode 100644 com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 33ed09e5233..4cec9ef7c1e 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -26,7 +26,7 @@ // -------------------------------- // Perceptual Quantizer (PQ) / ST 2084 // -------------------------------- -// This section has a bunch of options, a few of them are accurate a bunch are not. + #define MAX_PQ_VALUE 10000 // 10k nits is the maximum supported by the standard. #define PQ_N (2610.0f / 4096.0f / 4.0f) @@ -227,6 +227,26 @@ 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) { 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 8890c1978d6..519d2a10cbb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -289,6 +289,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; @@ -546,6 +547,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. /// @@ -739,12 +749,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. /// @@ -1151,6 +1171,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." }; @@ -1341,8 +1363,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..7c488c2d4fe --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -0,0 +1,342 @@ +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 + + + ///// TODO_FCC: + /// Check if inside gamut. + + // Contains the scene color pre-post processing + TEXTURE2D_X(_DebugFullScreenTexture); + + // Tonemap related + TEXTURE3D(_LogLut3D); + SAMPLER(sampler_LogLut3D); + + float4 _HDRDebugParams; + float4 _LogLut3D_Params; // x: 1 / lut_size, y: lut_size - 1, z: contribution, w: unused + // Custom tonemapping settings + float4 _CustomToneCurve; + float4 _ToeSegmentA; + float4 _ToeSegmentB; + float4 _MidSegmentA; + 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 _IsRec709 (int)(_HDROutputParams.w == 1) + + #define _TonemapType _HDRDebugParams.w + + 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 Tonemap(float3 colorLinear) + { + if(_TonemapType == TONEMAPPINGMODE_NEUTRAL) + { + colorLinear = NeutralTonemap(colorLinear); + } + if (_TonemapType == TONEMAPPINGMODE_ACES) + { + // Note: input is actually ACEScg (AP1 w/ linear encoding) + float3 aces = ACEScg_to_ACES(colorLinear); + colorLinear = AcesTonemap(aces); + } + if (_TonemapType == TONEMAPPINGMODE_CUSTOM) // Custom + { + colorLinear = CustomTonemap(colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy); + } + if (_TonemapType == TONEMAPPINGMODE_EXTERNAL) // External + { + float3 colorLutSpace = saturate(LinearToLogC(colorLinear)); + float3 colorLut = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); + colorLinear = lerp(colorLinear, colorLut, _LogLut3D_Params.z); + } + + return colorLinear; + } + + 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); + } + + float3 xyYtoXYZ(float3 xyY) + { + float x = xyY[0]; + float y = xyY[1]; + float Y = xyY[2]; + + float X = (Y / y) * x; + float Z = (Y / y) * (1.0 - x - y); + + return float3(X, Y, Z); + } + + float2 RGBtoxy(float3 rgb) + { + float3 XYZ = 0; + if (_IsRec709) + { + XYZ = RotateRec709ToXYZ(rgb); + } + else + { + XYZ = RotateRec2020ToXYZ(rgb); + } + return XYZ.xy / (dot(XYZ, 1)); + } + + 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); + } + + float3 FragColorGamut(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; + + 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; + int gamutPiPSize = _ScreenSize.x / 3.0f; + float lineThickness = 0.002; + + 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; + + if (PointInTriangle(uv, r_2020, g_2020, b_2020)) + { + linearRGB = uvToGamut(uv); + + color.rgb = linearRGB * _PaperWhite; + } + + color.rgb = color.rgb * (1.0f - lineColor.a) + lineColor.rgb; + } + else + { + float2 xy = RGBtoxy(color.rgb); + if (PointInTriangle(xy, r_709, g_709, b_709)) + { + return float3(0, 1, 0) * _PaperWhite; + } + else if (PointInTriangle(xy, r_2020, g_2020, b_2020)) + { + return float3(1, 0, 0) * _PaperWhite; + } + } + + return color; + // uv.y = 1.0f - uv.y; + //uv.x = 1.0f - uv.x; + + } + + + + float3 FragHistogram(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; + } + + StructuredBuffer _FullImageHistogram; + + float3 FragImageHistogram(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; + } + + 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 FragMetering + ENDHLSL + } + + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + + HLSLPROGRAM + #pragma fragment FragHistogram + ENDHLSL + } + + Pass + { + ZWrite Off + ZTest Always + Blend Off + Cull Off + HLSLPROGRAM + #pragma fragment FragImageHistogram + 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..d6f73c8746f 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,14 @@ public enum ExposureDebugMode MeteringWeighted, } + [GenerateHLSL] + public enum HDRDebugMode + { + None, + GamutView, + GamutClip, + TonemappedLuminance, + } /// /// Probe Volume Debug Modes. @@ -325,6 +333,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/PostProcessing/Shaders/DebugHDRxyMapping.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute new file mode 100644 index 00000000000..3aa5a325776 --- /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" + + +#pragma kernel KCIExyGen +#define GROUP_SIZE_X 8 +#define GROUP_SIZE_Y 8 + + +RWStructuredBuffer _xyBuffer; +TEXTURE2D_X(_SourceTexture); + +float4 _HDROutputParams; +#define _MinNits _HDROutputParams.x +#define _MaxNits _HDROutputParams.y +#define _PaperWhite _HDROutputParams.z +#define _IsRec709 (int)(_HDROutputParams.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; + + +} 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/RenderPipeline/HDRenderPipeline.Debug.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs index 9688eb67a82..b8c06194268 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,51 @@ void GenerateDebugImageHistogram(RenderGraph renderGraph, HDCamera hdCamera, Tex } } + class DebugHDRData + { + public LightingDebugSettings lightingDebugSettings; + public Material debugHDRMaterial; + public Vector4 hdrOutputParams; + public Vector4 hdrOutputParams2; + public Vector4 hdrDebugParams; + + public TextureHandle colorBuffer; + public TextureHandle debugFullScreenTexture; + public TextureHandle output; + } + + TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) + { + //if (!HDROutputIsActive()) return colorBuffer; + + using (var builder = renderGraph.AddRenderPass("Debug HDR", out var passData)) + { + passData.debugHDRMaterial = m_DebugHDROutput; + passData.lightingDebugSettings = m_CurrentDebugDisplaySettings.data.lightingDebugSettings; + if (HDROutputIsActive(hdCamera)) + GetHDROutputParameters(hdCamera.volumeStack.GetComponent(), out passData.hdrOutputParams, out passData.hdrOutputParams2); + else + passData.hdrOutputParams.z = 1.0f; + + 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" })); + + + builder.SetRenderFunc( + (DebugHDRData data, RenderGraphContext ctx) => + { + data.debugHDRMaterial.SetTexture(HDShaderIDs._DebugFullScreenTexture, data.debugFullScreenTexture); + data.debugHDRMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdrOutputParams); + data.debugHDRMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdrOutputParams2); + HDUtils.DrawFullScreen(ctx.cmd, data.debugHDRMaterial, data.output, null, 0); + }); + + return passData.output; + } + } + class DebugExposureData { public LightingDebugSettings lightingDebugSettings; @@ -1031,6 +1084,9 @@ TextureHandle RenderDebug(RenderGraph renderGraph, if (NeedExposureDebugMode(m_CurrentDebugDisplaySettings)) output = RenderExposureDebug(renderGraph, hdCamera, colorBuffer); + if (NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) + output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer); + if (NeedColorPickerDebug(m_CurrentDebugDisplaySettings)) output = ResolveColorPickerDebug(renderGraph, colorPickerDebugTexture, hdCamera, colorFormat); @@ -1275,6 +1331,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 bd20ba23935..c86686cbc2f 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 @@ -3869,7 +3869,7 @@ class ColorGradingPassData public TextureHandle logLut; } - void PrepareColorGradingParameters(ColorGradingPassData passData) + void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camera) { passData.tonemappingMode = m_TonemappingFS ? m_Tonemapping.mode.value : TonemappingMode.None; @@ -3894,7 +3894,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData) passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } - if (HDROutputIsActive()) + if (HDROutputIsActive(camera)) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -4115,7 +4115,7 @@ TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) enableRandomWrite = true }); - PrepareColorGradingParameters(passData); + PrepareColorGradingParameters(passData, hdCamera); passData.logLut = builder.WriteTexture(logLut); builder.SetRenderFunc( @@ -4422,7 +4422,7 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle passData.uberPostCS.EnableKeyword("GAMMA2_OUTPUT"); } - if (HDROutputIsActive()) + if (HDROutputIsActive(hdCamera)) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -4813,7 +4813,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.viewportSize = postProcessViewportSize; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !HDROutputIsActive(); // TODO: Investigate how to make grain work with HDR. + passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !HDROutputIsActive(hdCamera); // 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 @@ -4822,7 +4822,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.filmGrainResponse = m_FilmGrain.response.value; // Dithering - passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(); + passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(hdCamera); passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); @@ -4830,7 +4830,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.destination = builder.WriteTexture(finalRT); passData.uiBuffer = builder.ReadTexture(uiBuffer); - if (HDROutputIsActive()) + if (HDROutputIsActive(hdCamera)) { GetHDROutputParameters(m_Tonemapping, out passData.hdroutParameters, out passData.hdroutParameters2); } @@ -4923,7 +4923,8 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); - bool processHDR = HDROutputIsActive() && HDUtils.PostProcessIsFinalPass(data.hdCamera); + // TODO_FCC: IMPORTANT! FIX OR IT WILL CAPTURE. + bool processHDR = HDROutputIsActive(hdCamera) && HDUtils.PostProcessIsFinalPass(data.hdCamera); if (processHDR) { if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) @@ -4965,7 +4966,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.EnableKeyword("APPLY_AFTER_POST"); finalPassMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); } - else if (!HDROutputIsActive() && data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + else if (!HDROutputIsActive(data.hdCamera) && 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 a0182a54bcf..409bf86558e 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 @@ -270,11 +270,13 @@ void RecordRenderGraph(RenderRequest renderRequest, aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers); } + TextureHandle afterPostProcessBuffer = RenderAfterPostProcessObjects(m_RenderGraph, hdCamera, cullingResults, prepassOutput); TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, uiBuffer, afterPostProcessBuffer, cullingResults, hdCamera); GenerateDebugImageHistogram(m_RenderGraph, hdCamera, postProcessDest); PushFullScreenExposureDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); + PushFullScreenHDRDebugTexture(m_RenderGraph, postProcessDest, fullScreenDebugFormat); ResetCameraSizeForAfterPostProcess(m_RenderGraph, hdCamera, commandBuffer); @@ -304,7 +306,7 @@ void RecordRenderGraph(RenderRequest renderRequest, for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive()); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive(hdCamera)); } if (aovRequest.isValid) @@ -882,7 +884,7 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, TextureHandle depthBuffer) { var output = renderGraph.defaultResources.blackTextureXR; - if (HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay) + if (HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay) { using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { @@ -2058,7 +2060,7 @@ class RenderScreenSpaceOverlayData void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) { - if (!HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) + if (!HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) { using (var builder = renderGraph.AddRenderPass("Screen Space Overlay UI", out var passData)) { 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 e68c28822e5..b60a9bf2c7b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,7 +199,7 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } - static bool HDROutputIsActive() + static bool HDROutputIsActive(HDCamera camera) { if (HDROutputSettings.main.available) { @@ -225,7 +225,7 @@ static bool HDROutputIsActive() // Debug.Log("Display length more than 0"); //} // - return HDROutputSettings.main.active; + return HDROutputSettings.main.active && camera.camera.cameraType == CameraType.Game; } readonly SkyManager m_SkyManager = new SkyManager(); @@ -1788,12 +1788,6 @@ ref _cullingResults using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.HDRenderPipelineAllRenderRequest))) { - // Make sure HDR auto tonemap is off - if (HDROutputSettings.main.active) - { - HDROutputSettings.main.automaticHDRTonemapping = false; - } - // Warm up the RTHandle system so that it gets init to the maximum resolution available (avoiding to call multiple resizes // that can lead to high memory spike as the memory release is delayed while the creation is immediate). { @@ -1978,6 +1972,21 @@ AOVRequestData aovRequest // Updates RTHandle hdCamera.BeginRender(cmd); + // Make sure HDR auto tonemap is off + if (HDROutputSettings.main.active) + { + HDROutputSettings.main.automaticHDRTonemapping = false; + if (hdCamera.camera.cameraType != CameraType.Game) + { + HDROutputSettings.main.RequestHDRModeChange(false); + } + else + { + HDROutputSettings.main.RequestHDRModeChange(true); + } + } + + if (m_RayTracingSupported) { // This call need to happen once per camera 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 1cccb3112fc..16f55a33099 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")] 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 4427fe202b6..a82a31f5c92 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -20,6 +20,7 @@ MonoBehaviour: debugFullScreenPS: {fileID: 4800000, guid: e874aca2df8300a488258738c31f85cf, type: 3} debugColorPickerPS: {fileID: 4800000, guid: 8137b807709e178498f22ed710864bb0, type: 3} debugExposurePS: {fileID: 4800000, guid: 0ef322534f047a34c96d29419d56d17a, 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} @@ -164,8 +165,6 @@ MonoBehaviour: bilateralUpsampleCS: {fileID: 7200000, guid: 68e831c555284d741b985e05369f0e63, type: 3} temporalFilterCS: {fileID: 7200000, guid: 741979ff70f7bd6489fbcb464280ecff, type: 3} diffuseDenoiserCS: {fileID: 7200000, guid: b4ed2382141619f40af1f743a84ccaea, type: 3} - materials: - defaultUIMat: {fileID: 2100000, guid: 0b4a88fad3f0a6440a0434e38f80ebab, type: 2} textures: debugFontTex: {fileID: 2800000, guid: a3ad2df0e49aaa341a3b3a80f93b3f66, type: 3} colorGradient: {fileID: 2800000, guid: 4ea52e665573c1644bf05dd9b11fd2a4, type: 3} From c6474b9e15fafa4ae110c127b0a05a89864f7778 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 19:26:21 +0200 Subject: [PATCH 25/65] fix compile issue of the tmp setup --- .../Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute | 2 ++ 1 file changed, 2 insertions(+) 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 index 3aa5a325776..2e1d905ab0f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute @@ -1,6 +1,8 @@ #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 From 17069975ef70c2e563888c9b0c34fe3e8c763fe8 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 19:36:45 +0200 Subject: [PATCH 26/65] Revert turning off. --- .../RenderPipeline/HDRenderPipeline.cs | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) 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 b60a9bf2c7b..0c26febbe53 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -201,31 +201,7 @@ internal int GetMaxScreenSpaceShadows() static bool HDROutputIsActive(HDCamera camera) { - if (HDROutputSettings.main.available) - { - // Debug.Log("Available"); - } - - if (HDROutputSettings.main.available && SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) - { - // HDROutputSettings.main.automaticHDRTonemapping = false; - var minNits = HDROutputSettings.main.minToneMapLuminance; - var maxNits = HDROutputSettings.main.maxToneMapLuminance; - var gamut = HDROutputSettings.main.displayColorGamut; - var dst = HDROutputSettings.main.graphicsFormat; - - // Debug.Log($" min {minNits} max {maxNits} {gamut} {dst}"); - } - //if (SystemInfo.hdrDisplaySupportFlags.HasFlag(HDRDisplaySupportFlags.Supported)) - //{ - // Debug.Log("System info Available"); - //} - //if (HDROutputSettings.displays.Length > 0) - //{ - // Debug.Log("Display length more than 0"); - //} - // - return HDROutputSettings.main.active && camera.camera.cameraType == CameraType.Game; + return HDROutputSettings.main.active /*&& camera.camera.cameraType == CameraType.Game*/; } readonly SkyManager m_SkyManager = new SkyManager(); @@ -1976,14 +1952,6 @@ AOVRequestData aovRequest if (HDROutputSettings.main.active) { HDROutputSettings.main.automaticHDRTonemapping = false; - if (hdCamera.camera.cameraType != CameraType.Game) - { - HDROutputSettings.main.RequestHDRModeChange(false); - } - else - { - HDROutputSettings.main.RequestHDRModeChange(true); - } } From 0d20f89bbb246f3a264b62e9b238518a43c32644 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 20:12:20 +0200 Subject: [PATCH 27/65] Fix scene view being off. --- .../Runtime/Debug/DebugHDR.shader | 23 +++++++++---------- .../Shaders/CompositeWithUIAndOETF.shader | 14 +++++++---- .../Shaders/DebugHDRxyMapping.compute | 16 ++++++++----- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index 7c488c2d4fe..b662d19a904 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -224,6 +224,17 @@ Shader "Hidden/HDRP/DebugHDR" int gamutPiPSize = _ScreenSize.x / 3.0f; float lineThickness = 0.002; + float2 xy = RGBtoxy(color.rgb); + if (PointInTriangle(xy, r_709, g_709, b_709)) + { + color.rgb = (color.rgb * 0.7 + 0.3 * float3(0, _PaperWhite, 0)); + } + else if (PointInTriangle(xy, r_2020, g_2020, b_2020)) + { + color.rgb = (color.rgb * 0.7 + 0.3 * float3(_PaperWhite, 0, 0)); + } + + if (all(pos < gamutPiPSize)) { float2 uv = pos / gamutPiPSize; @@ -243,18 +254,6 @@ Shader "Hidden/HDRP/DebugHDR" color.rgb = color.rgb * (1.0f - lineColor.a) + lineColor.rgb; } - else - { - float2 xy = RGBtoxy(color.rgb); - if (PointInTriangle(xy, r_709, g_709, b_709)) - { - return float3(0, 1, 0) * _PaperWhite; - } - else if (PointInTriangle(xy, r_2020, g_2020, b_2020)) - { - return float3(1, 0, 0) * _PaperWhite; - } - } return color; // uv.y = 1.0f - uv.y; 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 index a9c40011463..fa7ba3b213e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -19,6 +19,7 @@ Shader "Hidden/HDRP/CompositeUI" CBUFFER_START(cb) float4 _HDROutputParams; + int _NeedsFlip; CBUFFER_END #define _MinNits _HDROutputParams.x @@ -53,19 +54,22 @@ Shader "Hidden/HDRP/CompositeUI" 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 - uv.y = 1.0f - uv.y; - - float4 outColor = SAMPLE_TEXTURE2D_X(_InputTexture, s_point_clamp_sampler, uv); + float4 outColor = LOAD_TEXTURE2D_X(_InputTexture, samplePos.xy); // Apply AfterPostProcess target #if APPLY_AFTER_POST - float4 afterPostColor = SAMPLE_TEXTURE2D_X_LOD(_AfterPostProcessTexture, s_point_clamp_sampler, uv, 0); + 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 = SAMPLE_TEXTURE2D_X_LOD(_UITexture, s_point_clamp_sampler, uv, 0); + float4 uiValue = LOAD_TEXTURE2D_X(_UITexture, samplePos.xy); outColor.rgb = SceneUIComposition(uiValue, outColor.rgb, _PaperWhite, _MaxNits); outColor.rgb = OETF(outColor.rgb); 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 index 2e1d905ab0f..b7cf571e394 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute @@ -13,11 +13,9 @@ RWStructuredBuffer _xyBuffer; TEXTURE2D_X(_SourceTexture); -float4 _HDROutputParams; -#define _MinNits _HDROutputParams.x -#define _MaxNits _HDROutputParams.y -#define _PaperWhite _HDROutputParams.z -#define _IsRec709 (int)(_HDROutputParams.w == 1) +float4 _HDRxyBufferDebugParams; +#define _SizePerDim _HDRxyBufferDebugParams.xy +#define _IsRec709 (int)(_HDRxyBufferDebugParams.w == 1) float2 RGBtoxy(float3 rgb) @@ -34,6 +32,12 @@ float2 RGBtoxy(float3 rgb) return XYZ.xy / (dot(XYZ, 1)); } +int xyToBufferEntry(float2 xy) +{ + // TODO: The gamuts don't stretch the full xy [0..1] stretch, so can normalize to optimize space. + return xy.x + _SizePerDim.x * xy.y; +} + [numthreads(GROUP_SIZE_X, GROUP_SIZE_Y, 1)] void KCIExyGen(uint groupIndex : SV_GroupIndex, uint3 dispatchThreadId : SV_DispatchThreadID) @@ -41,5 +45,5 @@ void KCIExyGen(uint groupIndex : SV_GroupIndex, UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); float3 rgbData = LOAD_TEXTURE2D_X(_SourceTexture, dispatchThreadId.xy).rgb; - + float2 xy = RGBtoxy(rgbData); } From 93f92f6ed6a9a948e773a2df56e47c3e37509efc Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 29 Sep 2021 23:05:43 +0200 Subject: [PATCH 28/65] Fix scene view. --- .../Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs | 1 + .../Runtime/RenderPipeline/HDRenderPipeline.cs | 2 +- .../Runtime/RenderPipeline/HDStringConstants.cs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) 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 409bf86558e..11775846097 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 @@ -420,6 +420,7 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH // We are in HDR mode so the final blit is different if (data.hdrOutputParmeters.x >= 0) { + data.blitMaterial.SetInt(HDShaderIDs._NeedsFlip, data.flip ? 1 : 0); propertyBlock.SetTexture(HDShaderIDs._UITexture, data.uiTexture); propertyBlock.SetTexture(HDShaderIDs._InputTexture, sourceTexture); 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 0c26febbe53..8e608a26b44 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -201,7 +201,7 @@ internal int GetMaxScreenSpaceShadows() static bool HDROutputIsActive(HDCamera camera) { - return HDROutputSettings.main.active /*&& camera.camera.cameraType == CameraType.Game*/; + return HDROutputSettings.main.active && camera.camera.cameraType == CameraType.Game; } readonly SkyManager m_SkyManager = new SkyManager(); 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 562617ec6e9..d30fd9acaa7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -935,6 +935,7 @@ static class HDShaderIDs 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"); From c69024925be2a1ad6c2802b2773b80a6125adf59 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Sep 2021 14:49:47 +0200 Subject: [PATCH 29/65] Gamut debug views --- .../Runtime/Debug/DebugHDR.shader | 79 ++++++++++++++---- .../Shaders/DebugHDRxyMapping.compute | 14 +--- .../Runtime/RenderPipeline/HDProfileId.cs | 1 + .../RenderPipeline/HDRenderPipeline.Debug.cs | 83 +++++++++++++++++-- .../HDRenderPipeline.PostProcess.cs | 1 + .../HDRenderPipeline.RenderGraph.cs | 3 +- .../HDRenderPipelineRuntimeResources.cs | 2 + .../RenderPipeline/HDStringConstants.cs | 3 + .../HDRenderPipelineRuntimeResources.asset | 1 + 9 files changed, 156 insertions(+), 31 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index b662d19a904..e18c3d337a8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -49,6 +49,8 @@ Shader "Hidden/HDRP/DebugHDR" #define _TonemapType _HDRDebugParams.w + TEXTURE2D_X(_xyBuffer); + struct Attributes { uint vertexID : SV_VertexID; @@ -206,12 +208,20 @@ Shader "Hidden/HDRP/DebugHDR" return (bar.x >= 0 && bar.x <= 1 && bar.y >= 0 && bar.y <= 1 && (bar.x + bar.y) <= 1); } - float3 FragColorGamut(Varyings input) : SV_Target + 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); @@ -221,20 +231,30 @@ Shader "Hidden/HDRP/DebugHDR" float2 b_709 = float2(0.15, 0.06); float2 pos = input.positionCS.xy; - int gamutPiPSize = _ScreenSize.x / 3.0f; float lineThickness = 0.002; float2 xy = RGBtoxy(color.rgb); - if (PointInTriangle(xy, r_709, g_709, b_709)) - { - color.rgb = (color.rgb * 0.7 + 0.3 * float3(0, _PaperWhite, 0)); - } - else if (PointInTriangle(xy, r_2020, g_2020, b_2020)) + + 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) { - color.rgb = (color.rgb * 0.7 + 0.3 * float3(_PaperWhite, 0, 0)); + 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; @@ -244,23 +264,52 @@ Shader "Hidden/HDRP/DebugHDR" 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); - color.rgb = linearRGB * _PaperWhite; + 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; + } } - color.rgb = color.rgb * (1.0f - lineColor.a) + lineColor.rgb; + gamutColor.rgb = gamutColor.rgb * (1.0f - lineColor.a) + lineColor.rgb; } + color.rgb = gamutColor.rgb * gamutColor.a + color.rgb * (1 - gamutColor.a); + return color; - // uv.y = 1.0f - uv.y; - //uv.x = 1.0f - uv.x; + } + float3 FragColorGamut(Varyings input) : SV_Target + { + return CommonFrag(input, false); } + float3 FragColorGamutClip(Varyings input) : SV_Target + { + return CommonFrag(input, true); + } float3 FragHistogram(Varyings input) : SV_Target @@ -309,7 +358,7 @@ Shader "Hidden/HDRP/DebugHDR" Cull Off HLSLPROGRAM - #pragma fragment FragMetering + #pragma fragment FragColorGamutClip ENDHLSL } 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 index b7cf571e394..f821f53323e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/DebugHDRxyMapping.compute @@ -4,20 +4,17 @@ #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 - -RWStructuredBuffer _xyBuffer; 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; @@ -32,11 +29,6 @@ float2 RGBtoxy(float3 rgb) return XYZ.xy / (dot(XYZ, 1)); } -int xyToBufferEntry(float2 xy) -{ - // TODO: The gamuts don't stretch the full xy [0..1] stretch, so can normalize to optimize space. - return xy.x + _SizePerDim.x * xy.y; -} [numthreads(GROUP_SIZE_X, GROUP_SIZE_Y, 1)] void KCIExyGen(uint groupIndex : SV_GroupIndex, @@ -45,5 +37,7 @@ void KCIExyGen(uint groupIndex : SV_GroupIndex, UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); float3 rgbData = LOAD_TEXTURE2D_X(_SourceTexture, dispatchThreadId.xy).rgb; - float2 xy = RGBtoxy(rgbData); + float2 xy = (RGBtoxy(rgbData)); + + _xyBuffer[COORD_TEXTURE2D_X(xy * _SizePerDim)] = 1; } 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 b7595b68176..da7993dfd3d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -226,6 +226,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 b8c06194268..be6e3a83976 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 @@ -879,6 +879,66 @@ 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(hdCamera)) + { + 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; @@ -886,16 +946,18 @@ class DebugHDRData 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 RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle xyBuff) { - //if (!HDROutputIsActive()) return colorBuffer; - using (var builder = renderGraph.AddRenderPass("Debug HDR", out var passData)) { passData.debugHDRMaterial = m_DebugHDROutput; @@ -905,19 +967,30 @@ TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, Texture else passData.hdrOutputParams.z = 1.0f; + passData.debugPass = 0; + if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.hdrDebugMode == HDRDebugMode.GamutClip) + passData.debugPass = 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" })); + // TODO: Put here tonemap type. + 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); - HDUtils.DrawFullScreen(ctx.cmd, data.debugHDRMaterial, data.output, null, 0); + data.debugHDRMaterial.SetVector(HDShaderIDs._HDRDebugParams, data.hdrDebugParams); + + HDUtils.DrawFullScreen(ctx.cmd, data.debugHDRMaterial, data.output, null, data.debugPass); }); return passData.output; @@ -1085,7 +1158,7 @@ TextureHandle RenderDebug(RenderGraph renderGraph, output = RenderExposureDebug(renderGraph, hdCamera, colorBuffer); if (NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) - output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer); + output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer, rayCountTexture); if (NeedColorPickerDebug(m_CurrentDebugDisplaySettings)) output = ResolveColorPickerDebug(renderGraph, colorPickerDebugTexture, hdCamera, colorFormat); 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 c86686cbc2f..19a017fa47e 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 @@ -32,6 +32,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]; 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 11775846097..6382c22e5f2 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 @@ -274,6 +274,7 @@ void RecordRenderGraph(RenderRequest renderRequest, 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); @@ -296,7 +297,7 @@ void RecordRenderGraph(RenderRequest renderRequest, prepassOutput.resolvedDepthBuffer, prepassOutput.depthPyramidTexture, colorPickerTexture, - rayCountTexture, + xyMapping, // TODO_FCC REVERT, HERE TO QUICK TEST. gpuLightListOutput, shadowResult, cullingResults, 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 16f55a33099..f5e86873b07 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -257,6 +257,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")] 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 d30fd9acaa7..1b72b16b9c3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -778,6 +778,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"); 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 a82a31f5c92..25b2d4264b2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -119,6 +119,7 @@ MonoBehaviour: histogramExposureCS: {fileID: 7200000, guid: 222da48299136f34b8e3fb75ae9f8ac7, type: 3} applyExposureCS: {fileID: 7200000, guid: 1a6fea1dc099b984d8f2b27d504dc096, 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, type: 3} From 5563e98562860e66c0d312db268dc2923307bef9 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 30 Sep 2021 17:41:11 +0200 Subject: [PATCH 30/65] Fix aces grading being capped out. --- .../ShaderLibrary/HDROutput.hlsl | 4 ++-- .../Runtime/PostProcessing/Shaders/LutBuilder3D.compute | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 4cec9ef7c1e..96074fea11e 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -491,9 +491,9 @@ float3 HDRMappingFromRec709(float3 Rec709Input, float paperWhite, float minNits, } -float3 HDRMappingFromRec709_ACES(float3 Rec709Input, float hdrBoost, int reductionMode, bool skipOETF = false) +float3 HDRMappingACES(float3 aces, float hdrBoost, int reductionMode, bool skipOETF = false) { - float3 aces = unity_to_ACES(Rec709Input * hdrBoost * 0.01f); + aces = (aces * hdrBoost * 0.01f); float3 oces = RRT(aces); float3 AP1ODT = 0; 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 80ecd9753e3..3a684e5ab75 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 @@ -95,7 +95,7 @@ float3 ColorGrade(float3 colorLutSpace) colorLinear = LMSToLinear(colorLMS); // Do contrast in log after white balance - #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) + #if defined(TONEMAPPING_ACES) float3 colorLog = ACES_to_ACEScc(unity_to_ACES(colorLinear)); #else float3 colorLog = LinearToLogC(colorLinear); @@ -103,7 +103,7 @@ float3 ColorGrade(float3 colorLutSpace) colorLog = (colorLog - ACEScc_MIDGRAY) * _HueSatCon.z + ACEScc_MIDGRAY; - #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) + #if defined(TONEMAPPING_ACES) colorLinear = ACES_to_ACEScg(ACEScc_to_ACES(colorLog)); #else colorLinear = LogCToLinear(colorLog); @@ -213,7 +213,7 @@ float3 NeutralColorGrade(float3 colorLutSpace) float3 colorLinear = LogCToLinear(colorLutSpace); #endif - #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) + #if defined(TONEMAPPING_ACES) colorLinear = ACES_to_ACEScg(unity_to_ACES(colorLinear)); #endif @@ -253,7 +253,7 @@ float3 ProcessColorForHDR(float3 gradedColor) #ifdef HDR_OUTPUT #if TONEMAPPING_ACES - return HDRMappingFromRec709_ACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); + return HDRMappingACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); #else return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); #endif From 679fe2d03a062ae9087ce851772bfc7744cbe99c Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 1 Oct 2021 10:29:35 +0200 Subject: [PATCH 31/65] Finalize debug view --- .../Runtime/Debug/DebugHDR.shader | 74 ++++--------------- .../Runtime/Debug/LightingDebug.cs | 9 ++- .../RenderPipeline/HDRenderPipeline.Debug.cs | 5 +- 3 files changed, 23 insertions(+), 65 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index e18c3d337a8..8f127ccd5b2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -29,15 +29,6 @@ Shader "Hidden/HDRP/DebugHDR" SAMPLER(sampler_LogLut3D); float4 _HDRDebugParams; - float4 _LogLut3D_Params; // x: 1 / lut_size, y: lut_size - 1, z: contribution, w: unused - // Custom tonemapping settings - float4 _CustomToneCurve; - float4 _ToeSegmentA; - float4 _ToeSegmentB; - float4 _MidSegmentA; - float4 _MidSegmentB; - float4 _ShoSegmentA; - float4 _ShoSegmentB; float4 _HDROutputParams; float4 _HDROutputParams2; @@ -75,32 +66,6 @@ Shader "Hidden/HDRP/DebugHDR" return output; } - float3 Tonemap(float3 colorLinear) - { - if(_TonemapType == TONEMAPPINGMODE_NEUTRAL) - { - colorLinear = NeutralTonemap(colorLinear); - } - if (_TonemapType == TONEMAPPINGMODE_ACES) - { - // Note: input is actually ACEScg (AP1 w/ linear encoding) - float3 aces = ACEScg_to_ACES(colorLinear); - colorLinear = AcesTonemap(aces); - } - if (_TonemapType == TONEMAPPINGMODE_CUSTOM) // Custom - { - colorLinear = CustomTonemap(colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy); - } - if (_TonemapType == TONEMAPPINGMODE_EXTERNAL) // External - { - float3 colorLutSpace = saturate(LinearToLogC(colorLinear)); - float3 colorLut = ApplyLut3D(TEXTURE3D_ARGS(_LogLut3D, sampler_LogLut3D), colorLutSpace, _LogLut3D_Params.xy); - colorLinear = lerp(colorLinear, colorLut, _LogLut3D_Params.z); - } - - return colorLinear; - } - float3 ToHeat(float value) { float3 r = value * 2.1f - float3(1.8f, 1.14f, 0.3f); @@ -312,25 +277,26 @@ Shader "Hidden/HDRP/DebugHDR" } - float3 FragHistogram(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; - } - StructuredBuffer _FullImageHistogram; - float3 FragImageHistogram(Varyings input) : SV_Target + 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; - return color; + 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 @@ -370,21 +336,9 @@ Shader "Hidden/HDRP/DebugHDR" Cull Off HLSLPROGRAM - #pragma fragment FragHistogram - ENDHLSL - } - - Pass - { - ZWrite Off - ZTest Always - Blend Off - Cull Off - HLSLPROGRAM - #pragma fragment FragImageHistogram + #pragma fragment FragNits ENDHLSL } - } Fallback Off } 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 d6f73c8746f..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,13 +189,20 @@ 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, - TonemappedLuminance, + /// Show in colors between yellow and red any value that is above the paper white value. Luminance otherwise. + ValuesAbovePaperWhite, } /// 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 be6e3a83976..609708b7330 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 @@ -967,10 +967,7 @@ TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, Texture else passData.hdrOutputParams.z = 1.0f; - passData.debugPass = 0; - if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.hdrDebugMode == HDRDebugMode.GamutClip) - passData.debugPass = 1; - + 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) From 61b5d81522d4b24d077e9676ba1987d0c4c89584 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 1 Oct 2021 10:31:14 +0200 Subject: [PATCH 32/65] Small cleanup --- .../Runtime/Debug/DebugHDR.shader | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index 8f127ccd5b2..8feb4b6f199 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -17,17 +17,8 @@ Shader "Hidden/HDRP/DebugHDR" #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch - - ///// TODO_FCC: - /// Check if inside gamut. - - // Contains the scene color pre-post processing TEXTURE2D_X(_DebugFullScreenTexture); - // Tonemap related - TEXTURE3D(_LogLut3D); - SAMPLER(sampler_LogLut3D); - float4 _HDRDebugParams; float4 _HDROutputParams; @@ -277,8 +268,6 @@ Shader "Hidden/HDRP/DebugHDR" } - StructuredBuffer _FullImageHistogram; - float3 FragNits(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); From 7bb6fb586779142417a2c1529991cf350750e443 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 1 Oct 2021 13:54:02 +0200 Subject: [PATCH 33/65] Perform grading in ACEScg by default --- .../ShaderLibrary/ACES.hlsl | 6 ++ .../ShaderLibrary/HDROutput.hlsl | 6 +- .../Settings/HDGlobalSettingsWindow.Skin.cs | 1 + .../Settings/HDGlobalSettingsWindow.cs | 1 + ...erializedHDRenderPipelineGlobalSettings.cs | 2 + .../Shaders/LutBuilder3D.compute | 76 ++++++++++++++----- .../HDRenderPipeline.PostProcess.cs | 5 ++ ...Pipeline.PostProcess.cs.preformat.bak.meta | 7 ++ .../HDRenderPipelineGlobalSettings.cs | 9 +++ 9 files changed, 93 insertions(+), 20 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index a4870622a3f..6fad6bc2e82 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 // diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 96074fea11e..ca41bbf09e0 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -472,11 +472,13 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mod // 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) +float3 HDRMappingFromRec2020(float3 Rec2020Input, float paperWhite, float minNits, float maxNits, int reductionMode, bool skipOETF = false) { float3 outputSpaceInput = RotateRec2020ToOutputSpace(Rec2020Input); - float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode); + + if (skipOETF) return reducedHDR; + return OETF(reducedHDR); } 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/Runtime/PostProcessing/Shaders/LutBuilder3D.compute b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LutBuilder3D.compute index 3a684e5ab75..290dc23d2bb 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 @@ -2,6 +2,8 @@ #pragma multi_compile TONEMAPPING_NONE TONEMAPPING_NEUTRAL TONEMAPPING_ACES TONEMAPPING_CUSTOM TONEMAPPING_EXTERNAL #pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB +#pragma multi_compile_local GRADE_IN_SRGB GRADE_IN_ACESCG + #pragma kernel KBuild #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" @@ -65,7 +67,7 @@ CBUFFER_END float GetLuminance(float3 colorLinear) { - #if defined(TONEMAPPING_ACES) && !defined(HDR_OUTPUT) + #if defined(TONEMAPPING_ACES) || defined(GRADE_IN_ACESCG) return AcesLuminance(colorLinear); #else return Luminance(colorLinear); @@ -78,6 +80,54 @@ 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) { @@ -95,19 +145,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; @@ -199,7 +241,8 @@ 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 @@ -213,11 +256,7 @@ float3 NeutralColorGrade(float3 colorLutSpace) 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) @@ -253,9 +292,10 @@ float3 ProcessColorForHDR(float3 gradedColor) #ifdef HDR_OUTPUT #if TONEMAPPING_ACES + gradedColor = ACEScg_to_ACES(gradedColor); return HDRMappingACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); #else - return HDRMappingFromRec709(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); + return HDRMappingFromRec2020(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); #endif #else 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 19a017fa47e..f6dbaceb793 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 @@ -3909,6 +3909,11 @@ void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camer 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; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta new file mode 100644 index 00000000000..36fa898fff8 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eae5a6e8d005f3a45be72a32ee7135bc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: 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]; From 06939e0d2e70cb411af15ed7095251bee6fe16ab Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 1 Oct 2021 16:22:41 +0200 Subject: [PATCH 34/65] fix issues with debugs --- .../Runtime/RenderPipeline/HDRenderPipeline.Debug.cs | 3 ++- ...DRenderPipeline.PostProcess.cs.preformat.bak.meta | 7 ------- .../RenderPipeline/HDRenderPipeline.RenderGraph.cs | 12 +++++++----- 3 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta 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 609708b7330..791fb17adb4 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 @@ -1128,6 +1128,7 @@ TextureHandle RenderDebug(RenderGraph renderGraph, TextureHandle depthPyramidTexture, TextureHandle colorPickerDebugTexture, TextureHandle rayCountTexture, + TextureHandle xyBufferMapping, in BuildGPULightListOutput lightLists, in ShadowResult shadowResult, CullingResults cullResults, @@ -1155,7 +1156,7 @@ TextureHandle RenderDebug(RenderGraph renderGraph, output = RenderExposureDebug(renderGraph, hdCamera, colorBuffer); if (NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) - output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer, rayCountTexture); + output = RenderHDRDebug(renderGraph, hdCamera, colorBuffer, xyBufferMapping); if (NeedColorPickerDebug(m_CurrentDebugDisplaySettings)) output = ResolveColorPickerDebug(renderGraph, colorPickerDebugTexture, hdCamera, colorFormat); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta deleted file mode 100644 index 36fa898fff8..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs.preformat.bak.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: eae5a6e8d005f3a45be72a32ee7135bc -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: 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 6382c22e5f2..1a5aa55417b 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 @@ -297,7 +297,8 @@ void RecordRenderGraph(RenderRequest renderRequest, prepassOutput.resolvedDepthBuffer, prepassOutput.depthPyramidTexture, colorPickerTexture, - xyMapping, // TODO_FCC REVERT, HERE TO QUICK TEST. + rayCountTexture, + xyMapping, gpuLightListOutput, shadowResult, cullingResults, @@ -370,8 +371,8 @@ class FinalBlitPassData public Rect viewport; public Material blitMaterial; public Vector4 hdrOutputParmeters; + public bool applyAfterPP; - public FrameSettings frameSettings; public TextureHandle uiTexture; public TextureHandle afterPostProcessTexture; public TextureHandle source; @@ -399,13 +400,14 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); passData.destination = builder.WriteTexture(destination); - passData.frameSettings = hdCamera.frameSettings; + 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 { @@ -434,7 +436,7 @@ void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureH else data.blitMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); - if (data.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + if (data.applyAfterPP) { data.blitMaterial.EnableKeyword("APPLY_AFTER_POST"); data.blitMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); @@ -886,7 +888,7 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, TextureHandle depthBuffer) { var output = renderGraph.defaultResources.blackTextureXR; - if (HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay) + if (HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay && !NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) { using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { From dac0d3832a115430a1d262256b3b09fa8f4c5e83 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 4 Oct 2021 09:59:32 +0200 Subject: [PATCH 35/65] Only UI for hue shift, need to switch branch. --- .../Editor/PostProcessing/TonemappingEditor.cs | 6 ++++++ .../Runtime/PostProcessing/Components/Tonemapping.cs | 6 ++++++ 2 files changed, 12 insertions(+) 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 821ff34e952..6dc55be2aeb 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -22,6 +22,7 @@ sealed class TonemappingEditor : VolumeComponentEditor // HDR Mode. SerializedDataParameter m_NeutralHDRRangeReductionMode; + SerializedDataParameter m_HueShiftAmount; SerializedDataParameter m_HDRReduceLuminanceOnly; SerializedDataParameter m_HDRDetectPaperWhite; SerializedDataParameter m_HDRPaperwhite; @@ -54,6 +55,7 @@ public override void OnEnable() m_NeutralHDRRangeReductionMode = Unpack(o.Find(x => x.neutralHDRRangeReductionMode)); m_HDRReduceLuminanceOnly = Unpack(o.Find(x => x.tonemapOnlyLuminance)); + 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)); @@ -163,6 +165,10 @@ public override void OnInspectorGUI() { PropertyField(m_NeutralHDRRangeReductionMode); PropertyField(m_HDRReduceLuminanceOnly); + if (m_HDRReduceLuminanceOnly.value.boolValue) + { + PropertyField(m_HueShiftAmount); + } PropertyField(m_HDRDetectPaperWhite); EditorGUI.indentLevel++; using (new EditorGUI.DisabledScope(m_HDRDetectPaperWhite.value.boolValue)) 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 c0f67e1ad5f..2c130ba4b92 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 @@ -188,6 +188,12 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent [Tooltip("Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact.")] public BoolParameter tonemapOnlyLuminance = new BoolParameter(true); + /// + /// How much hue shift we want to preserve, tonemapping luma only will preserve hue, but if content relies on hue shift this slider helps reintroducing some. + /// + [Tooltip("How much hue shift we want to preserve, tonemapping luma only will preserve hue, but if content relies on hue shift this slider helps reintroducing some.")] + 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 will not lead to equivalent images between SDR and HDR. It is suggested to manually set this value. /// From 5b6fb71f4d298e81455e1a6d401bd599050bec56 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 Oct 2021 18:22:12 +0200 Subject: [PATCH 36/65] Naive hue shift version --- .../ShaderLibrary/HDROutput.hlsl | 22 ++++++++++++++----- .../Shaders/LutBuilder3D.compute | 3 ++- .../HDRenderPipeline.PostProcess.cs | 5 ++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index ca41bbf09e0..7f963e4d1dc 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -282,7 +282,10 @@ float3 RotateICtCpToOutputSpace(float3 ICtCp) return RotateICtCpToRec709(ICtCp); #elif defined(HDR_OUTPUT_REC2020) return RotateICtCpToRec2020(ICtCp); +#else + return RotateICtCpToRec2020(ICtCp); #endif + } // -------------------------------------------------------------------------------------------- @@ -421,7 +424,7 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits) return RotateICtCpToOutputSpace(ICtCp); // This moves back to linear too! } -float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mode) +float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mode, float hueShift) { float3 outputValue = input; if (mode == HDRRANGEREDUCTION_NONE) @@ -431,20 +434,27 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mod else if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY || mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) { float3 ICtCp = RotateOutputSpaceToICtCp(input); + float3 hueShiftedResult = 0; float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY) { linearLuma = ReinhardTonemap(linearLuma, maxNits); + hueShiftedResult.x = ReinhardTonemap(input.x, maxNits); + hueShiftedResult.y = ReinhardTonemap(input.y, maxNits); + hueShiftedResult.z = ReinhardTonemap(input.z, maxNits); } else if (mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) { linearLuma = BT2390EETF(linearLuma, minNits, maxNits); + hueShiftedResult.x = BT2390EETF(input.x, minNits, maxNits); + hueShiftedResult.y = BT2390EETF(input.y, minNits, maxNits); + hueShiftedResult.z = BT2390EETF(input.z, minNits, maxNits); } ICtCp.x = LinearToPQ(linearLuma); - outputValue = RotateICtCpToOutputSpace(ICtCp); + outputValue = lerp(RotateICtCpToOutputSpace(ICtCp), hueShiftedResult, hueShift); } else if (mode == HDRRANGEREDUCTION_REINHARD) { @@ -472,20 +482,20 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits, int mod // 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, bool skipOETF = false) +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); + 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, bool skipOETF = false) +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); + float3 reducedHDR = PerformRangeReduction(outputSpaceInput * paperWhite, minNits, maxNits, reductionMode, hueShift); if (skipOETF) return reducedHDR; 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 290dc23d2bb..21af7734f02 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 @@ -62,6 +62,7 @@ CBUFFER_START(cb0) #define _MaxNits _HDROutputParams.y #define _PaperWhite _HDROutputParams.z #define _RangeReductionMode (int)_HDROutputParams2.x + #define _HueShift _HDROutputParams2.y CBUFFER_END @@ -295,7 +296,7 @@ float3 ProcessColorForHDR(float3 gradedColor) gradedColor = ACEScg_to_ACES(gradedColor); return HDRMappingACES(gradedColor.rgb, _PaperWhite, _RangeReductionMode, true); #else - return HDRMappingFromRec2020(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, true); + return HDRMappingFromRec2020(gradedColor.rgb, _PaperWhite, _MinNits, _MaxNits, _RangeReductionMode, _HueShift, true); #endif #else 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 f6dbaceb793..376e652bcc0 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 @@ -3977,11 +3977,14 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out var maxNits = HDROutputSettings.main.maxToneMapLuminance; var paperWhite = HDROutputSettings.main.paperWhiteNits; int eetfMode = 0; + float hueShift = 0.0f; + if (tonemappingComponent.mode.value == TonemappingMode.Neutral || tonemappingComponent.mode.value == TonemappingMode.Custom || tonemappingComponent.mode.value == TonemappingMode.External) { bool luminanceOnly = tonemappingComponent.tonemapOnlyLuminance.value; + hueShift = luminanceOnly ? tonemappingComponent.hueShiftAmount.value : 0.0f; if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.BT2390) { eetfMode = luminanceOnly ? (int)HDRRangeReduction.BT2390LumaOnly : (int)HDRRangeReduction.BT2390; @@ -4007,7 +4010,7 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out } hdrOutputParameters1 = new Vector4(minNits, maxNits, paperWhite, HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709 ? 1 : 2); - hdrOutputParameters2 = new Vector4(eetfMode, maxNits, paperWhite, 0); + hdrOutputParameters2 = new Vector4(eetfMode, hueShift, paperWhite, 0); } void ComputeShadowsMidtonesHighlights(out Vector4 shadows, out Vector4 midtones, out Vector4 highlights, out Vector4 limits) From 92f1ef389c85b6020e281b5d04e0d41eb9f2edb7 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 Oct 2021 18:57:39 +0200 Subject: [PATCH 37/65] Option to have full ACES -- Note HDR always uses full. --- com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl | 2 ++ .../Editor/PostProcessing/TonemappingEditor.cs | 6 ++++++ .../Runtime/PostProcessing/Components/Tonemapping.cs | 7 +++++++ .../Runtime/PostProcessing/Shaders/LutBuilder3D.compute | 5 ++++- .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 2 +- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index 75556f2d65b..97c36276ffd 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -604,7 +604,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.high-definition/Editor/PostProcessing/TonemappingEditor.cs b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs index 6dc55be2aeb..0bf6d894023 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; @@ -44,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)); @@ -150,6 +152,10 @@ 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) { 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 2c130ba4b92..657c28cd11a 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 @@ -108,6 +108,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.")] + 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. 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 21af7734f02..f256b61a1cb 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,9 +1,12 @@ #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 +#define TONEMAPPING_ACES (defined(TONEMAPPING_ACES_APPROX) || defined(TONEMAPPING_ACES_FULL)) +#define TONEMAPPING_USE_FULL_ACES defined(TONEMAPPING_ACES_FULL) + #pragma kernel KBuild #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl" 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 376e652bcc0..0749a7ba8ee 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 @@ -3885,7 +3885,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camer 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; } From 6f91b696830398f286255123945f0794c99e8943 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 6 Oct 2021 19:39:54 +0200 Subject: [PATCH 38/65] Add better tooltip --- .../Runtime/PostProcessing/Components/Tonemapping.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 657c28cd11a..70ec1bb13e0 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 @@ -112,7 +112,7 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent /// Whether to use full ACES tonemap instead of an approximation. /// [AdditionalProperty] - [Tooltip("Whether to use full ACES tonemap instead of an approximation.")] + [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); /// From 3238bc124a2f7c117cc4101be7eb5ba2c94c5bb0 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 7 Oct 2021 15:59:12 +0200 Subject: [PATCH 39/65] Hue shift + add some desat on no hue shift regardless. --- .../PostProcessing/HDROutputDefines.cs | 8 - .../PostProcessing/HDROutputDefines.cs.hlsl | 12 +- .../ShaderLibrary/HDROutput.hlsl | 147 ++++++++++++++---- .../PostProcessing/TonemappingEditor.cs | 9 +- .../Runtime/Debug/LightingDebug.cs.hlsl | 8 + .../PostProcessing/Components/Tonemapping.cs | 10 +- .../HDRenderPipeline.PostProcess.cs | 9 +- 7 files changed, 138 insertions(+), 65 deletions(-) diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs index de690be0716..1cd9d7d11a2 100644 --- a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs @@ -13,14 +13,6 @@ public enum HDRRangeReduction /// None, /// - /// Reinhard tonemapping only on luminance. - /// - ReinhardLumaOnly, - /// - /// BT2390 Hermite spline EETF range reduction only on luminance. - /// - BT2390LumaOnly, - /// /// Reinhard tonemapping. /// Reinhard, diff --git a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl index 6e6ed3efa85..5f1423e3977 100644 --- a/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl +++ b/com.unity.render-pipelines.core/Runtime/PostProcessing/HDROutputDefines.cs.hlsl @@ -8,13 +8,11 @@ // UnityEngine.Rendering.HDRRangeReduction: static fields // #define HDRRANGEREDUCTION_NONE (0) -#define HDRRANGEREDUCTION_REINHARD_LUMA_ONLY (1) -#define HDRRANGEREDUCTION_BT2390LUMA_ONLY (2) -#define HDRRANGEREDUCTION_REINHARD (3) -#define HDRRANGEREDUCTION_BT2390 (4) -#define HDRRANGEREDUCTION_ACES1000NITS (5) -#define HDRRANGEREDUCTION_ACES2000NITS (6) -#define HDRRANGEREDUCTION_ACES4000NITS (7) +#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/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 7f963e4d1dc..07ef837fcee 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -424,54 +424,139 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits) 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 maxNits) +{ + float saturationAmount = pow(smoothstep(1.0f, 0.4f, ICtCp.x), 0.9f); + ICtCp.yz *= saturationAmount; + return ICtCp; +} + +float LumaRangeReduction(float input, float minNits, float maxNits, int mode) +{ + if (mode == HDRRANGEREDUCTION_REINHARD) + { + return ReinhardTonemap(input, maxNits); + } + else if (mode == HDRRANGEREDUCTION_BT2390) + { + return BT2390EETF(input, minNits, maxNits); + } + + return input; +} + +float3 HuePreservingRangeReduction(float3 input, float minNits, float maxNits, int mode) +{ + float3 ICtCp = RotateOutputSpaceToICtCp(input); + + float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); + linearLuma = LumaRangeReduction(linearLuma, minNits, maxNits, mode); + ICtCp.x = LinearToPQ(linearLuma); + ICtCp = DesaturateReducedICtCp(ICtCp, 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 if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY || mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) + else { - float3 ICtCp = RotateOutputSpaceToICtCp(input); - float3 hueShiftedResult = 0; + float3 huePreserving = reduceLuma ? HuePreservingRangeReduction(input, minNits, maxNits, mode) : 0; + float3 hueShifted = needHueShiftVersion ? HueShiftingRangeReduction(input, minNits, maxNits, mode) : 0; - float linearLuma = PQToLinear(ICtCp.x, MAX_PQ_VALUE); - if (mode == HDRRANGEREDUCTION_REINHARD_LUMA_ONLY) + if (reduceLuma && !needHueShiftVersion) { - linearLuma = ReinhardTonemap(linearLuma, maxNits); - hueShiftedResult.x = ReinhardTonemap(input.x, maxNits); - hueShiftedResult.y = ReinhardTonemap(input.y, maxNits); - hueShiftedResult.z = ReinhardTonemap(input.z, maxNits); + outputValue = huePreserving; } - else if (mode == HDRRANGEREDUCTION_BT2390LUMA_ONLY) + else if (!reduceLuma && needHueShiftVersion) { - linearLuma = BT2390EETF(linearLuma, minNits, maxNits); - hueShiftedResult.x = BT2390EETF(input.x, minNits, maxNits); - hueShiftedResult.y = BT2390EETF(input.y, minNits, maxNits); - hueShiftedResult.z = BT2390EETF(input.z, minNits, maxNits); + outputValue = hueShifted; + } + else + { + // We need to combine the two cases + outputValue = lerp(huePreserving, hueShifted, hueShift); } - - ICtCp.x = LinearToPQ(linearLuma); - - outputValue = lerp(RotateICtCpToOutputSpace(ICtCp), hueShiftedResult, hueShift); - } - else if (mode == HDRRANGEREDUCTION_REINHARD) - { - outputValue.x = ReinhardTonemap(input.x, maxNits); - outputValue.y = ReinhardTonemap(input.y, maxNits); - outputValue.z = ReinhardTonemap(input.z, maxNits); - } - else if (mode == HDRRANGEREDUCTION_BT2390) - { - outputValue.x = BT2390EETF(input.x, minNits, maxNits); - outputValue.y = BT2390EETF(input.y, minNits, maxNits); - outputValue.z = BT2390EETF(input.z, minNits, maxNits); } + return outputValue; } - // -------------------------------------------------------------------------------------------- // -------------------------------- 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 0bf6d894023..c7955889abe 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -24,7 +24,6 @@ sealed class TonemappingEditor : VolumeComponentEditor // HDR Mode. SerializedDataParameter m_NeutralHDRRangeReductionMode; SerializedDataParameter m_HueShiftAmount; - SerializedDataParameter m_HDRReduceLuminanceOnly; SerializedDataParameter m_HDRDetectPaperWhite; SerializedDataParameter m_HDRPaperwhite; SerializedDataParameter m_HDRDetectNitLimits; @@ -56,7 +55,6 @@ public override void OnEnable() m_LutContribution = Unpack(o.Find(x => x.lutContribution)); m_NeutralHDRRangeReductionMode = Unpack(o.Find(x => x.neutralHDRRangeReductionMode)); - m_HDRReduceLuminanceOnly = Unpack(o.Find(x => x.tonemapOnlyLuminance)); m_HueShiftAmount = Unpack(o.Find(x => x.hueShiftAmount)); m_HDRDetectPaperWhite = Unpack(o.Find(x => x.detectPaperWhite)); m_HDRPaperwhite = Unpack(o.Find(x => x.paperWhite)); @@ -170,11 +168,8 @@ public override void OnInspectorGUI() if (hdrTonemapMode == (int)TonemappingMode.Neutral) { PropertyField(m_NeutralHDRRangeReductionMode); - PropertyField(m_HDRReduceLuminanceOnly); - if (m_HDRReduceLuminanceOnly.value.boolValue) - { - PropertyField(m_HueShiftAmount); - } + PropertyField(m_HueShiftAmount); + PropertyField(m_HDRDetectPaperWhite); EditorGUI.indentLevel++; using (new EditorGUI.DisabledScope(m_HDRDetectPaperWhite.value.boolValue)) 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/PostProcessing/Components/Tonemapping.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Components/Tonemapping.cs index 70ec1bb13e0..8158f8117c3 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 @@ -190,15 +190,9 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent public HDRACESPresetParameter acesPreset = new HDRACESPresetParameter(HDRACESPreset.ACES1000Nits); /// - /// Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact. + /// 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("Whether to tonemap only the luminance when HDR Output is enabled, while keeping chroma intact.")] - public BoolParameter tonemapOnlyLuminance = new BoolParameter(true); - - /// - /// How much hue shift we want to preserve, tonemapping luma only will preserve hue, but if content relies on hue shift this slider helps reintroducing some. - /// - [Tooltip("How much hue shift we want to preserve, tonemapping luma only will preserve hue, but if content relies on hue shift this slider helps reintroducing some.")] + [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); /// 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 0749a7ba8ee..1a73bda2d73 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 @@ -3983,15 +3983,16 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out tonemappingComponent.mode.value == TonemappingMode.Custom || tonemappingComponent.mode.value == TonemappingMode.External) { - bool luminanceOnly = tonemappingComponent.tonemapOnlyLuminance.value; - hueShift = luminanceOnly ? tonemappingComponent.hueShiftAmount.value : 0.0f; + hueShift = tonemappingComponent.hueShiftAmount.value; + + bool luminanceOnly = hueShift == 0; if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.BT2390) { - eetfMode = luminanceOnly ? (int)HDRRangeReduction.BT2390LumaOnly : (int)HDRRangeReduction.BT2390; + eetfMode = (int)HDRRangeReduction.BT2390; } if (tonemappingComponent.neutralHDRRangeReductionMode.value == NeutralRangeReductionMode.Reinhard) { - eetfMode = luminanceOnly ? (int)HDRRangeReduction.ReinhardLumaOnly : (int)HDRRangeReduction.Reinhard; + eetfMode = (int)HDRRangeReduction.Reinhard; } } if (tonemappingComponent.mode.value == TonemappingMode.ACES) From 3f9e187adca27ee970a33f4ee0fbd8ab01beb306 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 7 Oct 2021 17:20:08 +0200 Subject: [PATCH 40/65] Dont compute LUT unless we need to. --- .../HDRenderPipeline.PostProcess.cs | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) 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 1a73bda2d73..acd5a0e65e5 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 @@ -65,6 +65,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); @@ -244,6 +246,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); @@ -282,12 +286,14 @@ void CleanupPostProcess() CoreUtils.Destroy(m_ClearBlackMaterial); CoreUtils.Destroy(m_SMAAMaterial); CoreUtils.Destroy(m_TemporalAAMaterial); + CoreUtils.Destroy(m_GradingAndTonemappingLUT); CoreUtils.SafeRelease(m_HistogramBuffer); CoreUtils.SafeRelease(m_DebugImageHistogramBuffer); RTHandles.Release(m_DebugExposureData); m_ExposureCurveTexture = null; m_InternalSpectralLut = null; + m_GradingAndTonemappingLUT = null; m_FinalPassMaterial = null; m_ClearBlackMaterial = null; m_SMAAMaterial = null; @@ -390,6 +396,19 @@ void BeginPostProcessFrame(CommandBuffer cmd, HDCamera camera, HDRenderPipeline m_DLSSPass.BeginFrame(camera); } + int ComputeLUTHash() + { + // hash = hash * 23 + parameters[i].GetHashCode(); + 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(); + } + static void ValidateComputeBuffer(ref ComputeBuffer cb, int size, int stride, ComputeBufferType type = ComputeBufferType.Default) { if (cb == null || cb.count < size) @@ -4109,22 +4128,20 @@ void ComputeSplitToning(out Vector4 shadows, out Vector4 highlights) TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) { + 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, hdCamera); passData.logLut = builder.WriteTexture(logLut); From 3ac01231005cc73db7102179dee23645ed506b23 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 7 Oct 2021 19:11:05 +0200 Subject: [PATCH 41/65] Selectable fallback --- .../PostProcessing/TonemappingEditor.cs | 11 ++-- .../PostProcessing/Components/Tonemapping.cs | 51 ++++++++++++++++++- .../HDRenderPipeline.PostProcess.cs | 19 ++++--- 3 files changed, 71 insertions(+), 10 deletions(-) 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 c7955889abe..fe34dab539a 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -30,6 +30,7 @@ sealed class TonemappingEditor : VolumeComponentEditor SerializedDataParameter m_HDRMinNits; SerializedDataParameter m_HDRMaxNits; SerializedDataParameter m_HDRAcesPreset; + SerializedDataParameter m_HDRFallbackMode; public override bool hasAdditionalProperties => true; @@ -62,6 +63,7 @@ public override void OnEnable() 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")); } @@ -159,10 +161,13 @@ public override void OnInspectorGUI() { EditorGUILayout.LabelField("HDR Output"); int hdrTonemapMode = m_Mode.value.intValue; - if (m_Mode.value.intValue == (int)TonemappingMode.Custom || m_Mode.value.intValue == (int)TonemappingMode.External) + if (m_Mode.value.intValue == (int)TonemappingMode.Custom || hdrTonemapMode == (int)TonemappingMode.External) { - EditorGUILayout.HelpBox("The selected tonmapping mode is not supported in HDR Output mode. It will fall-back to neutral tonmapping when outputting to HDR devices.", MessageType.Warning); - hdrTonemapMode = (int)TonemappingMode.Neutral; + EditorGUILayout.HelpBox("The selected tonmapping 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) 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 8158f8117c3..8a1741f8a0b 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, @@ -71,6 +71,24 @@ public enum HDRACESPreset 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 @@ -94,6 +112,17 @@ public sealed class HDRACESPresetParameter : VolumeParameter 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. /// @@ -189,6 +218,13 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent [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. /// @@ -233,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/RenderPipeline/HDRenderPipeline.PostProcess.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index acd5a0e65e5..164eddc3776 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 @@ -3892,6 +3892,12 @@ class ColorGradingPassData void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camera) { passData.tonemappingMode = m_TonemappingFS ? m_Tonemapping.mode.value : TonemappingMode.None; + bool tonemappingIsActive = m_Tonemapping.IsActive() && m_TonemappingFS; + if (HDROutputIsActive(camera) && 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"); @@ -3899,7 +3905,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camer // Setup lut builder compute & grab the kernel we need passData.builderCS.shaderKeywords = null; - if (m_Tonemapping.IsActive() && m_TonemappingFS) + if (tonemappingIsActive) { switch (passData.tonemappingMode) { @@ -3914,7 +3920,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camer passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } - if (HDROutputIsActive(camera)) + if (HDROutputIsActive(camera) && m_TonemappingFS) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -3998,9 +4004,9 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out int eetfMode = 0; float hueShift = 0.0f; - if (tonemappingComponent.mode.value == TonemappingMode.Neutral || - tonemappingComponent.mode.value == TonemappingMode.Custom || - tonemappingComponent.mode.value == TonemappingMode.External) + TonemappingMode hdrTonemapMode = tonemappingComponent.GetHDRTonemappingMode(); + + if (hdrTonemapMode == TonemappingMode.Neutral) { hueShift = tonemappingComponent.hueShiftAmount.value; @@ -4014,7 +4020,7 @@ public static void GetHDROutputParameters(Tonemapping tonemappingComponent, out eetfMode = (int)HDRRangeReduction.Reinhard; } } - if (tonemappingComponent.mode.value == TonemappingMode.ACES) + if (hdrTonemapMode == TonemappingMode.ACES) { eetfMode = (int)tonemappingComponent.acesPreset.value; } @@ -4126,6 +4132,7 @@ void ComputeSplitToning(out Vector4 shadows, out Vector4 highlights) highlights.w = 0f; } + // TODO: This can easily go async. TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) { TextureHandle logLut = renderGraph.ImportTexture(m_GradingAndTonemappingLUT); From a0503a7de691d4973493bbddbcbd301d365a9092 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 10:21:28 +0200 Subject: [PATCH 42/65] Fix scene view --- .../RenderPipeline/HDRenderPipeline.Debug.cs | 4 +-- .../HDRenderPipeline.PostProcess.cs | 35 +++++++++++-------- .../HDRenderPipeline.RenderGraph.cs | 6 ++-- .../RenderPipeline/HDRenderPipeline.cs | 30 +++++++++++----- 4 files changed, 47 insertions(+), 28 deletions(-) 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 791fb17adb4..c6cc73c7327 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 @@ -909,7 +909,7 @@ TextureHandle GenerateDebugHDRxyMapping(RenderGraph renderGraph, HDCamera hdCame { colorFormat = GraphicsFormat.R32_SFloat, enableRandomWrite = true, clearBuffer = true, name = "HDR_xyMapping" })); int gamut = 1; - if (HDROutputIsActive(hdCamera)) + if (HDROutputIsActive()) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) gamut = 1; @@ -962,7 +962,7 @@ TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, Texture { passData.debugHDRMaterial = m_DebugHDROutput; passData.lightingDebugSettings = m_CurrentDebugDisplaySettings.data.lightingDebugSettings; - if (HDROutputIsActive(hdCamera)) + if (HDROutputIsActive()) GetHDROutputParameters(hdCamera.volumeStack.GetComponent(), out passData.hdrOutputParams, out passData.hdrOutputParams2); else passData.hdrOutputParams.z = 1.0f; 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 164eddc3776..340858c39fc 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 @@ -406,7 +406,8 @@ int ComputeLUTHash() m_SplitToning.GetHashCode() * 23 + m_LiftGammaGain.GetHashCode() * 23 + m_ShadowsMidtonesHighlights.GetHashCode() * 23 + - m_Curves.GetHashCode(); + m_Curves.GetHashCode() * 23 + + HDROutputIsActive().GetHashCode(); } static void ValidateComputeBuffer(ref ComputeBuffer cb, int size, int stride, ComputeBufferType type = ComputeBufferType.Default) @@ -537,7 +538,7 @@ TextureHandle RenderPostProcess(RenderGraph renderGraph, source = LensFlareDataDrivenPass(renderGraph, hdCamera, source); 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); @@ -3889,11 +3890,11 @@ class ColorGradingPassData public TextureHandle logLut; } - void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camera) + void PrepareColorGradingParameters(ColorGradingPassData passData) { passData.tonemappingMode = m_TonemappingFS ? m_Tonemapping.mode.value : TonemappingMode.None; bool tonemappingIsActive = m_Tonemapping.IsActive() && m_TonemappingFS; - if (HDROutputIsActive(camera) && m_TonemappingFS) + if (HDROutputIsActive() && m_TonemappingFS) { passData.tonemappingMode = m_Tonemapping.GetHDRTonemappingMode(); tonemappingIsActive = m_TonemappingFS && passData.tonemappingMode != TonemappingMode.None; @@ -3920,7 +3921,7 @@ void PrepareColorGradingParameters(ColorGradingPassData passData, HDCamera camer passData.builderCS.EnableKeyword("TONEMAPPING_NONE"); } - if (HDROutputIsActive(camera) && m_TonemappingFS) + if (HDROutputIsActive() && m_TonemappingFS) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -4133,7 +4134,7 @@ void ComputeSplitToning(out Vector4 shadows, out Vector4 highlights) } // TODO: This can easily go async. - TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) + TextureHandle ColorGradingPass(RenderGraph renderGraph) { TextureHandle logLut = renderGraph.ImportTexture(m_GradingAndTonemappingLUT); @@ -4149,7 +4150,7 @@ TextureHandle ColorGradingPass(RenderGraph renderGraph, HDCamera hdCamera) using (var builder = renderGraph.AddRenderPass("Color Grading", out var passData, ProfilingSampler.Get(HDProfileId.ColorGradingLUTBuilder))) { - PrepareColorGradingParameters(passData, hdCamera); + PrepareColorGradingParameters(passData); passData.logLut = builder.WriteTexture(logLut); builder.SetRenderFunc( @@ -4456,7 +4457,7 @@ TextureHandle UberPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle passData.uberPostCS.EnableKeyword("GAMMA2_OUTPUT"); } - if (HDROutputIsActive(hdCamera)) + if (HDROutputIsActive()) { if (HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) { @@ -4817,6 +4818,7 @@ class FinalPassData public Vector4 hdroutParameters; public Vector4 hdroutParameters2; + public int outputColorSpace; public TextureHandle inputTest; @@ -4847,7 +4849,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.viewportSize = postProcessViewportSize; // Film Grain - passData.filmGrainEnabled = m_FilmGrain.IsActive() && m_FilmGrainFS && !HDROutputIsActive(hdCamera); // TODO: Investigate how to make grain work with HDR. + 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 @@ -4856,7 +4858,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.filmGrainResponse = m_FilmGrain.response.value; // Dithering - passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(hdCamera); + passData.ditheringEnabled = hdCamera.dithering && m_DitheringFS && !HDROutputIsActive(); passData.source = builder.ReadTexture(source); passData.afterPostProcessTexture = builder.ReadTexture(afterPostProcessTexture); @@ -4864,8 +4866,12 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo passData.destination = builder.WriteTexture(finalRT); passData.uiBuffer = builder.ReadTexture(uiBuffer); - if (HDROutputIsActive(hdCamera)) + 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); } @@ -4957,11 +4963,10 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo else finalPassMaterial.DisableKeyword("ENABLE_ALPHA"); - // TODO_FCC: IMPORTANT! FIX OR IT WILL CAPTURE. - bool processHDR = HDROutputIsActive(hdCamera) && HDUtils.PostProcessIsFinalPass(data.hdCamera); + bool processHDR = HDROutputIsActive() && HDUtils.PostProcessIsFinalPass(data.hdCamera); if (processHDR) { - if (HDROutputSettings.main.active && HDROutputSettings.main.displayColorGamut == ColorGamut.Rec709) + if (data.outputColorSpace == 0) { finalPassMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); } @@ -5000,7 +5005,7 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo finalPassMaterial.EnableKeyword("APPLY_AFTER_POST"); finalPassMaterial.SetTexture(HDShaderIDs._AfterPostProcessTexture, data.afterPostProcessTexture); } - else if (!HDROutputIsActive(data.hdCamera) && data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.AfterPostprocess)) + 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 1a5aa55417b..98c698023c0 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 @@ -308,7 +308,7 @@ void RecordRenderGraph(RenderRequest renderRequest, for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex) { - BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive(hdCamera)); + BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, uiBuffer, afterPostProcessBuffer, viewIndex, HDROutputIsActive()); } if (aovRequest.isValid) @@ -888,7 +888,7 @@ TextureHandle RenderTransparentUI(RenderGraph renderGraph, TextureHandle depthBuffer) { var output = renderGraph.defaultResources.blackTextureXR; - if (HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay && !NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) + if (HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && !NeedHDRDebugMode(m_CurrentDebugDisplaySettings)) { using (var builder = renderGraph.AddRenderPass("UI Rendering", out var passData, ProfilingSampler.Get(HDProfileId.OffscreenUIRendering))) { @@ -2064,7 +2064,7 @@ class RenderScreenSpaceOverlayData void RenderScreenSpaceOverlayUI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) { - if (!HDROutputIsActive(hdCamera) && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) + if (!HDROutputIsActive() && SupportedRenderingFeatures.active.rendersUIOverlay && hdCamera.camera.cameraType != CameraType.SceneView) { using (var builder = renderGraph.AddRenderPass("Screen Space Overlay UI", out var passData)) { 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 8e608a26b44..015bddb7ebf 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -199,9 +199,28 @@ internal int GetMaxScreenSpaceShadows() return currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows ? currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots : 0; } - static bool HDROutputIsActive(HDCamera camera) + static bool HDROutputIsActive() { - return HDROutputSettings.main.active && camera.camera.cameraType == CameraType.Game; + return 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(); @@ -1948,12 +1967,7 @@ AOVRequestData aovRequest // Updates RTHandle hdCamera.BeginRender(cmd); - // Make sure HDR auto tonemap is off - if (HDROutputSettings.main.active) - { - HDROutputSettings.main.automaticHDRTonemapping = false; - } - + SetHDRState(hdCamera); if (m_RayTracingSupported) { From a3a7d7fb76b1914922104e6f887a626a0a366ae5 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 10:35:10 +0200 Subject: [PATCH 43/65] Add paperwhite back into ACES mode --- .../Editor/PostProcessing/TonemappingEditor.cs | 7 +++++++ 1 file changed, 7 insertions(+) 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 fe34dab539a..c2cd20aee34 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -194,6 +194,13 @@ public override void OnInspectorGUI() 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--; } } } From 6423b458bf592b06814ecaa174f950589a16cb8b Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 11:31:59 +0200 Subject: [PATCH 44/65] Minor cleanup --- .../HDRenderPipelineEditorResources.asset | 1 - .../Runtime/PostProcessing/Shaders/FinalPass.shader | 1 - .../Runtime/RenderPipeline/HDProfileId.cs | 1 - .../Runtime/RenderPipeline/HDRenderPipeline.Debug.cs | 1 - .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 1 - 5 files changed, 5 deletions(-) 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 41b2ec6587c..299b477908f 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipelineResources/HDRenderPipelineEditorResources.asset @@ -26,7 +26,6 @@ MonoBehaviour: defaultDecalMat: {fileID: 2100000, guid: 500e733574922d04ea961553b1b26a63, type: 2} defaultParticleMat: {fileID: 2100000, guid: b739a3f02ff77bf48b7636e64c3e3b4c, type: 2} defaultTerrainMat: {fileID: 2100000, guid: 22ff8771d87ef27429e670136399094b, type: 2} - defaultUIMat: {fileID: 2100000, guid: 0b4a88fad3f0a6440a0434e38f80ebab, type: 2} GUITextureBlit2SRGB: {fileID: 2100000, guid: 6e95c04e4e686554e8bed96ee69f690c, type: 2} shaderGraphs: autodeskInteractive: {fileID: 4800000, guid: 7252379db4c18b641b517f2c91bb57e1, type: 3} 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 ce10a9581a6..1644eecb4c0 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 @@ -25,7 +25,6 @@ Shader "Hidden/HDRP/FinalPass" #if defined(HDR_OUTPUT_REC2020) || defined(HDR_OUTPUT_SCRGB) #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl" #endif - #pragma enable_d3d11_debug_symbols TEXTURE2D_X(_InputTexture); TEXTURE2D(_GrainTexture); 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 da7993dfd3d..10a8bd1d5c5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -62,7 +62,6 @@ internal enum HDProfileId HDRenderPipelineRenderAOV, HDRenderPipelineAllRenderRequest, CullResultsCull, - UICullResults, CustomPassCullResultsCull, DisplayCookieAtlas, RenderWireFrame, 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 c6cc73c7327..303a54e099a 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 @@ -973,7 +973,6 @@ TextureHandle RenderHDRDebug(RenderGraph renderGraph, HDCamera hdCamera, Texture passData.output = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, name = "HDRDebug" })); - // TODO: Put here tonemap type. passData.hdrDebugParams = new Vector4(k_SizeOfHDRXYMapping, k_SizeOfHDRXYMapping, 0, 0); passData.xyTexture = builder.ReadTexture(xyBuff); 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 340858c39fc..e56e3c18204 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 @@ -398,7 +398,6 @@ void BeginPostProcessFrame(CommandBuffer cmd, HDCamera camera, HDRenderPipeline int ComputeLUTHash() { - // hash = hash * 23 + parameters[i].GetHashCode(); return m_Tonemapping.GetHashCode() * 23 + m_WhiteBalance.GetHashCode() * 23 + m_ColorAdjustments.GetHashCode() * 23 + From 98bd50f27146b6694ef09cc106f1e06b4d4b4e17 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 11:47:47 +0200 Subject: [PATCH 45/65] Add HDR bit depth to the LUT hash. --- .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 e56e3c18204..538e46f5cf2 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 @@ -406,7 +406,12 @@ int ComputeLUTHash() m_LiftGammaGain.GetHashCode() * 23 + m_ShadowsMidtonesHighlights.GetHashCode() * 23 + m_Curves.GetHashCode() * 23 + - HDROutputIsActive().GetHashCode(); + HDROutputIsActive().GetHashCode() +#if UNITY_EDITOR + * 23 + UnityEditor.PlayerSettings.D3DHDRBitDepth.GetHashCode() + +#endif + ; } static void ValidateComputeBuffer(ref ComputeBuffer cb, int size, int stride, ComputeBufferType type = ComputeBufferType.Default) From 3551ebdb9d41556964a9eb9fd56712645d55e5c6 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 11:53:26 +0200 Subject: [PATCH 46/65] Changelog --- com.unity.render-pipelines.high-definition/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 51809acae69..78c5d8a4b87 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -6,7 +6,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. @@ -41,6 +47,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Visual Environment ambient mode is now Dynamic by default. - Surface ReflectionTypeLoadExceptions in HDUtils.GetRenderPipelineMaterialList(). Without surfacing these exceptions, developers cannot act on any underlying reflection errors in the HDRP assembly. +- Optimized color grading LUT building. +- Made ACEScg the default color space for color grading. ## [12.0.0] - 2021-01-11 From baf4f01f57ff9529bd3b3b5f338a4498d098820e Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 13:18:53 +0200 Subject: [PATCH 47/65] Fix NONE tonemapper case fallbacking into ACES --- .../Runtime/PostProcessing/Shaders/LutBuilder3D.compute | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 f256b61a1cb..3923732e63d 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 @@ -4,7 +4,9 @@ #pragma multi_compile_local _ HDR_OUTPUT_REC2020 HDR_OUTPUT_SCRGB #pragma multi_compile_local GRADE_IN_SRGB GRADE_IN_ACESCG -#define TONEMAPPING_ACES (defined(TONEMAPPING_ACES_APPROX) || defined(TONEMAPPING_ACES_FULL)) +#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 From 4e1afd0b5c807e9ec6252f691a7de4505561dde9 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 14:35:53 +0200 Subject: [PATCH 48/65] wokaround compile issue? --- .../Runtime/PostProcessing/Shaders/LutBuilder3D.compute | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 3923732e63d..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 @@ -297,16 +297,15 @@ float3 ProcessColorForHDR(float3 gradedColor) { #ifdef HDR_OUTPUT -#if TONEMAPPING_ACES +#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 -#else - return gradedColor; #endif + return gradedColor; } From f77cf3d78fc9787b5416a0066ebeb6e2da3dc0f3 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Fri, 8 Oct 2021 15:58:03 +0200 Subject: [PATCH 49/65] For simplicity move old tests to sRGB grading --- .../HDRenderPipelineGlobalSettings.asset | 20 +++- .../HDRenderPipelineGlobalSettings.asset | 102 ++++++++++++++++++ .../HDRenderPipelineGlobalSettings.asset | 1 + .../HDRenderPipelineGlobalSettings.asset | 6 +- .../HDRenderPipelineGlobalSettings.asset | 10 +- 5 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 TestProjects/HDRP_HybridTests/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset 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 746c7214d84..89851ddd0ec 100644 --- a/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset +++ b/TestProjects/VisualEffectGraph_HDRP/Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset @@ -65,6 +65,7 @@ MonoBehaviour: m_RenderPipelineRayTracingResources: {fileID: 0} beforeTransparentCustomPostProcesses: [] beforePostProcessCustomPostProcesses: [] + afterPostProcessBlursCustomPostProcesses: [] afterPostProcessCustomPostProcesses: [] beforeTAACustomPostProcesses: [] lightLayerName0: @@ -85,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} @@ -92,7 +94,11 @@ MonoBehaviour: DLSSProjectId: 000000 useDLSSCustomProjectId: 0 supportProbeVolumes: 0 - apvScenesBounds: + supportRuntimeDebugDisplay: 1 + apvScenesData: serializedBounds: [] serializedHasVolumes: [] - m_Version: 2 + serializedProfiles: [] + serializedBakeSettings: [] + serializedBakingSets: [] + m_Version: 3 From b545a67302370501f0f264a897cfe30d16d9d61f Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 Oct 2021 13:53:47 +0200 Subject: [PATCH 50/65] Fix desaturation so it uses BT2390 doc (but similar to prev ad-hoc version) + code review touchups --- .../ShaderLibrary/HDROutput.hlsl | 10 +++++++--- .../Runtime/PostProcessing/Shaders/FinalPass.shader | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 07ef837fcee..5e9339a26f9 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -425,9 +425,12 @@ float3 PerformRangeReduction(float3 input, float minNits, float maxNits) } // TODO: This is very ad-hoc and eyeballed on a limited set. Would be nice to find a standard. -float3 DesaturateReducedICtCp(float3 ICtCp, float maxNits) +float3 DesaturateReducedICtCp(float3 ICtCp, float lumaPre, float maxNits) { - float saturationAmount = pow(smoothstep(1.0f, 0.4f, ICtCp.x), 0.9f); + 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; } @@ -450,10 +453,11 @@ float3 HuePreservingRangeReduction(float3 input, float minNits, float maxNits, i { 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, maxNits); + ICtCp = DesaturateReducedICtCp(ICtCp, lumaPreRed, maxNits); return RotateICtCpToOutputSpace(ICtCp); } 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 1644eecb4c0..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 @@ -28,7 +28,6 @@ Shader "Hidden/HDRP/FinalPass" TEXTURE2D_X(_InputTexture); TEXTURE2D(_GrainTexture); - TEXTURE2D(_HDRImageTest); TEXTURE2D_X(_AfterPostProcessTexture); TEXTURE2D_ARRAY(_BlueNoiseTexture); From 475e700d4272b068177fdf216ed20c18cbd1c850 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 Oct 2021 13:55:50 +0200 Subject: [PATCH 51/65] Missing code change. --- .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 f5bbb4de2bc..d5abe4647fc 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 @@ -281,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); @@ -289,14 +291,12 @@ void CleanupPostProcess() CoreUtils.Destroy(m_ClearBlackMaterial); CoreUtils.Destroy(m_SMAAMaterial); CoreUtils.Destroy(m_TemporalAAMaterial); - CoreUtils.Destroy(m_GradingAndTonemappingLUT); CoreUtils.SafeRelease(m_HistogramBuffer); CoreUtils.SafeRelease(m_DebugImageHistogramBuffer); RTHandles.Release(m_DebugExposureData); m_ExposureCurveTexture = null; m_InternalSpectralLut = null; - m_GradingAndTonemappingLUT = null; m_FinalPassMaterial = null; m_ClearBlackMaterial = null; m_SMAAMaterial = null; From 1aae7ca6242367e629a7ff28b353731e1375cf82 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 Oct 2021 17:28:00 +0200 Subject: [PATCH 52/65] Documentation sync point (missing debug views) --- .../Documentation~/HDR-Output.md | 72 +++++++++++++++++++ .../Documentation~/Images/HDR-Output-ACES.png | 3 + .../Images/HDR-Output-HueShift.png | 3 + .../Images/HDR-Output-Neutral.png | 3 + .../Upgrading-from-2021.2-to-2022.1.md | 7 ++ 5 files changed, 88 insertions(+) create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md new file mode 100644 index 00000000000..6b987750231 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md @@ -0,0 +1,72 @@ +# High Definition Range (HDR) Output in HDRP + +With HDRP it is possible to output to High Dynamic Range (HDR) devices that allows for wider color gamut and higher brightness range. + +HDR Output can be enabled for a given platform in **Player Settings > Other Settings > Use display in HDR mode**. When this option is enabled, HDRP will process the frame so that when an HDR screen is used as output device it is presented correctly. + +## Tonemapping for HDR Output + +When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the Tonemapping [TODO ADD LINK] volume component. The available options depend on the Tonemapping mode selected. + +Unlike tonemapping for LDR displays, the tonemapping for HDR screens require to take into account the capabilities of the device. In particular it is important to adapt to three values: + +- Paper white value: determines the brightness value of a paper-white surface. In practice this will determines the overall screen brightness and what brightness the UI will map to. This latter point is important as usually unlit UI is rendered assuming that a value of 1 corresponds to a white color; this assumption is not true when it comes to HDR, so HDRP uses the paper white to tune the UI so that white UI will map to a white value on screen. +- Minimum Brightness: the minimum brightness that the display can display. +- Maximum Brightness: the maximum brightness that the display can display before saturating the values. + +All the above values are in nits (candela per square meters). + +While it is possible to detect the above three values from the screen outputting your content, it is possible that the values communicated by the device are going to be inaccurate. For this reason, we suggest to implement a calibration menu for your application. + +Specifically, detected Paper white values are often going to produce dimmer results than what the LDR content will produce, the reason is that normally TV boost brightness values when displaying LDR content, but respect the actual values when outputting HDR contents. + +#### Neutral + +![HDR-Output-Neutral](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-Neutral.png) + +## + +| **Property** | **Description** | +| ------------------------------------ | ------------------------------------------------------------ | +| **Neutral HDR Range Reduction Mode** | The tonemapping curve used for the Neutral tonemapper. The options are:
- BT2390: Uses a curve defined by the BT2390 broadcasting recommendations. (Default)
- Reinhard: A very simple tonemapping operator.

This option is available only when Additional Properties are displayed. | +| **Hue Shift Amount** | Determines how much hue preservation is desired. When the value is 0, the tonemapper will try to preserve the hue of the content as much as possible, tonemapping only the luminance. However, some content might have been authored assuming that hue-shift will happen when all color channels are tonemapped independently. To recover the hue-shift behaviour this slider can be moved toward See note below for more information. | +| **Detect Paper White** | Whether the paper white value is detected from the data communicated by the display device. We strongly suggest to provide a calibration screen to let the user set this value depending on their screen and viewing experience. | +| **- Paper White** | Paper white value (in nits) set when it is not automatically detected from the display. | +| **Detect Brightness Limits** | Whether the minimum and maximum brightness values are detected from the data communicated by the display device. While using these values as detected lead to more precise results than detecting paperwhite values, we still suggest to use a calibration screen. | +| **- Min Nits** | Minimum brightness supported by the device. | +| **- Max Nits** | Maximum brightness supported by the device. | + +While Hue-preserving tonemapping (i.e. Hue Shift Amount set to 0) will better preserve the content colors, sometimes content is authored to rely on the hue shifts that high brightness will produce. A typical example can be for example a very bright flame VFX. The image below shows on the left a flame with Hue Shift Amount set to 0 and on the right the same flame with the hue shift preserved (Hue Shift Amount set to 1). + + HDR-Output-HueShift +*Image modified to show the issue clearly.* + +The right choice depends on your content, but we suggest to make sure your content is authored to work well without relying on Hue-shift. + +#### ACES + +Contrary to the neutral version, the ACES tonemapping option has fixed presets. These are meant to target screens with 1000, 2000 and 4000 nits maximum brightness. We suggest to use calibration screen to detect the right preset for the user consuming the content. + +![HDR-Output-ACES](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-ACES.png) + +## + +| **Property** | **Description** | +| ---------------------- | ------------------------------------------------------------ | +| **ACES Preset** | The tonemapper preset to use. The options are:
- ACES 1000 Nits: Curve used to target 1000 nits displays (Default)
- ACES 2000 Nits: Curve used to target 2000 nits displays
- ACES 4000 Nits: Curve used to target 4000 nits displays | +| **Detect Paper White** | Whether the paper white value is detected from the data communicated by the display device. We strongly suggest to provide a calibration screen to let the user set this value depending on their screen and viewing experience. | +| **- Paper White** | Paper white value (in nits) set when it is not automatically detected from the display. | + +#### Custom + +Currently not supported by HDR Output. It is possible to decide whether to fallback on Neutral or ACES for outputting to an HDR device. + +#### External + +Not supported. Mostly because every different HDR screen used to display the content would need a different LUT. It is possible to decide whether to fallback on Neutral or ACES for outputting to an HDR device. + + + +## HDR Debug Views + +HDRP offers three debug views for HDR rendering. diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png new file mode 100644 index 00000000000..2bbe321fe20 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e448f756eaf85b79ee68d01f254ce7fdaa65e272b48614c5188e9b24f4c0fb4b +size 11739 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png new file mode 100644 index 00000000000..d73c46b1b88 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7c2b98f74f6d706fadd589e63998ac17e36d3beb6244fc6a1887b64aa9ed79a +size 562696 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png new file mode 100644 index 00000000000..6d9e3fbe487 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c073e4c07f8470fa3244ebd6d3c844379b85ce5c7169f85ce480d09f919b8be6 +size 17252 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md b/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md new file mode 100644 index 00000000000..edcb72bc32b --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md @@ -0,0 +1,7 @@ +# Upgrading HDRP from 2021.1 to 2021.2 + +In the High Definition Render Pipeline (HDRP), some features work differently between major versions. This document helps you upgrade HDRP from 12.x to 13.x. + +## Color Grading + +Starting from HDRP 13.x, HDRP will use ACEScg as a default color space to perform color grading even when using a non-ACES if unlike the previously used sRGB color space. It is possible to go back to sRGB in the Global Settings Asset. From 9af360420dd752894d66e69051ce38bd3011016d Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 Oct 2021 18:20:34 +0200 Subject: [PATCH 53/65] Added debug view docs --- .../Documentation~/HDR-Output.md | 25 ++++++++++++++++--- .../Images/HDR-Output-GamutClip.png | 3 +++ .../Images/HDR-Output-GamutView.png | 3 +++ .../Images/HDR-Output-OverPaperWhite.png | 3 +++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png create mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md index 6b987750231..0fa782557cf 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md @@ -24,8 +24,6 @@ Specifically, detected Paper white values are often going to produce dimmer resu ![HDR-Output-Neutral](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-Neutral.png) -## - | **Property** | **Description** | | ------------------------------------ | ------------------------------------------------------------ | | **Neutral HDR Range Reduction Mode** | The tonemapping curve used for the Neutral tonemapper. The options are:
- BT2390: Uses a curve defined by the BT2390 broadcasting recommendations. (Default)
- Reinhard: A very simple tonemapping operator.

This option is available only when Additional Properties are displayed. | @@ -69,4 +67,25 @@ Not supported. Mostly because every different HDR screen used to display the con ## HDR Debug Views -HDRP offers three debug views for HDR rendering. +HDRP offers three debug views for HDR rendering. These can be found in **Window > Analysis > Render Pipeline Debugger > Lighting > HDR** + +#### Gamut View + +Will display on the bottom left of the screen two triangles representing the Rec709 and Rec2020 color gamuts and display what parts of the gamut are covered by the scene. +![HDR-Output-GamutView](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-GamutView.png) + +This can be very useful to verify that you are taking advantage of the wider color gamut and is a way to see how color plot changes as you perform color grading. + +#### Gamut Clip + +Very similar to the above, except it shows red for areas of the screen that are outside the sRGB/Rec709 color gamut and green for anything that is in both the Rec709 and Rec2020 color gamut. + +![HDR-Output-GamutClip](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-GamutClip.png) + + + +#### Values over Paperwhite value + +This debug view shows the scene as luminance values except for parts of the scene that are over the paper white value that are displayed as a gradient from yellow (paperwhite +1) value to red (max brightness nits) + +![HDR-Output-OverPaperWhite](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-OverPaperWhite.png) diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png new file mode 100644 index 00000000000..95d7d0fe921 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3a44f81adad68d45bbabe06f36624712ecc240b600628ca2e250c0bc00347c60 +size 621662 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png new file mode 100644 index 00000000000..9075f5ab8a2 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec2e3037811ea0d1dd3c072d94939523c960d97664de48fb54756dc45d182792 +size 1556683 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png new file mode 100644 index 00000000000..cb8c11d97e6 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:937596394f73d1e92cab97f1445bb5a7ad8916bc7861d4185c1552cc09d0e367 +size 2466410 From f5626c0450f38c3a51b012198668d2903de6ed6e Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 11 Oct 2021 18:33:43 +0200 Subject: [PATCH 54/65] Add link to tonemap --- .../Documentation~/HDR-Output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md index 0fa782557cf..1f156eaf321 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md @@ -6,7 +6,7 @@ HDR Output can be enabled for a given platform in **Player Settings > Other Sett ## Tonemapping for HDR Output -When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the Tonemapping [TODO ADD LINK] volume component. The available options depend on the Tonemapping mode selected. +When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the [Tonemapping](Post-Processing-Tonemapping.md) volume component. The available options depend on the Tonemapping mode selected. Unlike tonemapping for LDR displays, the tonemapping for HDR screens require to take into account the capabilities of the device. In particular it is important to adapt to three values: From af1355e7a3703dc4e839c48242a456119e03bd1b Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 12 Oct 2021 16:21:44 +0200 Subject: [PATCH 55/65] Fix player Rec2020 --- .../RenderPipeline/HDRenderPipeline.PostProcess.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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 d5abe4647fc..34a0a6ca82f 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 @@ -5063,14 +5063,11 @@ void FinalPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle afterPo bool processHDR = HDROutputIsActive() && HDUtils.PostProcessIsFinalPass(data.hdCamera); if (processHDR) { - if (data.outputColorSpace == 0) - { - finalPassMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); - } + if (data.hdroutParameters.w == 1) + data.finalPassMaterial.EnableKeyword("HDR_OUTPUT_SCRGB"); else - { - finalPassMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); - } + data.finalPassMaterial.EnableKeyword("HDR_OUTPUT_REC2020"); + finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams, data.hdroutParameters); finalPassMaterial.SetVector(HDShaderIDs._HDROutputParams2, data.hdroutParameters2); From 8ca33de9155b32c7772b46a179015fc5972e13ee Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 12 Oct 2021 16:30:46 +0200 Subject: [PATCH 56/65] Revert "Add link to tonemap" This reverts commit f5626c0450f38c3a51b012198668d2903de6ed6e. --- .../Documentation~/HDR-Output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md index 1f156eaf321..0fa782557cf 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md @@ -6,7 +6,7 @@ HDR Output can be enabled for a given platform in **Player Settings > Other Sett ## Tonemapping for HDR Output -When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the [Tonemapping](Post-Processing-Tonemapping.md) volume component. The available options depend on the Tonemapping mode selected. +When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the Tonemapping [TODO ADD LINK] volume component. The available options depend on the Tonemapping mode selected. Unlike tonemapping for LDR displays, the tonemapping for HDR screens require to take into account the capabilities of the device. In particular it is important to adapt to three values: From 2f7233019b6b7a4f3dc0e53b7f6b53c2183e005c Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 12 Oct 2021 16:30:52 +0200 Subject: [PATCH 57/65] Revert "Added debug view docs" This reverts commit 9af360420dd752894d66e69051ce38bd3011016d. --- .../Documentation~/HDR-Output.md | 25 +++---------------- .../Images/HDR-Output-GamutClip.png | 3 --- .../Images/HDR-Output-GamutView.png | 3 --- .../Images/HDR-Output-OverPaperWhite.png | 3 --- 4 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md index 0fa782557cf..6b987750231 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md @@ -24,6 +24,8 @@ Specifically, detected Paper white values are often going to produce dimmer resu ![HDR-Output-Neutral](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-Neutral.png) +## + | **Property** | **Description** | | ------------------------------------ | ------------------------------------------------------------ | | **Neutral HDR Range Reduction Mode** | The tonemapping curve used for the Neutral tonemapper. The options are:
- BT2390: Uses a curve defined by the BT2390 broadcasting recommendations. (Default)
- Reinhard: A very simple tonemapping operator.

This option is available only when Additional Properties are displayed. | @@ -67,25 +69,4 @@ Not supported. Mostly because every different HDR screen used to display the con ## HDR Debug Views -HDRP offers three debug views for HDR rendering. These can be found in **Window > Analysis > Render Pipeline Debugger > Lighting > HDR** - -#### Gamut View - -Will display on the bottom left of the screen two triangles representing the Rec709 and Rec2020 color gamuts and display what parts of the gamut are covered by the scene. -![HDR-Output-GamutView](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-GamutView.png) - -This can be very useful to verify that you are taking advantage of the wider color gamut and is a way to see how color plot changes as you perform color grading. - -#### Gamut Clip - -Very similar to the above, except it shows red for areas of the screen that are outside the sRGB/Rec709 color gamut and green for anything that is in both the Rec709 and Rec2020 color gamut. - -![HDR-Output-GamutClip](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-GamutClip.png) - - - -#### Values over Paperwhite value - -This debug view shows the scene as luminance values except for parts of the scene that are over the paper white value that are displayed as a gradient from yellow (paperwhite +1) value to red (max brightness nits) - -![HDR-Output-OverPaperWhite](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-OverPaperWhite.png) +HDRP offers three debug views for HDR rendering. diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png deleted file mode 100644 index 95d7d0fe921..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutClip.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a44f81adad68d45bbabe06f36624712ecc240b600628ca2e250c0bc00347c60 -size 621662 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png deleted file mode 100644 index 9075f5ab8a2..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-GamutView.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ec2e3037811ea0d1dd3c072d94939523c960d97664de48fb54756dc45d182792 -size 1556683 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png deleted file mode 100644 index cb8c11d97e6..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-OverPaperWhite.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:937596394f73d1e92cab97f1445bb5a7ad8916bc7861d4185c1552cc09d0e367 -size 2466410 From 939a2127ad3d2acc149bae11b239c400b64840b3 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Tue, 12 Oct 2021 16:31:03 +0200 Subject: [PATCH 58/65] Revert "Documentation sync point (missing debug views)" This reverts commit 1aae7ca6242367e629a7ff28b353731e1375cf82. --- .../Documentation~/HDR-Output.md | 72 ------------------- .../Documentation~/Images/HDR-Output-ACES.png | 3 - .../Images/HDR-Output-HueShift.png | 3 - .../Images/HDR-Output-Neutral.png | 3 - .../Upgrading-from-2021.2-to-2022.1.md | 7 -- 5 files changed, 88 deletions(-) delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png delete mode 100644 com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md diff --git a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md b/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md deleted file mode 100644 index 6b987750231..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/HDR-Output.md +++ /dev/null @@ -1,72 +0,0 @@ -# High Definition Range (HDR) Output in HDRP - -With HDRP it is possible to output to High Dynamic Range (HDR) devices that allows for wider color gamut and higher brightness range. - -HDR Output can be enabled for a given platform in **Player Settings > Other Settings > Use display in HDR mode**. When this option is enabled, HDRP will process the frame so that when an HDR screen is used as output device it is presented correctly. - -## Tonemapping for HDR Output - -When the *Use display in HDR mode* option is set in the player settings, all the HDR related options appear in the Tonemapping [TODO ADD LINK] volume component. The available options depend on the Tonemapping mode selected. - -Unlike tonemapping for LDR displays, the tonemapping for HDR screens require to take into account the capabilities of the device. In particular it is important to adapt to three values: - -- Paper white value: determines the brightness value of a paper-white surface. In practice this will determines the overall screen brightness and what brightness the UI will map to. This latter point is important as usually unlit UI is rendered assuming that a value of 1 corresponds to a white color; this assumption is not true when it comes to HDR, so HDRP uses the paper white to tune the UI so that white UI will map to a white value on screen. -- Minimum Brightness: the minimum brightness that the display can display. -- Maximum Brightness: the maximum brightness that the display can display before saturating the values. - -All the above values are in nits (candela per square meters). - -While it is possible to detect the above three values from the screen outputting your content, it is possible that the values communicated by the device are going to be inaccurate. For this reason, we suggest to implement a calibration menu for your application. - -Specifically, detected Paper white values are often going to produce dimmer results than what the LDR content will produce, the reason is that normally TV boost brightness values when displaying LDR content, but respect the actual values when outputting HDR contents. - -#### Neutral - -![HDR-Output-Neutral](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-Neutral.png) - -## - -| **Property** | **Description** | -| ------------------------------------ | ------------------------------------------------------------ | -| **Neutral HDR Range Reduction Mode** | The tonemapping curve used for the Neutral tonemapper. The options are:
- BT2390: Uses a curve defined by the BT2390 broadcasting recommendations. (Default)
- Reinhard: A very simple tonemapping operator.

This option is available only when Additional Properties are displayed. | -| **Hue Shift Amount** | Determines how much hue preservation is desired. When the value is 0, the tonemapper will try to preserve the hue of the content as much as possible, tonemapping only the luminance. However, some content might have been authored assuming that hue-shift will happen when all color channels are tonemapped independently. To recover the hue-shift behaviour this slider can be moved toward See note below for more information. | -| **Detect Paper White** | Whether the paper white value is detected from the data communicated by the display device. We strongly suggest to provide a calibration screen to let the user set this value depending on their screen and viewing experience. | -| **- Paper White** | Paper white value (in nits) set when it is not automatically detected from the display. | -| **Detect Brightness Limits** | Whether the minimum and maximum brightness values are detected from the data communicated by the display device. While using these values as detected lead to more precise results than detecting paperwhite values, we still suggest to use a calibration screen. | -| **- Min Nits** | Minimum brightness supported by the device. | -| **- Max Nits** | Maximum brightness supported by the device. | - -While Hue-preserving tonemapping (i.e. Hue Shift Amount set to 0) will better preserve the content colors, sometimes content is authored to rely on the hue shifts that high brightness will produce. A typical example can be for example a very bright flame VFX. The image below shows on the left a flame with Hue Shift Amount set to 0 and on the right the same flame with the hue shift preserved (Hue Shift Amount set to 1). - - HDR-Output-HueShift -*Image modified to show the issue clearly.* - -The right choice depends on your content, but we suggest to make sure your content is authored to work well without relying on Hue-shift. - -#### ACES - -Contrary to the neutral version, the ACES tonemapping option has fixed presets. These are meant to target screens with 1000, 2000 and 4000 nits maximum brightness. We suggest to use calibration screen to detect the right preset for the user consuming the content. - -![HDR-Output-ACES](C:\Users\franc\Documents\Github\SRP\com.unity.render-pipelines.high-definition\Documentation~\Images\HDR-Output-ACES.png) - -## - -| **Property** | **Description** | -| ---------------------- | ------------------------------------------------------------ | -| **ACES Preset** | The tonemapper preset to use. The options are:
- ACES 1000 Nits: Curve used to target 1000 nits displays (Default)
- ACES 2000 Nits: Curve used to target 2000 nits displays
- ACES 4000 Nits: Curve used to target 4000 nits displays | -| **Detect Paper White** | Whether the paper white value is detected from the data communicated by the display device. We strongly suggest to provide a calibration screen to let the user set this value depending on their screen and viewing experience. | -| **- Paper White** | Paper white value (in nits) set when it is not automatically detected from the display. | - -#### Custom - -Currently not supported by HDR Output. It is possible to decide whether to fallback on Neutral or ACES for outputting to an HDR device. - -#### External - -Not supported. Mostly because every different HDR screen used to display the content would need a different LUT. It is possible to decide whether to fallback on Neutral or ACES for outputting to an HDR device. - - - -## HDR Debug Views - -HDRP offers three debug views for HDR rendering. diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png deleted file mode 100644 index 2bbe321fe20..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-ACES.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e448f756eaf85b79ee68d01f254ce7fdaa65e272b48614c5188e9b24f4c0fb4b -size 11739 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png deleted file mode 100644 index d73c46b1b88..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-HueShift.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7c2b98f74f6d706fadd589e63998ac17e36d3beb6244fc6a1887b64aa9ed79a -size 562696 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png deleted file mode 100644 index 6d9e3fbe487..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Images/HDR-Output-Neutral.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c073e4c07f8470fa3244ebd6d3c844379b85ce5c7169f85ce480d09f919b8be6 -size 17252 diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md b/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md deleted file mode 100644 index edcb72bc32b..00000000000 --- a/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2021.2-to-2022.1.md +++ /dev/null @@ -1,7 +0,0 @@ -# Upgrading HDRP from 2021.1 to 2021.2 - -In the High Definition Render Pipeline (HDRP), some features work differently between major versions. This document helps you upgrade HDRP from 12.x to 13.x. - -## Color Grading - -Starting from HDRP 13.x, HDRP will use ACEScg as a default color space to perform color grading even when using a non-ACES if unlike the previously used sRGB color space. It is possible to go back to sRGB in the Global Settings Asset. From 7c8424734aeceb2059e62e707b1ae16b6e2368dc Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 13 Oct 2021 12:54:34 +0200 Subject: [PATCH 59/65] Warning fix and fix lut not updating upon changing color space --- .../ShaderLibrary/HDROutput.hlsl | 7 ++++--- .../Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 5e9339a26f9..7b33ca5641b 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -437,16 +437,17 @@ float3 DesaturateReducedICtCp(float3 ICtCp, float lumaPre, float maxNits) float LumaRangeReduction(float input, float minNits, float maxNits, int mode) { + float3 output = input; if (mode == HDRRANGEREDUCTION_REINHARD) { - return ReinhardTonemap(input, maxNits); + output = ReinhardTonemap(input, maxNits); } else if (mode == HDRRANGEREDUCTION_BT2390) { - return BT2390EETF(input, minNits, maxNits); + output = BT2390EETF(input, minNits, maxNits); } - return input; + return output; } float3 HuePreservingRangeReduction(float3 input, float minNits, float maxNits, int mode) 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 34a0a6ca82f..f159108c6df 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 @@ -411,7 +411,9 @@ int ComputeLUTHash() m_Curves.GetHashCode() * 23 + HDROutputIsActive().GetHashCode() #if UNITY_EDITOR - * 23 + UnityEditor.PlayerSettings.D3DHDRBitDepth.GetHashCode() + * 23 + + m_GlobalSettings.colorGradingSpace.GetHashCode() * 23 + + + UnityEditor.PlayerSettings.D3DHDRBitDepth.GetHashCode() #endif ; From 6ff1cfa7124e0f83ecd9401384efcb4966c82945 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 14 Oct 2021 13:37:59 +0200 Subject: [PATCH 60/65] Reduce code duplication in ACES --- .../ShaderLibrary/ACES.hlsl | 207 ++++++++---------- 1 file changed, 86 insertions(+), 121 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl index 6fad6bc2e82..1d16d8fa36e 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl @@ -563,6 +563,82 @@ half segmented_spline_c9_fwd(half x, SegmentedSplineParams_c9 params) 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; @@ -771,18 +847,7 @@ static const half ODT_SAT_FACTOR = 0.93; // half3 ODT_RGBmonitor_100nits_dim(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -882,18 +947,7 @@ half3 ODT_RGBmonitor_100nits_dim(half3 oces) // half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1005,18 +1059,7 @@ half3 ODT_RGBmonitor_D60sim_100nits_dim(half3 oces) // half3 ODT_Rec709_100nits_dim(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1110,18 +1153,7 @@ half3 ODT_Rec709_100nits_dim(half3 oces) // half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1233,18 +1265,7 @@ half3 ODT_Rec709_D60sim_100nits_dim(half3 oces) half3 ODT_Rec2020_100nits_dim(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1328,16 +1349,7 @@ half3 ODT_Rec2020_100nits_dim(half3 oces) // half3 ODT_P3DCI_48nits(half3 oces) { - const SegmentedSplineParams_c9 ODT_48nits = - { - { -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) // 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) - half2(segmented_spline_c5_fwd(0.18 * exp2(-6.5)), 0.02), // {luminance, luminance} linear extension below this - half2(segmented_spline_c5_fwd(0.18), 4.8), // {luminance, luminance} - half2(segmented_spline_c5_fwd(0.18 * exp2(6.5)), 48.0), // {luminance, luminance} linear extension above this - 0.0, // log-log slope of low linear extension - 0.04 // log-log slope of high linear extension - }; + const SegmentedSplineParams_c9 ODT_48nits = GetSplineParams_ODT48Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1405,25 +1417,11 @@ half3 ODT_P3DCI_48nits(half3 oces) return outputCV; } -// > 48 Nits from https://github.com/ampas/aces-dev/blob/dev/transforms/ctl/lib/ACESlib.Tonescales.ctl // 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 = - { - // 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 - }; - - + const SegmentedSplineParams_c9 ODT_1000nits = GetSplineParams_ODT1000Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1459,18 +1457,7 @@ half3 ODT_Rec2020_1000nits_ToLinear(half3 oces) half3 ODT_1000nits_ToAP1(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_1000nits = GetSplineParams_ODT1000Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1486,18 +1473,7 @@ half3 ODT_1000nits_ToAP1(half3 oces) half3 ODT_2000nits_ToAP1(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_2000nits = GetSplineParams_ODT2000Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); @@ -1513,18 +1489,7 @@ half3 ODT_2000nits_ToAP1(half3 oces) half3 ODT_4000nits_ToAP1(half3 oces) { - 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 - }; + const SegmentedSplineParams_c9 ODT_4000nits = GetSplineParams_ODT4000Nits(); // OCES to RGB rendering space half3 rgbPre = mul(AP0_2_AP1_MAT, oces); From 6d34281850a42d8ea9169a80c6883ab0b9e87e26 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 14 Oct 2021 13:45:49 +0200 Subject: [PATCH 61/65] Other review corrections --- .../ShaderLibrary/Color.hlsl | 19 +++++++++++++++++++ .../ShaderLibrary/HDROutput.hlsl | 2 +- .../PostProcessing/TonemappingEditor.cs | 2 +- .../Runtime/Debug/DebugHDR.shader | 13 +------------ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl index 97c36276ffd..16e95e80a09 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl @@ -324,6 +324,25 @@ real RotateHue(real value, real low, real hi) : value; } +// CIE xyY to CIE 1931 XYZ +float3 xyYtoXYZ(float3 xyY) +{ + float x = xyY.x; + float y = xyY.y; + float Y = xyY.z; + + float X = (Y / y) * x; + float Z = (Y / y) * (1.0 - x - y); + + return float3(X, Y, Z); +} + +// CIE 1931 XYZ to CIE xy (Y component not returned) +float2 XYZtoxy(float3 XYZ) +{ + return XYZ.xy / (dot(XYZ, 1)); +} + // 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) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 7b33ca5641b..60e39b9d190 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -481,7 +481,7 @@ float3 HueShiftingRangeReduction(float3 input, float minNits, float maxNits, int return hueShiftedResult; } -// Ref "High Dynamic Range color grading and display in Frostbite" [Fry 2017] +// 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); 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 ca0766b7e1d..8c33fb526b5 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -163,7 +163,7 @@ public override void OnInspectorGUI() int hdrTonemapMode = m_Mode.value.intValue; if (m_Mode.value.intValue == (int)TonemappingMode.Custom || hdrTonemapMode == (int)TonemappingMode.External) { - EditorGUILayout.HelpBox("The selected tonmapping mode is not supported in HDR Output mode. Select a fallback mode.", MessageType.Warning); + 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 : diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index 8feb4b6f199..6097704dff8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -95,17 +95,6 @@ Shader "Hidden/HDRP/DebugHDR" return float4(color * lineAlpha, lineAlpha); } - float3 xyYtoXYZ(float3 xyY) - { - float x = xyY[0]; - float y = xyY[1]; - float Y = xyY[2]; - - float X = (Y / y) * x; - float Z = (Y / y) * (1.0 - x - y); - - return float3(X, Y, Z); - } float2 RGBtoxy(float3 rgb) { @@ -118,7 +107,7 @@ Shader "Hidden/HDRP/DebugHDR" { XYZ = RotateRec2020ToXYZ(rgb); } - return XYZ.xy / (dot(XYZ, 1)); + return XYZtoxyY(XYZ); } float3 uvToGamut(float2 uv) From fb78e6ae29ecfc1ad0c2df3e5e1d82c5eed012b6 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Thu, 14 Oct 2021 13:52:09 +0200 Subject: [PATCH 62/65] Small issues left with previous commits --- com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl | 2 +- .../Runtime/Debug/DebugHDR.shader | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index 60e39b9d190..5accdda52b5 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -437,7 +437,7 @@ float3 DesaturateReducedICtCp(float3 ICtCp, float lumaPre, float maxNits) float LumaRangeReduction(float input, float minNits, float maxNits, int mode) { - float3 output = input; + float output = input; if (mode == HDRRANGEREDUCTION_REINHARD) { output = ReinhardTonemap(input, maxNits); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader index 6097704dff8..a5e373a4e10 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugHDR.shader @@ -107,7 +107,7 @@ Shader "Hidden/HDRP/DebugHDR" { XYZ = RotateRec2020ToXYZ(rgb); } - return XYZtoxyY(XYZ); + return XYZtoxy(XYZ); } float3 uvToGamut(float2 uv) From 9658adce60c4c3028a2cdffd8ab74c51215aa4e4 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 25 Oct 2021 11:50:02 +0200 Subject: [PATCH 63/65] Fix tooltips --- .../Runtime/PostProcessing/Components/Tonemapping.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 03f45b3b196..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 @@ -232,14 +232,14 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent 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 will not lead to equivalent images between SDR and HDR. It is suggested to manually set this value. + /// 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 will 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("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. @@ -249,12 +249,12 @@ public sealed class Tonemapping : VolumeComponent, IPostProcessComponent /// /// 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.0f 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 1000.0f with ACES Tonemap. + /// 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 minimum brightness (in nits) of the screen. Note that this is assumed to be 0.0f with ACES Tonemap.")] + [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); /// From afd9bcbc1954d58f503e2a8a4c0c7c3523728c9a Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 27 Oct 2021 14:25:59 +0200 Subject: [PATCH 64/65] Hide HDR label with no tonemap --- .../Editor/PostProcessing/TonemappingEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8c33fb526b5..96d38e5825c 100644 --- a/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/PostProcessing/TonemappingEditor.cs @@ -157,7 +157,7 @@ public override void OnInspectorGUI() PropertyField(m_UseFullACES); } - if (hdrInPlayerSettings) + if (hdrInPlayerSettings && m_Mode.value.intValue != (int)TonemappingMode.None) { EditorGUILayout.LabelField("HDR Output"); int hdrTonemapMode = m_Mode.value.intValue; From eb96d1a8d33ee63236c539d21d3677456bb80b92 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Wed, 27 Oct 2021 14:52:42 +0200 Subject: [PATCH 65/65] Disable in Metal --- .../Runtime/RenderPipeline/HDRenderPipeline.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 304f47fcfa4..f63c3ed86e6 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -201,7 +201,8 @@ internal int GetMaxScreenSpaceShadows() static bool HDROutputIsActive() { - return HDROutputSettings.main.active; + // TODO: Until we can test it, disable on Mac. + return SystemInfo.graphicsDeviceType != GraphicsDeviceType.Metal && HDROutputSettings.main.active; } void SetHDRState(HDCamera camera)