Shader "Hidden/PostProcessing/Lut2DBaker" { HLSLINCLUDE #pragma target 3.0 #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl" #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/Colors.hlsl" #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/ACES.hlsl" TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex); float4 _Lut2D_Params; float4 _UserLut2D_Params; float3 _ColorBalance; float3 _ColorFilter; float3 _HueSatCon; float _Brightness; // LDR only float3 _ChannelMixerRed; float3 _ChannelMixerGreen; float3 _ChannelMixerBlue; float3 _Lift; float3 _InvGamma; float3 _Gain; TEXTURE2D_SAMPLER2D(_Curves, sampler_Curves); float4 _CustomToneCurve; float4 _ToeSegmentA; float4 _ToeSegmentB; float4 _MidSegmentA; float4 _MidSegmentB; float4 _ShoSegmentA; float4 _ShoSegmentB; float3 ApplyCommonGradingSteps(float3 colorLinear) { colorLinear = WhiteBalance(colorLinear, _ColorBalance); colorLinear *= _ColorFilter; colorLinear = ChannelMixer(colorLinear, _ChannelMixerRed, _ChannelMixerGreen, _ChannelMixerBlue); colorLinear = LiftGammaGainHDR(colorLinear, _Lift, _InvGamma, _Gain); // Do NOT feed negative values to RgbToHsv or they'll wrap around colorLinear = max((float3)0.0, colorLinear); float3 hsv = RgbToHsv(colorLinear); // Hue Vs Sat float satMult; satMult = saturate(SAMPLE_TEXTURE2D_LOD(_Curves, sampler_Curves, float2(hsv.x, 0.25), 0).y) * 2.0; // Sat Vs Sat satMult *= saturate(SAMPLE_TEXTURE2D_LOD(_Curves, sampler_Curves, float2(hsv.y, 0.25), 0).z) * 2.0; // Lum Vs Sat satMult *= saturate(SAMPLE_TEXTURE2D_LOD(_Curves, sampler_Curves, float2(Luminance(colorLinear), 0.25), 0).w) * 2.0; // Hue Vs Hue float hue = hsv.x + _HueSatCon.x; float offset = saturate(SAMPLE_TEXTURE2D_LOD(_Curves, sampler_Curves, float2(hue, 0.25), 0).x) - 0.5; hue += offset; hsv.x = RotateHue(hue, 0.0, 1.0); colorLinear = HsvToRgb(hsv); colorLinear = Saturation(colorLinear, _HueSatCon.y * satMult); return colorLinear; } // // LDR Grading process // float3 ColorGradeLDR(float3 colorLinear) { // Brightness is a simple linear multiplier. Works better in LDR than using e.v. colorLinear *= _Brightness; // Contrast is done in linear, switching to log for that in LDR is pointless and doesn't // feel as good to tweak const float kMidGrey = pow(0.5, 2.2); colorLinear = Contrast(colorLinear, kMidGrey, _HueSatCon.z); colorLinear = ApplyCommonGradingSteps(colorLinear); // YRGB only works in LDR for now as we don't do any curve range remapping colorLinear = YrgbCurve(saturate(colorLinear), TEXTURE2D_PARAM(_Curves, sampler_Curves)); return saturate(colorLinear); } float4 FragLDRFromScratch(VaryingsDefault i) : SV_Target { float3 colorLinear = GetLutStripValue(i.texcoordStereo, _Lut2D_Params); float3 graded = ColorGradeLDR(colorLinear); return float4(graded, 1.0); } float4 FragLDR(VaryingsDefault i) : SV_Target { // Note: user luts may not have the same size as the internal one float3 neutralColorLinear = GetLutStripValue(i.texcoordStereo, _Lut2D_Params); float3 lookup = ApplyLut2D(TEXTURE2D_PARAM(_MainTex, sampler_MainTex), neutralColorLinear, _UserLut2D_Params.xyz); float3 colorLinear = lerp(neutralColorLinear, lookup, _UserLut2D_Params.w); float3 graded = ColorGradeLDR(colorLinear); return float4(graded, 1.0); } // // HDR Grading process // float3 LogGradeHDR(float3 colorLog) { // HDR contrast feels a lot more natural when done in log rather than doing it in linear colorLog = Contrast(colorLog, ACEScc_MIDGRAY, _HueSatCon.z); return colorLog; } float3 LinearGradeHDR(float3 colorLinear) { colorLinear = ApplyCommonGradingSteps(colorLinear); return colorLinear; } float3 ColorGradeHDR(float3 colorLutSpace) { #if TONEMAPPING_ACES { float3 colorLinear = LUT_SPACE_DECODE(colorLutSpace); float3 aces = unity_to_ACES(colorLinear); // ACEScc (log) space float3 acescc = ACES_to_ACEScc(aces); acescc = LogGradeHDR(acescc); aces = ACEScc_to_ACES(acescc); // ACEScg (linear) space float3 acescg = ACES_to_ACEScg(aces); acescg = LinearGradeHDR(acescg); // Tonemap ODT(RRT(aces)) aces = ACEScg_to_ACES(acescg); colorLinear = AcesTonemap(aces); return colorLinear; } #else { // colorLutSpace is already in log space colorLutSpace = LogGradeHDR(colorLutSpace); // Switch back to linear float3 colorLinear = LUT_SPACE_DECODE(colorLutSpace); colorLinear = LinearGradeHDR(colorLinear); colorLinear = max(0.0, colorLinear); // Tonemap #if TONEMAPPING_NEUTRAL { colorLinear = NeutralTonemap(colorLinear); } #elif TONEMAPPING_CUSTOM { colorLinear = CustomTonemap( colorLinear, _CustomToneCurve.xyz, _ToeSegmentA, _ToeSegmentB.xy, _MidSegmentA, _MidSegmentB.xy, _ShoSegmentA, _ShoSegmentB.xy ); } #endif return colorLinear; } #endif } float4 FragHDR(VaryingsDefault i) : SV_Target { float3 colorLutSpace = GetLutStripValue(i.texcoord, _Lut2D_Params); float3 graded = ColorGradeHDR(colorLutSpace); return float4(max(graded, 0.0), 1.0); } ENDHLSL SubShader { Cull Off ZWrite Off ZTest Always Pass { HLSLPROGRAM #pragma vertex VertDefault #pragma fragment FragLDRFromScratch ENDHLSL } Pass { HLSLPROGRAM #pragma vertex VertDefault #pragma fragment FragLDR ENDHLSL } Pass { HLSLPROGRAM #pragma vertex VertDefault #pragma fragment FragHDR #pragma multi_compile __ TONEMAPPING_ACES TONEMAPPING_NEUTRAL TONEMAPPING_CUSTOM ENDHLSL } } }