Last active
May 26, 2023 03:58
-
-
Save 0b5vr/a1ccea3ce866c34706084e3526204f4f to your computer and use it in GitHub Desktop.
Windows Terminal VHS Pixel Shader You Definitely Are Not Gonna Need This
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* (c) 2021 FMS_Cat, MIT License | |
* Original shader: https://www.shadertoy.com/view/MdffD7 | |
* I dumbass don't know what it says despite it's my own shader | |
*/ | |
Texture2D shaderTexture; | |
SamplerState samplerState; | |
cbuffer PixelShaderSettings { | |
float Time; | |
float Scale; | |
float2 Resolution; | |
float4 Background; | |
}; | |
static const float PI = 3.14159265f; | |
static const int SAMPLES = 6; | |
static const float COLOR_NOISE_AMP = 0.1f; | |
static const float3 YIQ_OFFSET = float3( -0.1f, -0.1f, 0.0f ); | |
static const float3 YIQ_AMP = float3( 1.2f, 1.1f, 1.5f ); | |
bool validuv( float2 uv ) | |
{ | |
return 0.0f < uv.x && uv.x < 1.0f && 0.0f < uv.y && uv.y < 1.0f; | |
} | |
float2 yflip( float2 uv ) | |
{ | |
return float2( uv.x, 1.0 - uv.y ); | |
} | |
float fs( float s ) | |
{ | |
return frac( sin( s * 114.514f ) * 1919.810f ); | |
} | |
float fs2( float2 s ) | |
{ | |
return fs( s.x + fs( s.y ) ); | |
} | |
float2x2 rotate2D( float t ) | |
{ | |
return float2x2( cos( t ), sin( t ), -sin( t ), cos( t ) ); | |
} | |
float3 rgb2yiq( float3 rgb ) | |
{ | |
return mul( float3x3( 0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f ), rgb ); | |
} | |
float3 yiq2rgb( float3 yiq ) | |
{ | |
return mul( float3x3( 1.000f, 1.000f, 1.000f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f ), yiq ); | |
} | |
float v2Random( float2 v ) | |
{ | |
float2 vf = frac( v * 256.0f ); | |
float2 vi = floor( v * 256.0f ) / 256.0f; | |
float2 d = float2( 0.0f, 1.0f / 256.0f ); | |
return lerp( | |
lerp( fs2( vi + d.xx ), fs2( vi + d.yx ), vf.x ), | |
lerp( fs2( vi + d.xy ), fs2( vi + d.yy ), vf.x ), | |
vf.y | |
); | |
} | |
half3 vhsTex2D( Texture2D input, float2 uv ) { | |
if ( validuv( uv ) ) { | |
half3 yiq = half3( 0.0f, 0.0f, 0.0f ); | |
for ( int i = 0; i < SAMPLES; i ++ ) { | |
float2 uvt = uv - float2( float( i ), 0.0f ) / Resolution; | |
if ( validuv( uvt ) ) { | |
half4 tex = input.Sample( samplerState, uvt ); | |
yiq += ( | |
rgb2yiq( lerp( Background.rgb, tex.rgb, tex.a ) ) * | |
float2( float( i ), float( SAMPLES - 1 - i ) ).yxx / float( SAMPLES - 1 ) | |
) / float( SAMPLES ) * 2.0f; | |
} | |
} | |
return yiq2rgb( yiq ); | |
} | |
return half3( 0.1f, 0.1f, 0.1f ); | |
} | |
float4 main( float4 pos : SV_POSITION, float2 uv : TEXCOORD ) : SV_TARGET | |
{ | |
Texture2D input = shaderTexture; | |
float2 uvt = yflip( uv ); | |
float3 col = float3( 0.0f, 0.0f, 0.0f ); | |
// tape wave | |
uvt.x += ( v2Random( float2( uvt.y / 10.0f, Time / 10.0f ) / 1.0f ) - 0.5f ) / Resolution.x * 1.0f; | |
uvt.x += ( v2Random( float2( uvt.y, Time * 10.0f ) ) - 0.5f ) / Resolution.x * 1.0f; | |
// tape crease | |
float tcPhase = smoothstep( 0.9f, 0.96f, sin( uvt.y * 8.0f - ( Time + 0.14f * v2Random( Time * float2( 0.67f, 0.59f ) ) ) * PI * 1.2f ) ); | |
float tcNoise = smoothstep( 0.3f, 1.0f, v2Random( float2( uvt.y * 4.77f, Time ) ) ); | |
float tc = tcPhase * tcNoise; | |
uvt.x = uvt.x - tc / Resolution.x * 8.0f; | |
// switching noise | |
float snPhase = smoothstep( 6.0f / Resolution.y, 0.0f, uvt.y ); | |
uvt.y += snPhase * 0.3f; | |
uvt.x += snPhase * ( ( v2Random( float2( uv.y * 100.0f, Time * 10.0f ) ) - 0.5f ) / Resolution.x * 24.0f ); | |
// fetch | |
half3 color = vhsTex2D( input, yflip( uvt ) ); | |
color = pow( color, 0.4545f ); | |
// crease noise | |
float cn = tcNoise * ( 0.3f + 0.7f * tcPhase ); | |
if ( 0.29f < cn ) { | |
float2 uvtt = ( uvt + float2( 1.0f, 0.0f ) * v2Random( float2( uvt.y, Time ) ) ) * float2( 0.1f, 1.0f ); | |
float n0 = v2Random( uvtt ); | |
float n1 = v2Random( uvtt + float2( 1.0f, 0.0f ) / Resolution.x ); | |
if ( n1 < n0 ) { | |
color = lerp( color, float3( 2.0f, 2.0f, 2.0f ), pow( n0, 10.0f ) ); | |
} | |
} | |
// ac beat | |
color *= 1.0f + 0.1f * smoothstep( 0.4f, 0.6f, v2Random( float2( 0.0f, 0.1f * ( uv.y + Time * 0.2f ) ) / 10.0f ) ); | |
// color noise | |
half2 noiseuv = uvt + float2( fs( Time ), fs( Time / 0.7f ) ); | |
half3 noise = half3( | |
v2Random( noiseuv ), | |
v2Random( noiseuv + 0.7f ), | |
v2Random( noiseuv + 1.4f ) | |
); | |
color = saturate( color ); | |
// yiq | |
color = rgb2yiq( color ); | |
color += COLOR_NOISE_AMP * ( noise - 0.5f ); | |
color = YIQ_OFFSET + YIQ_AMP * color; | |
color = yiq2rgb( color ); | |
color = pow( color, 2.2f ); | |
return half4( color, 1.0f ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment