Skip to content

Commit

Permalink
cColor: Fixed OKLab, added LogC4 conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
papadanku committed Oct 9, 2024
1 parent 440de09 commit 095a169
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 35 deletions.
61 changes: 30 additions & 31 deletions shaders/cRaySchism.fx
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,29 @@

// Bloom-specific settings
#if ENABLE_BLOOM
uniform int _RenderMode <
uniform int _BloomRenderMode <
ui_label = "Bloom";
ui_type = "combo";
ui_items = "Base + Bloom\0Bloom\0";
> = 0;

uniform float _Threshold <
uniform float _BloomThreshold <
ui_category = "Bloom";
ui_label = "Threshold";
ui_type = "slider";
ui_min = 0.0;
ui_max = 1.0;
> = 0.8;

uniform float _Smooth <
uniform float _BloomSmoothing <
ui_category = "Bloom";
ui_label = "Smoothing";
ui_type = "slider";
ui_min = 0.0;
ui_max = 1.0;
> = 0.5;

uniform float _Intensity <
uniform float _BloomIntensity <
ui_category = "Bloom";
ui_label = "Intensity";
ui_type = "slider";
Expand All @@ -50,7 +50,7 @@
ui_max = 1.0;
> = 0.5;

uniform float3 _ColorShift <
uniform float3 _BloomColorShift <
ui_category = "Bloom";
ui_label = "Color Shift (RGB)";
ui_type = "color";
Expand All @@ -63,37 +63,37 @@
#if ENABLE_AUTOEXPOSURE
uniform float _Frametime < source = "frametime"; >;

uniform int _Meter <
ui_category = "Auto-Exposure";
uniform int _ExposureMeter <
ui_category = "Exposure";
ui_label = "Method";
ui_type = "combo";
ui_items = "Average\0Spot\0";
> = 0;

uniform float _Scale <
ui_category = "Auto-Exposure";
uniform float _ExposureScale <
ui_category = "Exposure";
ui_label = "Spot Scale";
ui_type = "slider";
ui_min = 0.0;
ui_max = 1.0;
> = 0.5;

uniform float2 _Offset <
ui_category = "Auto-Exposure";
uniform float2 _ExposureOffset <
ui_category = "Exposure";
ui_label = "Spot Offset";
ui_type = "slider";
ui_min = -1.0;
ui_max = 1.0;
> = 0.0;

uniform bool _DisplayAverageLumaOverlay <
ui_category = "Auto-Exposure";
uniform bool _ExposureLumaOverlay <
ui_category = "Exposure";
ui_label = "Display Average Luminance";
ui_type = "radio";
> = false;

uniform bool _DisplaySpotMeterOverlay <
ui_category = "Auto-Exposure";
uniform bool _ExposureSpotMeterOverlay <
ui_category = "Exposure";
ui_label = "Display Spot Metering";
ui_type = "radio";
> = false;
Expand Down Expand Up @@ -163,8 +163,8 @@
#else
SpotMeterTex.y /= ASPECT_RATIO;
#endif
SpotMeterTex *= _Scale;
SpotMeterTex += float2(_Offset.x, -_Offset.y);
SpotMeterTex *= _ExposureScale;
SpotMeterTex += float2(_ExposureOffset.x, -_ExposureOffset.y);
SpotMeterTex = (SpotMeterTex * 0.5) + 0.5;

return SpotMeterTex;
Expand All @@ -178,8 +178,8 @@
Height conversion | [0, 1] -> [-N, N]
*/
float2 OverlayPos = UnormTex;
OverlayPos -= float2(_Offset.x, -_Offset.y);
OverlayPos /= _Scale;
OverlayPos -= float2(_ExposureOffset.x, -_ExposureOffset.y);
OverlayPos /= _ExposureScale;

// Shrink the UV so [-1, 1] fills a square
#if BUFFER_WIDTH > BUFFER_HEIGHT
Expand All @@ -189,7 +189,7 @@
#endif

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

Expand Down Expand Up @@ -250,7 +250,7 @@
// Apply auto-exposure to the backbuffer
#if ENABLE_AUTOEXPOSURE
// Store log luminance in the alpha channel
if (_Meter == 1)
if (_ExposureMeter == 1)
{
float3 ColorArea = CShade_BackBuffer2D(GetSpotMeterTex(Input.Tex0)).rgb;
Luminance = CCamera_GetLogLuminance(ColorArea.rgb);
Expand All @@ -267,18 +267,18 @@
#endif

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

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

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

return float4(Color.rgb * _ColorShift, Luminance);
return float4(Color.rgb * _BloomColorShift, Luminance);
}

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

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

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

if (_DisplaySpotMeterOverlay)
if (_ExposureSpotMeterOverlay)
{
ApplySpotMeterOverlay(BaseColor, UnormTex, NonExposedColor);
}

if (_DisplayAverageLumaOverlay)
if (_ExposureLumaOverlay)
{
ApplyAverageLumaOverlay(BaseColor, UnormTex, ExposureData);
}
#endif

BaseColor = saturate(BaseColor);
return CBlend_OutputChannels(float4(BaseColor, _CShadeAlphaFactor));
}

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


technique CShade_RaySchism < ui_tooltip = "CShade's Color Multi-tool."; >
{
#if ENABLE_BLOOM
Expand Down
74 changes: 70 additions & 4 deletions shaders/shared/cColor.fxh
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,28 @@
return Output;
}

float3 CColor_GetRGBfromHSV(float3 HSV)
{
float H = HSV.x * 6.0;
float S = HSV.y;
float V = HSV.z;

float I = floor(H);
float J = V * (1.0 - S);
float K = V * (1.0 - S * (H - I));
float L = V * (1.0 - S * (1.0 - (H - I)));
float4 P = float4(V, J, K, L);

float3 O = 0.0;
O = (I < 6) ? P.xyz : O;
O = (I < 5) ? P.wyx : O;
O = (I < 4) ? P.yzx : O;
O = (I < 3) ? P.yxw : O;
O = (I < 2) ? P.zxy : O;
O = (I < 1) ? P.xwy : O;
return O;
}

float3 CColor_GetHSLfromRGB(float3 Color)
{
float MinRGB = min(min(Color.r, Color.g), Color.b);
Expand Down Expand Up @@ -232,12 +254,11 @@
LMS.g = dot(Color, float3(0.2119034982, 0.6806995451, 0.1073969566));
LMS.b = dot(Color, float3(0.0883024619, 0.2817188376, 0.6299787005));
LMS = pow(LMS, 1.0 / 3.0);
LMS = dot(Color, float3(0.2104542553, 0.7936177850, -0.0040720468));
LMS = dot(Color, float3(1.9779984951, -2.4285922050, 0.4505937099));
LMS = dot(Color, float3(0.0259040371, 0.7827717662, -0.8086757660));
LMS.r = dot(LMS, float3(0.2104542553, 0.7936177850, -0.0040720468));
LMS.g = dot(LMS, float3(1.9779984951, -2.4285922050, 0.4505937099));
LMS.b = dot(LMS, float3(0.0259040371, 0.7827717662, -0.8086757660));
return LMS;
}

float3 CColor_GetOKLchFromOKLab(float3 Color)
{
float Pi2 = CMath_GetPi() * 2.0;
Expand All @@ -252,4 +273,49 @@
{
return CColor_GetOKLchFromOKLab(CColor_GetOKLabFromRGB(Color));
}

/*
LogC conversion
https://www.arri.com/en/learn-help/learn-help-camera-system/image-science/log-c
*/

struct CCamera_LogC_Constants
{
float A, B, C, S, T;
};

CCamera_LogC_Constants CCamera_GetLogC_Constants()
{
CCamera_LogC_Constants Output;
const float A = (exp2(18.0) - 16.0) / 117.45;
const float B = (1023.0 - 95.0) / 1023.0;
const float C = 95.0 / 1023.0;
const float S = (7.0 * log(2.0) * exp2(7.0 - 14.0 * C / B)) / (A * B);
const float T = (exp2(14.0 * (-C / B) + 6.0) - 64.0) / A;
Output.A = A;
Output.B = B;
Output.C = C;
Output.S = S;
Output.T = T;
}

// LogC4 Curve Encoding Function
float3 CCamera_EncodeLogC(float3 Color)
{
CCamera_LogC_Constants LogC = CCamera_GetLogC_Constants();
float3 A = (Color - LogC.T) / LogC.S;
float3 B = (log2(LogC.A * Color + 64.0) - 6.0) / 14.0 * LogC.B + LogC.C;
return lerp(B, A, Color < LogC.T);
}

// LogC4 Curve Decoding Function
float3 CCamera_DecodeLogC(float3 Color)
{
CCamera_LogC_Constants LogC = CCamera_GetLogC_Constants();
float3 A = Color * LogC.S + LogC.T;
float3 P = 14.0 * (Color - LogC.C) / LogC.B + 6.0;
float3 B = (exp2(P) - 64.0) / LogC.A;

return lerp(B, A, Color < 0.0);
}
#endif

0 comments on commit 095a169

Please sign in to comment.