crt vhs simple
min vhs simple que cree y ya xd
Shader code
shader_type canvas_item;
uniform sampler2D screen_texture: hint_screen_texture, filter_linear_mipmap, repeat_disable;
uniform vec2 vhs_resolution = vec2(320.0, 240.0);
uniform int samples = 2;
uniform float crease_noise: hint_range(0.0, 2.0, 0.1) = 1.0;
uniform float crease_opacity: hint_range(0.0, 1.0, 0.1) = 0.5;
uniform float filter_intensity: hint_range(0.0, 1.0, 0.1) = 0.1;
group_uniforms fisheye_effect;
uniform float fisheye_strength: hint_range(-2.0, 2.0, 0.1) = 0.3;
group_uniforms tape_crease;
uniform float tape_crease_smear: hint_range(0.0, 2.0, 0.1) = 0.2;
uniform float tape_crease_intensity: hint_range(0.0, 1.0, 0.1) = 0.2;
uniform float tape_crease_jitter: hint_range(0.0, 1.0, 0.01) = 0.10;
uniform float tape_crease_speed: hint_range(-2.0, 2.0, 0.1) = 0.5;
uniform float tape_crease_discoloration: hint_range(0.0, 2.0, 0.1) = 1.0;
group_uniforms bottom_border;
uniform float bottom_border_thickness: hint_range(0.0,32.0, 0.1) = 6.0;
uniform float bottom_border_jitter: hint_range(0.0, 24.0, 0.5) = 6.0;
group_uniforms noise;
uniform float noise_intensity: hint_range(0.0, 1.0, 0.1) = 0.1;
uniform sampler2D noise_texture: filter_linear_mipmap, repeat_enable;
group_uniforms rec_ui;
uniform vec2 rec_position = vec2(0.05, 0.05);
uniform float rec_scale: hint_range(0.1, 3.0, 0.1) = 0.4;
uniform float blink_speed = 3.0;
float v2random(vec2 uv) {
return texture(noise_texture, mod(uv, vec2(1.0))).x;
}
mat2 rotate2D(float t) {
return mat2(vec2(cos(t), sin(t)), vec2(-sin(t), cos(t)));
}
vec3 rgb2yiq(vec3 rgb) {
return mat3(vec3(0.299, 0.596, 0.211), vec3(0.587, -0.274, -0.523), vec3(0.114, -0.322, 0.312)) * rgb;
}
vec3 yiq2rgb(vec3 yiq) {
return mat3(vec3(1.0, 1.0, 1.0), vec3(0.956, -0.272, -1.106), vec3(0.621, -0.647, 1.703)) * yiq;
}
vec3 vhx_tex_2D(sampler2D tex, vec2 uv, float rot) {
vec3 yiq = vec3(0.0);
for (int i = 0; i < samples; i++) {
yiq += rgb2yiq(texture(tex, uv - vec2(float(i), 0.0) / vhs_resolution).xyz) * vec2(float(i), float(samples - 1 - i)).yxx / float(samples - 1) / float(samples) * 2.0;
}
if (rot != 0.0) {
yiq.yz *= rotate2D(rot * tape_crease_discoloration);
}
return yiq2rgb(yiq);
}
// CORREGIDO: Matriz de píxeles reordenada para que la R esté al derecho
float draw_rec_text(vec2 uv) {
vec2 st = (uv - rec_position) * (40.0 / rec_scale);
if (st.y < 0.0 || st.y > 5.0 || st.x < 0.0 || st.x > 11.0) return 0.0;
int x = int(st.x);
int y = int(st.y);
float text_mask = 0.0;
if (x >= 0 && x <= 2) { // Letra R (¡Arreglada y al derecho!)
if (x == 0 || y == 0 || y == 2 || (x == 2 && y == 1) || (x == 1 && y == 3) || (x == 2 && y == 4)) text_mask = 1.0;
} else if (x >= 4 && x <= 6) { // Letra E
if (x == 4 || y == 0 || y == 2 || y == 4) text_mask = 1.0;
} else if (x >= 8 && x <= 10) { // Letra C
if (x == 8 || y == 0 || y == 4) text_mask = 1.0;
}
return text_mask;
}
void fragment() {
vec2 uv_raw = UV;
// --- INICIO EFECTO OJO DE PEZ ---
vec2 uvn = UV - 0.5;
float d = length(uvn);
uvn = uvn * (1.0 + fisheye_strength * d * d);
uvn = uvn + 0.5;
// --- FIN EFECTO OJO DE PEZ ---
vec3 col = vec3(0.0, 0.0, 0.0);
uvn.x += (v2random(vec2(uvn.y / 10.0, TIME / 10.0) / 1.0) - 0.5) / vhs_resolution.x * 1.0;
uvn.x += (v2random(vec2(uvn.y, TIME * 10.0)) - 0.5) / vhs_resolution.x * 1.0;
float tc_phase = smoothstep(0.9, 0.96, sin(uvn.y * 8.0 - (TIME * tape_crease_speed + tape_crease_jitter * v2random(TIME * vec2(0.67, 0.59))) * PI * 1.2));
float tc_noise = smoothstep(0.3, 1.0, v2random(vec2(uvn.y * 4.77, TIME)));
float tc = tc_phase * tc_noise;
uvn.x = uvn.x - tc / vhs_resolution.x * 8.0 * tape_crease_smear;
float sn_phase = smoothstep(1.0 - bottom_border_thickness / vhs_resolution.y, 1.0, uvn.y);
uvn.x += sn_phase * (v2random(vec2(uvn.y * 100.0, TIME * 10.0)) - 0.5) / vhs_resolution.x * bottom_border_jitter;
col = vhx_tex_2D(screen_texture, uvn, tc_phase * 0.2 + sn_phase * 2.0);
float cn = tc_noise * crease_noise * (0.7 * tc_phase * tape_crease_intensity + 0.3);
if (0.29 < cn) {
vec2 V = vec2(0.0, crease_opacity);
vec2 uvt = (uvn + V.yx * v2random(vec2(uvn.y, TIME))) * vec2(0.1, 1.0);
float n0 = v2random(uvt);
float n1 = v2random(uvt + V.yx / vhs_resolution.x);
if (n1 < n0) {
col = mix(col, 2.0 * V.yyy, pow(n0, 10.0));
}
}
col *= 1.0 + 0.1 * smoothstep(0.4, 0.6, v2random(vec2(0.0, 0.1 * (uvn.y + TIME * 0.2)) / 10.0));
col *= 1.0 - noise_intensity * 0.5 + noise_intensity * texture(noise_texture, mod(uvn * vec2(1.0, 1.0) + TIME * vec2(5.97, 4.45), vec2(1.0))).xyz;
col = clamp(col, 0.0, 1.0);
col = rgb2yiq(col);
col = vec3(0.9, 1.1, 1.5) * col + vec3(0.1, -0.1, 0.0) * filter_intensity;
col = yiq2rgb(col);
// --- INTERFAZ "REC" ALINEADA Y CORREGIDA ---
// 1. Dibujar el texto "REC" al derecho
float text = draw_rec_text(uv_raw);
col = mix(col, vec3(0.95, 0.95, 0.95), text);
// 2. Punto rojo alineado al lado derecho
vec2 dot_offset = vec2(13.0, 2.5) * (rec_scale / 40.0);
vec2 dot_center = rec_position + dot_offset;
float dot_radius = 1.2 * (rec_scale / 40.0);
float dist_to_dot = length(uv_raw - dot_center);
float blink = step(0.0, sin(TIME * blink_speed));
if (dist_to_dot < dot_radius && blink > 0.5) {
col = vec3(1.0, 0.0, 0.0);
}
// ------------------------------------------
COLOR = vec4(col, 1.0);
}

