mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-11 06:15:05 +00:00
26a76e0451
There is hardly any reason for us to recalculate everything all the time. LUTs can cache the work once, and then re-use it every time necessary, drastically reducing the impact of Color Grading by almost 60% (on some GPUs even more). Additionally this fixes the negative gamma issue, which plagued the filter for a while. In the future, once PR 4199 (https://github.com/obsproject/obs-studio/pull/4199) has been merged, we can cut away one intermediate rendering step currently required to make the effect work. Hopefully this will be with the 27.x release of OBS Studio.
140 lines
3.8 KiB
Text
140 lines
3.8 KiB
Text
#include "shared.effect"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Uniforms
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Texture to which the effect is applied to.
|
|
uniform texture2d image;
|
|
|
|
// Lift: (rgb + lift.rgb) + lift.a
|
|
uniform float4 pLift;
|
|
|
|
// Gamma: pow(pow(rgb, gamma.rgb), gamma.a)
|
|
uniform float4 pGamma;
|
|
|
|
// Gain: mul(rgb, gain.rgb) * gain.a
|
|
uniform float4 pGain;
|
|
|
|
// Offset: (rgb + offset.rgb) + offset.a
|
|
uniform float4 pOffset;
|
|
|
|
// Tinting
|
|
uniform int pTintDetection; // 0 = HSV, 1 = HSL, 2 = YUV HD SDR
|
|
uniform int pTintMode; // 0 = Linear, 1 = Exp, 2 = Exp2, 3 = Log, 4 = Log10
|
|
uniform float pTintExponent;
|
|
uniform float3 pTintLow;
|
|
uniform float3 pTintMid;
|
|
uniform float3 pTintHig;
|
|
|
|
// Color Correction
|
|
uniform float4 pCorrection;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Defines
|
|
//------------------------------------------------------------------------------
|
|
#define TINT_DETECTION_HSV 0
|
|
#define TINT_DETECTION_HSL 1
|
|
#define TINT_DETECTION_YUV_SDR 2
|
|
|
|
#define TINT_MODE_LINEAR 0
|
|
#define TINT_MODE_EXP 1
|
|
#define TINT_MODE_EXP2 2
|
|
#define TINT_MODE_LOG 3
|
|
#define TINT_MODE_LOG10 4
|
|
|
|
#define C_e 2,7182818284590452353602874713527
|
|
#define C_log2_e 1.4426950408889634073599246810019 // Windows calculator: log(e(1)) / log(2)
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Functionality
|
|
//------------------------------------------------------------------------------
|
|
|
|
float3 grade_lift(float3 v) { // same as grade_offset?
|
|
return (v.rgb + pLift.rgb) + pLift.a;
|
|
};
|
|
|
|
float3 grade_gamma(float3 v) {
|
|
float3 s = sign(v); // Store sign for later use.
|
|
float3 u = abs(v); // Remove sign
|
|
u.rgb = pow(pow(u.rgb, pGamma.rgb), pGamma.a);
|
|
return u * s; // Restore sign.
|
|
};
|
|
|
|
float3 grade_gain(float3 v) {
|
|
return (v.rgb * pGain.rgb) * pGain.a;
|
|
};
|
|
|
|
float3 grade_offset(float3 v) {
|
|
return (v.rgb + pOffset.rgb) + pOffset.a;
|
|
};
|
|
|
|
float3 grade_tint(float3 v) {
|
|
float value = 0.;
|
|
if (pTintDetection == TINT_DETECTION_HSV) { // HSV
|
|
value = RGBtoHSV(v).z;
|
|
} else if (pTintDetection == TINT_DETECTION_HSL) { // HSL
|
|
value = RGBtoHSL(v).z;
|
|
} else if (pTintDetection == TINT_DETECTION_YUV_SDR) { // YUV HD SDR
|
|
const float3x3 mYUV709n = { // Normalized
|
|
0.2126, 0.7152, 0.0722,
|
|
-0.1145721060573399, -0.3854278939426601, 0.5,
|
|
0.5, -0.4541529083058166, -0.0458470916941834
|
|
};
|
|
value = RGBtoYUV(v, mYUV709n).r;
|
|
}
|
|
|
|
if (pTintMode == TINT_MODE_LINEAR) { // Linear
|
|
} else if (pTintMode == TINT_MODE_EXP) { // Exp
|
|
value = 1.0 - exp2(value * pTintExponent * -C_log2_e);
|
|
} else if (pTintMode == TINT_MODE_EXP2) { // Exp2
|
|
value = 1.0 - exp2(value * value * pTintExponent * pTintExponent * -C_log2_e);
|
|
} else if (pTintMode == TINT_MODE_LOG) { // Log
|
|
value = (log2(value) + 2.) / 2.333333;
|
|
} else if (pTintMode == TINT_MODE_LOG10) { // Log10
|
|
value = (log10(value) + 1.) / 2.;
|
|
}
|
|
|
|
float3 tint = float3(0,0,0);
|
|
if (value > 0.5) {
|
|
tint = lerp(pTintMid, pTintHig, value * 2.0 - 1.0);
|
|
} else {
|
|
tint = lerp(pTintLow, pTintMid, value * 2.0);
|
|
}
|
|
v.rgb *= tint;
|
|
return v;
|
|
};
|
|
|
|
float3 grade_colorcorrection(float3 v) {
|
|
float3 v1 = RGBtoHSV(v);
|
|
v1.r += pCorrection.r; // Hue Shift
|
|
v1.g *= pCorrection.g; // Saturation Multiplier
|
|
v1.b *= pCorrection.b; // Lightness Multiplier
|
|
float3 v2 = HSVtoRGB(v1);
|
|
|
|
// Contrast
|
|
v2.rgb = ((v2.rgb - 0.5) * max(pCorrection.a, 0)) + 0.5;
|
|
|
|
return v2;
|
|
};
|
|
|
|
float4 PSDraw(VertexData vtx) : TARGET {
|
|
float4 v1 = image.Sample(PointClampSampler, vtx.uv);
|
|
float3 v2 = grade_lift(v1.rgb);
|
|
float3 v3 = grade_gamma(v2);
|
|
float3 v4 = grade_gain(v3);
|
|
float3 v5 = grade_offset(v4);
|
|
float3 v6 = grade_tint(v5);
|
|
float3 v7 = grade_colorcorrection(v6);
|
|
float3 vf = v7;
|
|
return float4(vf, v1.a);
|
|
};
|
|
|
|
technique Draw
|
|
{
|
|
pass
|
|
{
|
|
vertex_shader = DefaultVertexShader(vtx);
|
|
pixel_shader = PSDraw(vtx);
|
|
};
|
|
};
|