From a989709b6f19e254f86ff02d92c2012303781894 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sat, 11 Apr 2020 22:32:36 +0200 Subject: [PATCH] examples: Fix some example shaders and add new ones * Fixed 'Pixelator's color transition point being off-center and uncontrollable. * Fixed 'Drunk' filter not working at all. * Added an inverted mode to 'Luma Burn'. * Added exponential Luma to 'Luma Burn'. * Fixed odd color behavior in the 'Color Shift' transition by switching out HSL with HSV. * Added a new 'Sliding Bars' transition shader, for an example of it see this clip: https://clips.twitch.tv/RacyEndearingHorseradishAMPTropPunch . --- data/examples/shaders/filter/drunk.effect | 54 +++--- .../shaders/transition/color-shift.effect | 62 ++----- .../shaders/transition/luma-burn.effect | 58 +++++- .../shaders/transition/pixelator.effect | 16 +- .../shaders/transition/sliding-bars.effect | 175 ++++++++++++++++++ 5 files changed, 284 insertions(+), 81 deletions(-) create mode 100644 data/examples/shaders/transition/sliding-bars.effect diff --git a/data/examples/shaders/filter/drunk.effect b/data/examples/shaders/filter/drunk.effect index 550ecc7f..d91105ef 100644 --- a/data/examples/shaders/filter/drunk.effect +++ b/data/examples/shaders/filter/drunk.effect @@ -15,22 +15,17 @@ uniform float4x4 Random< string name = "Random Array"; string description = "A float4x4 value containing random values between 0 and 1"; >; -uniform texture2d ImageSource< - bool visible = false; - string name = "Source Texture (Filter, Transition)"; +uniform float4 ViewSize< + bool automatic = true; >; -uniform float2 ImageSource_Size< - bool visible = false; - string name = "Source Texture Size (Filter, Transition)"; ->; -uniform float2 ImageSource_Texel< - bool visible = false; - string name = "Source Texture Texel Size (Filter, Transition)"; +uniform texture2d InputA< + bool automatic = true; >; // Shader Parameters uniform float p_drunk_strength< bool visible = true; + string field_type = "slider"; string name = "Strength"; float minimum = 0.; float maximum = 100.; @@ -38,6 +33,7 @@ uniform float p_drunk_strength< > = 25.0; uniform float p_drunk_speed< bool visible = true; + string field_type = "slider"; string name = "Speed"; float minimum = 0.; float maximum = 100.; @@ -56,19 +52,11 @@ struct VertData { float2 uv : TEXCOORD0; }; -struct FragData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -FragData VSDefault(VertData v_in) { - FragData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv; - return vert_out; +VertData VSDefault(VertData vtx) { + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; } -// ---------- Fixed Color #define MAX_PTS 5 #define MAX_LINE 5. @@ -96,30 +84,30 @@ float2 mult_at(int x, int y) { return mult; } -float4 PS_Drunk(FragData v_in) : TARGET { - float2 uvs[MAX_PTS + 1][MAX_PTS + 1]; +float4 PSDrunkStage1(VertData vtx) : TARGET { + float2 uvs[MAX_PTS + 1][MAX_PTS + 1]; for (int x = 0; x <= MAX_PTS; x++) { for (int y = 0; y <= MAX_PTS; y++) { float2 off = float2(0, 0); if ((x > 0) && (x < MAX_PTS)) { - off.x = cos(Time.y * p_drunk_speed + random_time_at(x, y)) * ImageSource_Texel.x; + off.x = cos(Time.x * p_drunk_speed + random_time_at(x, y)) * ViewSize.z; } if ((y > 0) && (y < MAX_PTS)) { - off.y = sin(Time.y * p_drunk_speed + random_time_at(x, y)) * ImageSource_Texel.y; + off.y = sin(Time.x * p_drunk_speed + random_time_at(x, y)) * ViewSize.w; } - off *= (p_drunk_strength / 100.0) * ImageSource_Size * 0.5 * mult_at(x, y); + off *= (p_drunk_strength / 100.0) * ViewSize.xy * 0.5 * mult_at(x, y); uvs[x][y] = float2(x / MAX_LINE + off.x, y / MAX_LINE + off.y); } } - float2 fade = frac(v_in.uv * MAX_LINE); + float2 fade = frac(vtx.uv * MAX_LINE); fade = (sin((fade - 0.5) * 3.141) + 1.0) * 0.5; - int2 _low = int2(floor(v_in.uv * MAX_LINE)); - int2 _hig = int2(ceil(v_in.uv * MAX_LINE)); + int2 _low = int2(floor(vtx.uv * MAX_LINE)); + int2 _hig = int2(ceil(vtx.uv * MAX_LINE)); - float2 uv = v_in.uv; + float2 uv = vtx.uv; float2 uv_tl = uvs[_low.x][_low.y]; float2 uv_tr = uvs[_hig.x][_low.y]; float2 uv_bl = uvs[_low.x][_hig.y]; @@ -129,14 +117,14 @@ float4 PS_Drunk(FragData v_in) : TARGET { float2 uv_b = lerp(uv_bl, uv_br, fade.x); uv = lerp(uv_t, uv_b, fade.y); - return ImageSource.Sample(def_sampler, uv); + return InputA.Sample(def_sampler, uv); } technique Draw { pass { - vertex_shader = VSDefault(v_in); - pixel_shader = PS_Drunk(v_in); + vertex_shader = VSDefault(vtx); + pixel_shader = PSDrunkStage1(vtx); } } diff --git a/data/examples/shaders/transition/color-shift.effect b/data/examples/shaders/transition/color-shift.effect index 4b25f1c7..d0ff7c82 100644 --- a/data/examples/shaders/transition/color-shift.effect +++ b/data/examples/shaders/transition/color-shift.effect @@ -56,59 +56,29 @@ VertData VSDefault(VertData v_in) { return vert_out; } -float4 HSLtoRGB(float4 HSLA) { - float3 rgb = clamp( - abs( - fmod( - HSLA.x * 6.0 + float3(0.0, 4.0, 2.0), - 6.0 - ) - 3.0 - ) - 1.0, - 0.0, - 1.0 - ); - return float4(HSLA.z + HSLA.y * (rgb - 0.5) * (1.0 - abs(2.0 * HSLA.z - 1.0)), HSLA.a); +float4 RGBtoHSV(float4 RGBA) { + const float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + const float e = 1.0e-10; + float4 p = lerp(float4(RGBA.bg, K.wz), float4(RGBA.gb, K.xy), step(RGBA.b, RGBA.g)); + float4 q = lerp(float4(p.xyw, RGBA.r), float4(RGBA.r, p.yzx), step(p.x, RGBA.r)); + float d = q.x - min(q.w, q.y); + return float4(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x, RGBA.a); } -float4 RGBtoHSL(float4 RGBA) { - float h = 0.0; - float s = 0.0; - float l = 0.0; - float r = RGBA.r; - float g = RGBA.g; - float b = RGBA.b; - float cMin = min( r, min( g, b ) ); - float cMax = max( r, max( g, b ) ); - - l = ( cMax + cMin ) / 2.0; - if ( cMax > cMin ) { - float cDelta = cMax - cMin; - - //s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original - s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); - - if ( r == cMax ) { - h = ( g - b ) / cDelta; - } else if ( g == cMax ) { - h = 2.0 + ( b - r ) / cDelta; - } else { - h = 4.0 + ( r - g ) / cDelta; - } - - if ( h < 0.0) { - h += 6.0; - } - h = h / 6.0; - } - return float4( h, s, l, RGBA.a ); +float4 HSVtoRGB(float4 HSVA) { + const float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float4 v = float4(0,0,0,0); + v.rgb = HSVA.z * lerp(K.xxx, clamp(abs(frac(HSVA.xxx + K.xyz) * 6.0 - K.www) - K.xxx, 0.0, 1.0), HSVA.y); + v.a = HSVA.a; + return v; } float4 PSDefault(VertData v_in) : TARGET { float4 sampleA = InputA.Sample(def_sampler, v_in.uv); float4 sampleB = InputB.Sample(def_sampler, v_in.uv); - float4 hslA = RGBtoHSL(sampleA); - float4 hslB = RGBtoHSL(sampleB); + float4 hslA = RGBtoHSV(sampleA); + float4 hslB = RGBtoHSV(sampleB); float4 hslT = hslB - hslA; if (hslT.r > 0.5) { hslB.r = 1.0 + (-1.0 + hslB.r); @@ -120,7 +90,7 @@ float4 PSDefault(VertData v_in) : TARGET { hslB.b = 1.0 + (-1.0 + hslB.b); } - float4 rgb = HSLtoRGB(lerp(hslA, hslB, TransitionTime)); + float4 rgb = HSVtoRGB(lerp(hslA, hslB, TransitionTime)); return rgb; } diff --git a/data/examples/shaders/transition/luma-burn.effect b/data/examples/shaders/transition/luma-burn.effect index 4ce8fdd0..89708774 100644 --- a/data/examples/shaders/transition/luma-burn.effect +++ b/data/examples/shaders/transition/luma-burn.effect @@ -37,6 +37,18 @@ uniform float Sharpness< float scale = 1.0; > = 10.0; +uniform bool LumaIsExponential< + string name = "Is Luminosity exponential?"; +>; +uniform float LumaExponent< + string name = "Luminosity Exponent"; + string field_type = "slider"; + float minimum = 0.; + float maximum = 500.; + float step = .01; + float scale = .01; +> = 150.; + // ---------- Shader Code sampler_state def_sampler { AddressU = Clamp; @@ -65,6 +77,9 @@ float4 RGBtoYUV(float4 rgba, float3x3 yuv) { ) + float4(0,0.5,0.5,0); } +#define C_e 2,7182818284590452353602874713527 +#define C_log2_e 1.4426950408889634073599246810019 // Windows calculator: log(e(1)) / log(2) + float4 PSDefault(VertData v_in) : TARGET { const float3x3 mYUV709n = { // Normalized 0.2126, 0.7152, 0.0722, @@ -79,7 +94,11 @@ float4 PSDefault(VertData v_in) : TARGET { float4 sampleBYUV = RGBtoYUV(sampleB, mYUV709n); float sharpinv = 1.0 / Sharpness; - float transition = sharpinv + sampleAYUV.r * (1.0 - sharpinv); + float luma = sampleAYUV.r; + if (LumaIsExponential) { + luma = exp2(luma * LumaExponent * LumaExponent * -C_log2_e); + } + float transition = sharpinv + luma * (1.0 - sharpinv); transition -= TransitionTime; transition *= Sharpness; transition += 0.5; @@ -97,3 +116,40 @@ technique Draw pixel_shader = PSDefault(v_in); } } + +float4 PSInverse(VertData v_in) : TARGET { + const float3x3 mYUV709n = { // Normalized + 0.2126, 0.7152, 0.0722, + -0.1145721060573399, -0.3854278939426601, 0.5, + 0.5, -0.4541529083058166, -0.0458470916941834 + }; + + float4 sampleA = InputA.Sample(def_sampler, v_in.uv); + float4 sampleB = InputB.Sample(def_sampler, v_in.uv); + + float4 sampleAYUV = RGBtoYUV(sampleA, mYUV709n); + float4 sampleBYUV = RGBtoYUV(sampleB, mYUV709n); + + float sharpinv = 1.0 / Sharpness; + float luma = (1.0 - sampleAYUV.r); + if (LumaIsExponential) { + luma = exp2(luma * LumaExponent * LumaExponent * -C_log2_e); + } + float transition = sharpinv + luma * (1.0 - sharpinv); + transition -= TransitionTime; + transition *= Sharpness; + transition += 0.5; + transition = clamp(transition, 0., 1.); + + return sampleB * (1.0 - transition) + sampleA * (transition); + //return transition; +} + +technique DrawInverse +{ + pass + { + vertex_shader = VSDefault(v_in); + pixel_shader = PSInverse(v_in); + } +} diff --git a/data/examples/shaders/transition/pixelator.effect b/data/examples/shaders/transition/pixelator.effect index 4ae8b0a8..e2c4b547 100644 --- a/data/examples/shaders/transition/pixelator.effect +++ b/data/examples/shaders/transition/pixelator.effect @@ -56,6 +56,14 @@ uniform float2 _3_blockOffset< float2 maximum = {100., 100.}; float2 scale = {0.01, 0.01}; > = {50., 50.}; +uniform float _4_transitionRange< + string name = "Transition Range"; + string field_type = "slider"; + float minimum = 0.; + float maximum = 100.; + float scale = .005; + float step = .01; +> = 25.0; // ---------- Shader Code sampler_state def_sampler { @@ -104,7 +112,13 @@ float4 PSDefault(VertData v_in) : TARGET { float4 sampleA = InputA.Sample(def_sampler, finalUV); float4 sampleB = InputB.Sample(def_sampler, finalUV); - float4 rgb = lerp(sampleA, sampleB, clamp((TransitionTime - 0.45) * (1.0 / 0.45), 0., 1.)); + float transition = clamp( + ((TransitionTime - 0.5) / _4_transitionRange) * .5 + .5, + 0., + 1. + ); + + float4 rgb = lerp(sampleA, sampleB, transition); return rgb; } diff --git a/data/examples/shaders/transition/sliding-bars.effect b/data/examples/shaders/transition/sliding-bars.effect new file mode 100644 index 00000000..29ca0090 --- /dev/null +++ b/data/examples/shaders/transition/sliding-bars.effect @@ -0,0 +1,175 @@ +// Always provided by OBS +uniform float4x4 ViewProj< + bool automatic = true; + string name = "View Projection Matrix"; +>; + +// Provided by Stream Effects +uniform float4 Time< + bool automatic = true; + string name = "Time Array"; + string description = "A float4 value containing the total time, rendering time and the time since the last tick. The last value is a random number between 0 and 1."; +>; +uniform float4x4 Random< + bool automatic = true; + string name = "Random Array"; + string description = "A float4x4 value containing random values between 0 and 1"; +>; +uniform float4 ViewSize< + bool automatic = true; +>; +uniform texture2d InputA< + bool automatic = true; +>; +uniform texture2d InputB< + bool automatic = true; +>; +uniform float TransitionTime< + bool automatic = true; +>; +uniform int2 TransitionSize< + bool automatic = true; +>; + +uniform bool _49_FadeToColor< + string name = "Fade To Color?"; +> = true; + +uniform float4 _50_Color< + string name = "Color"; + string field_type = "slider"; + float4 minimum = {0.,0.,0.,0.}; + float4 maximum = {100.,100.,100.,100.}; + float4 scale = {.01,.01,.01,.01}; + float4 step = {.01,.01,.01,.01}; +> = {0., 0., 0., 100.}; + +uniform float _100_Rotation< + string name = "Rotation"; + string field_type = "slider"; + float minimum = -90.; + float maximum = 90.; + float scale = 1.; + float step = .01; +> = 30.; + +uniform float _200_Bars< + string name = "Number of Bars"; + string field_type = "slider"; + float minimum = 1.; + float maximum = 100.; + float scale = 1.; + float step = .5; +> = 20.; + +// ---------- Shader Code +sampler_state def_sampler { + AddressU = Clamp; + AddressV = Clamp; + Filter = Linear; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +#define PI 3.1415926535897932384626433832795 +#define TO_RAD(x) (x * (PI/180.)) +#define TO_DEG(x) (x * (180./PI)) + +VertData VSDefault(VertData vtx) { + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; +} + +float2 rotate2D(float2 xy, float angle) { + float s = sin(angle); + float c = cos(angle); + return float2(xy.x * c + xy.y * s, xy.x * -s + xy.y * c); +} + +// https://www.shadertoy.com/view/4dXBRH +float hash( in float2 p ) // replace this by something better +{ + p = 50.0*frac( p*0.3183099 + float2(0.71,0.113)); + return -1.0+2.0*frac( p.x*p.y*(p.x+p.y) ); +} + +// return value noise (in x) and its derivatives (in yz) +float3 noised( in float2 p ) +{ + float2 i = floor( p ); + float2 f = frac( p ); + + // quintic interpolation + float2 u = f*f*f*(f*(f*6.0-15.0)+10.0); + float2 du = 30.0*f*f*(f*(f-2.0)+1.0); + + float va = hash( i + float2(0.0,0.0) ); + float vb = hash( i + float2(1.0,0.0) ); + float vc = hash( i + float2(0.0,1.0) ); + float vd = hash( i + float2(1.0,1.0) ); + + float k0 = va; + float k1 = vb - va; + float k2 = vc - va; + float k4 = va - vb - vc + vd; + + return float3( va+(vb-va)*u.x+(vc-va)*u.y+(va-vb-vc+vd)*u.x*u.y, // value + du*(u.yx*(va-vb-vc+vd) + float2(vb,vc) - va) ); // derivative +} + +bool compare_a_b(float time, float x, float dir) { + if (dir < .5) { + return time > x; + } else { + return (1. - time) < x; + } +} + +float4 PSDefault(VertData vtx) : TARGET { + float2 ruv = (rotate2D(vtx.uv - .5, TO_RAD(_100_Rotation)) + .5); + + float bar_offset_max = .2; + float bar_id = floor(ruv.y * _200_Bars); + float bar_offset = 0.; + float bar_direction = 0.; + if (TransitionTime < .5 || !_49_FadeToColor) { + bar_offset = noised(float2(bar_id, 0.)).x * bar_offset_max; + bar_direction = step(noised(float2(bar_id, 1.)).x, .5); + } else { + bar_offset = noised(float2(bar_id, 1.)).x * bar_offset_max; + bar_direction = step(noised(float2(bar_id, 0.)).x, .5); + } + + if (_49_FadeToColor) { + float bar_time_a = (TransitionTime * 3.) + bar_offset; + float bar_time_b = (TransitionTime * 3. - 2.) - bar_offset; + if (compare_a_b(bar_time_a, vtx.uv.x, bar_direction)) { + if (compare_a_b(bar_time_b, vtx.uv.x, bar_direction)) { + return InputB.Sample(def_sampler, vtx.uv); + } else { + return _50_Color; + } + } else { + return InputA.Sample(def_sampler, vtx.uv); + } + } else { + float bar_time_a = clamp((TransitionTime + bar_offset) / (1. - bar_offset_max), 0., 1.); + if (compare_a_b(bar_time_a, vtx.uv.x, bar_direction)) { + return InputB.Sample(def_sampler, vtx.uv); + } else { + return InputA.Sample(def_sampler, vtx.uv); + } + } +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(vtx); + pixel_shader = PSDefault(vtx); + } +}