Skip to content

Commit 095a169

Browse files
committed
cColor: Fixed OKLab, added LogC4 conversion
1 parent 440de09 commit 095a169

File tree

2 files changed

+100
-35
lines changed

2 files changed

+100
-35
lines changed

shaders/cRaySchism.fx

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,29 @@
1919

2020
// Bloom-specific settings
2121
#if ENABLE_BLOOM
22-
uniform int _RenderMode <
22+
uniform int _BloomRenderMode <
2323
ui_label = "Bloom";
2424
ui_type = "combo";
2525
ui_items = "Base + Bloom\0Bloom\0";
2626
> = 0;
2727

28-
uniform float _Threshold <
28+
uniform float _BloomThreshold <
2929
ui_category = "Bloom";
3030
ui_label = "Threshold";
3131
ui_type = "slider";
3232
ui_min = 0.0;
3333
ui_max = 1.0;
3434
> = 0.8;
3535

36-
uniform float _Smooth <
36+
uniform float _BloomSmoothing <
3737
ui_category = "Bloom";
3838
ui_label = "Smoothing";
3939
ui_type = "slider";
4040
ui_min = 0.0;
4141
ui_max = 1.0;
4242
> = 0.5;
4343

44-
uniform float _Intensity <
44+
uniform float _BloomIntensity <
4545
ui_category = "Bloom";
4646
ui_label = "Intensity";
4747
ui_type = "slider";
@@ -50,7 +50,7 @@
5050
ui_max = 1.0;
5151
> = 0.5;
5252

53-
uniform float3 _ColorShift <
53+
uniform float3 _BloomColorShift <
5454
ui_category = "Bloom";
5555
ui_label = "Color Shift (RGB)";
5656
ui_type = "color";
@@ -63,37 +63,37 @@
6363
#if ENABLE_AUTOEXPOSURE
6464
uniform float _Frametime < source = "frametime"; >;
6565

66-
uniform int _Meter <
67-
ui_category = "Auto-Exposure";
66+
uniform int _ExposureMeter <
67+
ui_category = "Exposure";
6868
ui_label = "Method";
6969
ui_type = "combo";
7070
ui_items = "Average\0Spot\0";
7171
> = 0;
7272

73-
uniform float _Scale <
74-
ui_category = "Auto-Exposure";
73+
uniform float _ExposureScale <
74+
ui_category = "Exposure";
7575
ui_label = "Spot Scale";
7676
ui_type = "slider";
7777
ui_min = 0.0;
7878
ui_max = 1.0;
7979
> = 0.5;
8080

81-
uniform float2 _Offset <
82-
ui_category = "Auto-Exposure";
81+
uniform float2 _ExposureOffset <
82+
ui_category = "Exposure";
8383
ui_label = "Spot Offset";
8484
ui_type = "slider";
8585
ui_min = -1.0;
8686
ui_max = 1.0;
8787
> = 0.0;
8888

89-
uniform bool _DisplayAverageLumaOverlay <
90-
ui_category = "Auto-Exposure";
89+
uniform bool _ExposureLumaOverlay <
90+
ui_category = "Exposure";
9191
ui_label = "Display Average Luminance";
9292
ui_type = "radio";
9393
> = false;
9494

95-
uniform bool _DisplaySpotMeterOverlay <
96-
ui_category = "Auto-Exposure";
95+
uniform bool _ExposureSpotMeterOverlay <
96+
ui_category = "Exposure";
9797
ui_label = "Display Spot Metering";
9898
ui_type = "radio";
9999
> = false;
@@ -163,8 +163,8 @@
163163
#else
164164
SpotMeterTex.y /= ASPECT_RATIO;
165165
#endif
166-
SpotMeterTex *= _Scale;
167-
SpotMeterTex += float2(_Offset.x, -_Offset.y);
166+
SpotMeterTex *= _ExposureScale;
167+
SpotMeterTex += float2(_ExposureOffset.x, -_ExposureOffset.y);
168168
SpotMeterTex = (SpotMeterTex * 0.5) + 0.5;
169169

170170
return SpotMeterTex;
@@ -178,8 +178,8 @@
178178
Height conversion | [0, 1] -> [-N, N]
179179
*/
180180
float2 OverlayPos = UnormTex;
181-
OverlayPos -= float2(_Offset.x, -_Offset.y);
182-
OverlayPos /= _Scale;
181+
OverlayPos -= float2(_ExposureOffset.x, -_ExposureOffset.y);
182+
OverlayPos /= _ExposureScale;
183183

