1 #include "../StdLib.hlsl"
2 #include "../Colors.hlsl"
3 #include "../ACES.hlsl"
5 #pragma kernel KGenLut3D_NoTonemap TONEMAPPING_NONE
6 #pragma kernel KGenLut3D_AcesTonemap TONEMAPPING_ACES
7 #pragma kernel KGenLut3D_NeutralTonemap TONEMAPPING_NEUTRAL
8 #pragma kernel KGenLut3D_CustomTonemap TONEMAPPING_CUSTOM
10 RWTexture3D<float4> _Output;
13 float4 _Size; // x: lut_size, y: 1 / (lut_size - 1), zw: unused
19 float4 _ChannelMixerRed;
20 float4 _ChannelMixerGreen;
21 float4 _ChannelMixerBlue;
27 float4 _CustomToneCurve;
29 // Packing is currently borked, can't pass float arrays without it creating one vector4 per
30 // float so we'll pack manually...
40 SamplerState sampler_Curves;
42 float3 LogGrade(float3 colorLog)
44 // Contrast feels a lot more natural when done in log rather than doing it in linear
45 colorLog = Contrast(colorLog, ACEScc_MIDGRAY, _HueSatCon.z);
50 float3 LinearGrade(float3 colorLinear)
52 colorLinear = WhiteBalance(colorLinear, _ColorBalance.rgb);
53 colorLinear *= _ColorFilter.rgb;
54 colorLinear = ChannelMixer(colorLinear, _ChannelMixerRed.rgb, _ChannelMixerGreen.rgb, _ChannelMixerBlue.rgb);
55 colorLinear = LiftGammaGainHDR(colorLinear, _Lift.rgb, _InvGamma.rgb, _Gain.rgb);
57 // Do NOT feed negative values to RgbToHsv or they'll wrap around
58 colorLinear = max(0.0, colorLinear);
60 float3 hsv = RgbToHsv(colorLinear);
64 satMult = saturate(_Curves.SampleLevel(sampler_Curves, float2(hsv.x, 0.25), 0).y) * 2.0;
67 satMult *= saturate(_Curves.SampleLevel(sampler_Curves, float2(hsv.y, 0.25), 0).z) * 2.0;
70 satMult *= saturate(_Curves.SampleLevel(sampler_Curves, float2(Luminance(colorLinear), 0.25), 0).w) * 2.0;
73 float hue = hsv.x + _HueSatCon.x;
74 float offset = saturate(_Curves.SampleLevel(sampler_Curves, float2(hue, 0.25), 0).x) - 0.5;
76 hsv.x = RotateHue(hue, 0.0, 1.0);
78 colorLinear = HsvToRgb(hsv);
79 colorLinear = Saturation(colorLinear, _HueSatCon.y * satMult);
86 float3 ColorGrade(float3 colorLutSpace)
88 float3 colorLinear = LUT_SPACE_DECODE(colorLutSpace);
89 float3 aces = unity_to_ACES(colorLinear);
92 float3 acescc = ACES_to_ACEScc(aces);
93 acescc = LogGrade(acescc);
94 aces = ACEScc_to_ACES(acescc);
96 // ACEScg (linear) space
97 float3 acescg = ACES_to_ACEScg(aces);
98 acescg = LinearGrade(acescg);
100 // Tonemap ODT(RRT(aces))
101 aces = ACEScg_to_ACES(acescg);
102 colorLinear = AcesTonemap(aces);
109 float3 ColorGrade(float3 colorLutSpace)
111 // colorLutSpace is already in log space
112 colorLutSpace = LogGrade(colorLutSpace);
114 // Switch back to linear
115 float3 colorLinear = LUT_SPACE_DECODE(colorLutSpace);
116 colorLinear = LinearGrade(colorLinear);
117 colorLinear = max(0.0, colorLinear);
120 #if TONEMAPPING_NEUTRAL
122 colorLinear = NeutralTonemap(colorLinear);
124 #elif TONEMAPPING_CUSTOM
126 colorLinear = CustomTonemap(
127 colorLinear, _CustomToneCurve.xyz,
128 _ToeSegmentA, _ToeSegmentB.xy,
129 _MidSegmentA, _MidSegmentB.xy,
130 _ShoSegmentA, _ShoSegmentB.xy
142 if (float(id.x) < _Size.x && float(id.y) < _Size.x && float(id.z) < _Size.x)
144 // Lut space (log space)
145 float3 colorLutSpace = float3(id) * _Size.y;
147 // Color grade & tonemap
148 float3 graded = ColorGrade(colorLutSpace);
150 _Output[id] = float4(max(graded, 0.0), 1.0);
156 #ifdef DISABLE_COMPUTE_SHADERS
158 TRIVIAL_COMPUTE_KERNEL(KGenLut3D_NoTonemap)
159 TRIVIAL_COMPUTE_KERNEL(KGenLut3D_AcesTonemap)
160 TRIVIAL_COMPUTE_KERNEL(KGenLut3D_NeutralTonemap)
161 TRIVIAL_COMPUTE_KERNEL(KGenLut3D_CustomTonemap)
165 [numthreads(GROUP_SIZE, GROUP_SIZE, GROUP_SIZE)]
166 void KGenLut3D_NoTonemap(uint3 id : SV_DispatchThreadID) { Eval(id); }
168 [numthreads(GROUP_SIZE, GROUP_SIZE, GROUP_SIZE)]
169 void KGenLut3D_AcesTonemap(uint3 id : SV_DispatchThreadID) { Eval(id); }
171 [numthreads(GROUP_SIZE, GROUP_SIZE, GROUP_SIZE)]
172 void KGenLut3D_NeutralTonemap(uint3 id : SV_DispatchThreadID) { Eval(id); }
174 [numthreads(GROUP_SIZE, GROUP_SIZE, GROUP_SIZE)]
175 void KGenLut3D_CustomTonemap(uint3 id : SV_DispatchThreadID) { Eval(id); }
177 #endif // DISABLE_COMPUTE_SHADERS