VHS with wiggle

ps: don’t actually call
Port of hunterk’s vhs shader for RetroArch. It has parameters for color smear amount, wiggle, wiggle speed and quality of blurring via samples.

If you’re having performance problems lower the blur samples. Do keep in mind that the smearing will look worse, however.

Instructions:

1- Create a CanvasLayer node

2- Add a ColorRect to the CanvasLayer node

3- Click on the ColorRect -> Material -> New ShaderMaterial -> Shader -> Create New Shader -> Paste the code below

 

CREDITS

Shader code
shader_type canvas_item;

group_uniforms Wiggle;
uniform float wiggle : hint_range(0.0, 1.5, 0.01) = 0.03;
uniform float wiggle_speed : hint_range(0.0, 100.0, 1.0) = 25;
group_uniforms Smear;
uniform float smear : hint_range(0.0, 2.0) = 1.0;

uniform sampler2D Source : hint_screen_texture, filter_linear_mipmap, repeat_disable;

group_uniforms Blur;
uniform int blur_samples : hint_range(3, 15, 1) = 15;

float onOff(float a, float b, float c, float framecount) {
    return step(c, sin((framecount * 0.001) + a * cos((framecount * 0.001) * b)));
}

vec2 jumpy(vec2 uv, float framecount) {
    vec2 look = uv;
    float window = 1.0 / (1.0 + 80.0 * (look.y - mod(framecount / 4.0, 1.0)) * (look.y - mod(framecount / 4.0, 1.0)));
    look.x += 0.05 * sin(look.y * 10.0 + framecount) / 20.0 * onOff(4.0, 4.0, 0.3, framecount) * (0.5 + cos(framecount * 20.0)) * window;
    float vShift = (0.1 * wiggle) * 0.4 * onOff(2.0, 3.0, 0.9, framecount) * (sin(framecount) * sin(framecount * 20.0) + (0.5 + 0.1 * sin(framecount * 200.0) * cos(framecount)));
    look.y = mod(look.y - 0.01 * vShift, 1.0);
    return look;
}

vec2 Circle(float Start, float Points, float Point) {
    float Rad = (3.141592 * 2.0 * (1.0 / Points)) * (Point + Start);
    return vec2(-(.3 + Rad), cos(Rad));
}

vec3 rgb2yiq(vec3 c) {
    return vec3(
        (0.2989 * c.x + 0.5959 * c.y + 0.2115 * c.z),
        (0.5870 * c.x - 0.2744 * c.y - 0.5229 * c.z),
        (0.1140 * c.x - 0.3216 * c.y + 0.3114 * c.z)
    );
}

vec3 yiq2rgb(vec3 c) {
    return vec3(
        (1.0 * c.x + 1.0 * c.y + 1.0 * c.z),
        (0.956 * c.x - 0.2720 * c.y - 1.1060 * c.z),
        (0.6210 * c.x - 0.6474 * c.y + 1.7046 * c.z)
    );
}

vec3 Blur(vec2 uv, float d, int samples) {
    vec3 sum = vec3(0.0);
    float W = 1.0 / float(samples);
    for (int i = 0; i < samples; ++i) {
        float t = (sin(TIME * 5.0 + uv.y * 5.0)) / 10.0;

        t = 0.0;
        vec2 PixelOffset = vec2(d + 0.0005 * t, 0);
        
        float Start = 2.0 / float(samples);
        vec2 Scale = 0.66 * 4.0 * 2.0 * PixelOffset.xy;
        
        vec3 N = texture(Source, uv + Circle(Start, float(samples), float(i)) * Scale).rgb;
        sum += N * W;
    }
    return sum;
}

void fragment() {
    vec2 uv = UV;

    float d=0.1-round(mod(TIME/3.0,1.0))*.1;;
    uv = jumpy(uv, mod(TIME * wiggle_speed, 7.0));

    float s = 0.0001 * -d + 0.0001 * wiggle *(sin(TIME * wiggle_speed));
    float e = min(.30,pow(max(0.0,cos(uv.y*4.0+.3)-.75)*(s+0.5)*1.0,3.0))*25.0;
    float r = (TIME*(2.0*s));
    uv.x += abs(r*pow(min(.003,(-uv.y+(.01*mod(TIME, 5.0))))*3.0,2.0)) * wiggle;
    
    d = 0.051+abs(sin(s/4.0));
    float c = max(0.0001,.002*d) * smear;
    vec4 final;

    final.rgb = Blur(uv, c + c * uv.x, blur_samples);
    float y = rgb2yiq(final.rgb).r;

    uv.x += 0.01 * d;
    c *= 6.0;
    final.rgb = Blur(uv, c, blur_samples);
    float i = rgb2yiq(final.rgb).g;

    uv.x += 0.005 * d;
    c *= 2.50;
    final.rgb = Blur(uv, c, blur_samples);
    float q = rgb2yiq(final.rgb).b;
    final.rgb = yiq2rgb(vec3(y, i, q)) - pow(s + e * 2.0, 3.0);

    final.a = 1.0;

    COLOR = final;
}
Tags
retro, tape, VHS
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from cyanone

Interlaced Video

Skyward Sword Pointillism (with depth)

Analog Monochrome Monitor

Related shaders

Wiggle 2D

Noise Offset (Wiggle)

VHS and CRT monitor effect

Subscribe
Notify of
guest

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
catszy
catszy
2 months ago

This is cool and all but could we maybe see a posterize time/frame stutter shader/script? Like a shader/script that caps the project to a set fps?

teebar
teebar
1 month ago

thanks for this!
i was getting a white flashing until I commented out the pow on line 93 to final.rgb = yiq2rgb(vec3(y, i, q));// - pow(s + e * 2.0, 3.0);

(rendering method Mobile on v4.3.dev5.official [c9c17d6ca])

Last edited 1 month ago by teebar
Apofex
Apofex
1 month ago

This is exactly what I’ve been looking for. Thanks a lot.

chikatilo
chikatilo
27 days ago

for some reason, after applying it, I can’t control the camera, although I can still control the character

LUL
LUL
13 days ago
Reply to  cyanone

nvm i got it

Last edited 13 days ago by LUL