184184
// Shrink the UV so [-1, 1] fills a square
185185
#if BUFFER_WIDTH > BUFFER_HEIGHT
@@ -189,7 +189,7 @@
189189
#endif
190190

191191
// Create the needed mask; output 1 if the texcoord is within square range
192-
float Factor = 1.0 * _Scale;
192+
float Factor = 1.0 * _ExposureScale;
193193
float SquareMask = all(abs(OverlayPos) <= Factor);
194194
float DotMask = CProcedural_GetAntiAliasShape(length(OverlayPos), Factor * 0.1);
195195

@@ -250,7 +250,7 @@
250250
// Apply auto-exposure to the backbuffer
251251
#if ENABLE_AUTOEXPOSURE
252252
// Store log luminance in the alpha channel
253-
if (_Meter == 1)
253+
if (_ExposureMeter == 1)
254254
{
255255
float3 ColorArea = CShade_BackBuffer2D(GetSpotMeterTex(Input.Tex0)).rgb;
256256
Luminance = CCamera_GetLogLuminance(ColorArea.rgb);
@@ -267,18 +267,18 @@
267267
#endif
268268

269269
// Thresholding phase
270-
const float Knee = mad(_Threshold, _Smooth, 1e-5);
271-
const float3 Curve = float3(_Threshold - Knee, Knee * 2.0, 0.25 / Knee);
270+
const float Knee = mad(_BloomThreshold, _BloomSmoothing, 1e-5);
271+
const float3 Curve = float3(_BloomThreshold - Knee, Knee * 2.0, 0.25 / Knee);
272272

273273
// Under-threshold
274274
float Brightness = CColor_GetLuma(Color.rgb, 3);
275275
float ResponseCurve = clamp(Brightness - Curve.x, 0.0, Curve.y);
276276
ResponseCurve = Curve.z * ResponseCurve * ResponseCurve;
277277

278278
// Combine and apply the brightness response curve
279-
Color = Color * max(ResponseCurve, Brightness - _Threshold) / max(Brightness, 1e-10);
279+
Color = Color * max(ResponseCurve, Brightness - _BloomThreshold) / max(Brightness, 1e-10);
280280

281-
return float4(Color.rgb * _ColorShift, Luminance);
281+
return float4(Color.rgb * _BloomColorShift, Luminance);
282282
}
283283

284284
#define CREATE_PS_DOWNSCALE(METHOD_NAME, SAMPLER, FLICKER_FILTER) \
@@ -325,8 +325,8 @@ float4 PS_Composite(CShade_VS2PS_Quad Input) : SV_TARGET0
325325

326326
// Bloom composition
327327
#if ENABLE_BLOOM
328-
float3 BloomColor = tex2D(SampleTempTex1, Input.Tex0).rgb * _Intensity;
329-
BaseColor = (_RenderMode == 0) ? BaseColor + BloomColor : BloomColor;
328+
float3 BloomColor = tex2D(SampleTempTex1, Input.Tex0).rgb * _BloomIntensity;
329+
BaseColor = (_BloomRenderMode == 0) ? BaseColor + BloomColor : BloomColor;
330330
#endif
331331

332332
// Apply tonemapping
@@ -336,17 +336,17 @@ float4 PS_Composite(CShade_VS2PS_Quad Input) : SV_TARGET0
336336
#if ENABLE_AUTOEXPOSURE
337337
float2 UnormTex = (Input.Tex0 * 2.0) - 1.0;
338338

339-
if (_DisplaySpotMeterOverlay)
339+
if (_ExposureSpotMeterOverlay)
340340
{
341341
ApplySpotMeterOverlay(BaseColor, UnormTex, NonExposedColor);
342342
}
343343

344-
if (_DisplayAverageLumaOverlay)
344+
if (_ExposureLumaOverlay)
345345
{
346346
ApplyAverageLumaOverlay(BaseColor, UnormTex, ExposureData);
347347
}
348348
#endif
349-
349+
BaseColor = saturate(BaseColor);
350350
return CBlend_OutputChannels(float4(BaseColor, _CShadeAlphaFactor));
351351
}
352352

@@ -363,7 +363,6 @@ float4 PS_Composite(CShade_VS2PS_Quad Input) : SV_TARGET0
363363
RenderTarget0 = RENDER_TARGET; \
364364
}
365365

366-
367366
technique CShade_RaySchism < ui_tooltip = "CShade's Color Multi-tool."; >
368367
{
369368
#if ENABLE_BLOOM

shaders/shared/cColor.fxh

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,28 @@
122122
return Output;
123123
}
124124

