Skip to content

Instantly share code, notes, and snippets.

@0b5vr
Last active May 26, 2023 03:58
Show Gist options
  • Save 0b5vr/a1ccea3ce866c34706084e3526204f4f to your computer and use it in GitHub Desktop.
Save 0b5vr/a1ccea3ce866c34706084e3526204f4f to your computer and use it in GitHub Desktop.
Windows Terminal VHS Pixel Shader You Definitely Are Not Gonna Need This
/**
* (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