2023-09-23 14:39:09 +06:00

200 lines
6.1 KiB
HLSL

/**
* Curves
* by Christian Cann Schuldt Jensen ~ CeeJay.dk
*
* Curves, uses S-curves to increase contrast, without clipping highlights and shadows.
*/
#include "ReShadeUI.fxh"
uniform int Mode <
ui_type = "combo";
ui_items = "Luma\0Chroma\0Both Luma and Chroma\0";
ui_tooltip = "Choose what to apply contrast to.";
> = 0;
uniform int Formula <
ui_type = "combo";
ui_items = "Sine\0Abs split\0Smoothstep\0Exp formula\0Simplified Catmull-Rom (0,0,1,1)\0Perlins Smootherstep\0Abs add\0Techicolor Cinestyle\0Parabola\0Half-circles\0Polynomial split\0";
ui_tooltip = "The contrast s-curve you want to use. Note that Technicolor Cinestyle is practically identical to Sine, but runs slower. In fact I think the difference might only be due to rounding errors. I prefer 2 myself, but 3 is a nice alternative with a little more effect (but harsher on the highlight and shadows) and it's the fastest formula.";
> = 4;
uniform float Contrast < __UNIFORM_SLIDER_FLOAT1
ui_min = -1.0; ui_max = 1.0;
ui_tooltip = "The amount of contrast you want.";
> = 0.65;
#include "ReShade.fxh"
float4 CurvesPass(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
float4 colorInput = tex2D(ReShade::BackBuffer, texcoord);
float3 lumCoeff = float3(0.2126, 0.7152, 0.0722); //Values to calculate luma with
float Contrast_blend = Contrast;
const float PI = 3.1415927;
/*-----------------------------------------------------------.
/ Separation of Luma and Chroma /
'-----------------------------------------------------------*/
// -- Calculate Luma and Chroma if needed --
//calculate luma (grey)
float luma = dot(lumCoeff, colorInput.rgb);
//calculate chroma
float3 chroma = colorInput.rgb - luma;
// -- Which value to put through the contrast formula? --
// I name it x because makes it easier to copy-paste to Graphtoy or Wolfram Alpha or another graphing program
float3 x;
if (Mode == 0)
x = luma; //if the curve should be applied to Luma
else if (Mode == 1)
x = chroma, //if the curve should be applied to Chroma
x = x * 0.5 + 0.5; //adjust range of Chroma from -1 -> 1 to 0 -> 1
else
x = colorInput.rgb; //if the curve should be applied to both Luma and Chroma
/*-----------------------------------------------------------.
/ Contrast formulas /
'-----------------------------------------------------------*/
// -- Curve 1 --
if (Formula == 0)
{
x = sin(PI * 0.5 * x); // Sin - 721 amd fps, +vign 536 nv
x *= x;
//x = 0.5 - 0.5*cos(PI*x);
//x = 0.5 * -sin(PI * -x + (PI*0.5)) + 0.5;
}
// -- Curve 2 --
if (Formula == 1)
{
x = x - 0.5;
x = (x / (0.5 + abs(x))) + 0.5;
//x = ( (x - 0.5) / (0.5 + abs(x-0.5)) ) + 0.5;
}
// -- Curve 3 --
if (Formula == 2)
{
//x = smoothstep(0.0,1.0,x); //smoothstep
x = x*x*(3.0 - 2.0*x); //faster smoothstep alternative - 776 amd fps, +vign 536 nv
//x = x - 2.0 * (x - 1.0) * x* (x- 0.5); //2.0 is contrast. Range is 0.0 to 2.0
}
// -- Curve 4 --
if (Formula == 3)
{
x = (1.0524 * exp(6.0 * x) - 1.05248) / (exp(6.0 * x) + 20.0855); //exp formula
}
// -- Curve 5 --
if (Formula == 4)
{
//x = 0.5 * (x + 3.0 * x * x - 2.0 * x * x * x); //a simplified catmull-rom (0,0,1,1) - btw smoothstep can also be expressed as a simplified catmull-rom using (1,0,1,0)
//x = (0.5 * x) + (1.5 -x) * x*x; //estrin form - faster version
x = x * (x * (1.5 - x) + 0.5); //horner form - fastest version
Contrast_blend = Contrast * 2.0; //I multiply by two to give it a strength closer to the other curves.
}
// -- Curve 6 --
if (Formula == 5)
{
x = x*x*x*(x*(x*6.0 - 15.0) + 10.0); //Perlins smootherstep
}
// -- Curve 7 --
if (Formula == 6)
{
//x = ((x-0.5) / ((0.5/(4.0/3.0)) + abs((x-0.5)*1.25))) + 0.5;
x = x - 0.5;
x = x / ((abs(x)*1.25) + 0.375) + 0.5;
//x = ( (x-0.5) / ((abs(x-0.5)*1.25) + (0.5/(4.0/3.0))) ) + 0.5;
}
// -- Curve 8 --
if (Formula == 7)
{
x = (x * (x * (x * (x * (x * (x * (1.6 * x - 7.2) + 10.8) - 4.2) - 3.6) + 2.7) - 1.8) + 2.7) * x * x; //Techicolor Cinestyle - almost identical to curve 1
}
// -- Curve 9 --
if (Formula == 8)
{
x = -0.5 * (x*2.0 - 1.0) * (abs(x*2.0 - 1.0) - 2.0) + 0.5; //parabola
}
// -- Curve 10 --
if (Formula == 9)
{
float3 xstep = step(x, 0.5); //tenary might be faster here
float3 xstep_shift = (xstep - 0.5);
float3 shifted_x = x + xstep_shift;
x = abs(xstep - sqrt(-shifted_x * shifted_x + shifted_x)) - xstep_shift;
//x = abs(step(x,0.5)-sqrt(-(x+step(x,0.5)-0.5)*(x+step(x,0.5)-0.5)+(x+step(x,0.5)-0.5)))-(step(x,0.5)-0.5); //single line version of the above
//x = 0.5 + (sign(x-0.5)) * sqrt(0.25-(x-trunc(x*2))*(x-trunc(x*2))); //worse
/* // if/else - even worse
if (x-0.5)
x = 0.5-sqrt(0.25-x*x);
else
x = 0.5+sqrt(0.25-(x-1)*(x-1));
*/
//x = (abs(step(0.5,x)-clamp( 1-sqrt(1-abs(step(0.5,x)- frac(x*2%1)) * abs(step(0.5,x)- frac(x*2%1))),0 ,1))+ step(0.5,x) )*0.5; //worst so far
//TODO: Check if I could use an abs split instead of step. It might be more efficient
Contrast_blend = Contrast * 0.5; //I divide by two to give it a strength closer to the other curves.
}
// -- Curve 11 --
if (Formula == 10)
{
float3 a = float3(0.0, 0.0, 0.0);
float3 b = float3(0.0, 0.0, 0.0);
a = x * x * 2.0;
b = (2.0 * -x + 4.0) * x - 1.0;
x = (x < 0.5) ? a : b;
}
/*-----------------------------------------------------------.
/ Joining of Luma and Chroma /
'-----------------------------------------------------------*/
if (Mode == 0) // Only Luma
{
x = lerp(luma, x, Contrast_blend); //Blend by Contrast
colorInput.rgb = x + chroma; //Luma + Chroma
}
else if (Mode == 1) // Only Chroma
{
x = x * 2.0 - 1.0; //adjust the Chroma range back to -1 -> 1
float3 color = luma + x; //Luma + Chroma
colorInput.rgb = lerp(colorInput.rgb, color, Contrast_blend); //Blend by Contrast
}
else // Both Luma and Chroma
{
float3 color = x; //if the curve should be applied to both Luma and Chroma
colorInput.rgb = lerp(colorInput.rgb, color, Contrast_blend); //Blend by Contrast
}
return colorInput;
}
technique Curves
{
pass
{
VertexShader = PostProcessVS;
PixelShader = CurvesPass;
}
}