125+
float3 CColor_GetRGBfromHSV(float3 HSV)
126+
{
127+
float H = HSV.x * 6.0;
128+
float S = HSV.y;
129+
float V = HSV.z;
130+
131+
float I = floor(H);
132+
float J = V * (1.0 - S);
133+
float K = V * (1.0 - S * (H - I));
134+
float L = V * (1.0 - S * (1.0 - (H - I)));
135+
float4 P = float4(V, J, K, L);
136+
137+
float3 O = 0.0;
138+
O = (I < 6) ? P.xyz : O;
139+
O = (I < 5) ? P.wyx : O;
140+
O = (I < 4) ? P.yzx : O;
141+
O = (I < 3) ? P.yxw : O;
142+
O = (I < 2) ? P.zxy : O;
143+
O = (I < 1) ? P.xwy : O;
144+
return O;
145+
}
146+
125147
float3 CColor_GetHSLfromRGB(float3 Color)
126148
{
127149
float MinRGB = min(min(Color.r, Color.g), Color.b);
@@ -232,12 +254,11 @@
232254
LMS.g = dot(Color, float3(0.2119034982, 0.6806995451, 0.1073969566));
233255
LMS.b = dot(Color, float3(0.0883024619, 0.2817188376, 0.6299787005));
234256
LMS = pow(LMS, 1.0 / 3.0);
235-
LMS = dot(Color, float3(0.2104542553, 0.7936177850, -0.0040720468));
236-
LMS = dot(Color, float3(1.9779984951, -2.4285922050, 0.4505937099));
237-
LMS = dot(Color, float3(0.0259040371, 0.7827717662, -0.8086757660));
257+
LMS.r = dot(LMS, float3(0.2104542553, 0.7936177850, -0.0040720468));
258+
LMS.g = dot(LMS, float3(1.9779984951, -2.4285922050, 0.4505937099));
259+
LMS.b = dot(LMS, float3(0.0259040371, 0.7827717662, -0.8086757660));
238260
return LMS;
239261
}
240-
241262
float3 CColor_GetOKLchFromOKLab(float3 Color)
242263
{
243264
float Pi2 = CMath_GetPi() * 2.0;
@@ -252,4 +273,49 @@
252273
{
253274
return CColor_GetOKLchFromOKLab(CColor_GetOKLabFromRGB(Color));
254275
}
276+
277+
/*
278+
LogC conversion
279+
https://www.arri.com/en/learn-help/learn-help-camera-system/image-science/log-c
280+
*/
281+
282+
struct CCamera_LogC_Constants
283+
{
284+
float A, B, C, S, T;
285+
};
286+
287+
CCamera_LogC_Constants CCamera_GetLogC_Constants()
288+
{
289+
CCamera_LogC_Constants Output;
290+
const float A = (exp2(18.0) - 16.0) / 117.45;
291+
const float B = (1023.0 - 95.0) / 1023.0;
292+
const float C = 95.0 / 1023.0;
293+
const float S = (7.0 * log(2.0) * exp2(7.0 - 14.0 * C / B)) / (A * B);
294+
const float T = (exp2(14.0 * (-C / B) + 6.0) - 64.0) / A;
295+
Output.A = A;
296+
Output.B = B;
297+
Output.C = C;
298+
Output.S = S;
299+
Output.T = T;
300+
}
301+
302+
// LogC4 Curve Encoding Function
303+
float3 CCamera_EncodeLogC(float3 Color)
304+
{
305+
CCamera_LogC_Constants LogC = CCamera_GetLogC_Constants();
306+
float3 A = (Color - LogC.T) / LogC.S;
307+
float3 B = (log2(LogC.A * Color + 64.0) - 6.0) / 14.0 * LogC.B + LogC.C;
308+
return lerp(B, A, Color < LogC.T);
309+
}
310+
311+
// LogC4 Curve Decoding Function
312+
float3 CCamera_DecodeLogC(float3 Color)
313+
{
314+
CCamera_LogC_Constants LogC = CCamera_GetLogC_Constants();
315+
float3 A = Color * LogC.S + LogC.T;
316+
float3 P = 14.0 * (Color - LogC.C) / LogC.B + 6.0;
317+
float3 B = (exp2(P) - 64.0) / LogC.A;
318+
319+
return lerp(B, A, Color < 0.0);
320+
}
255321
#endif

0 commit comments

Comments
 (0)