Vaho – Ghost Distortion Shader

📝 Descripción del Shader:

Shader para crear un efecto de fantasma distorsionado en Godot 4.4.
Incluye aberración cromática sutil, transparencia pulsante, bordes brillantes tipo fresnel y un campo de partículas flotantes que se desplazan suavemente.
Ideal para personajes espectrales, portales dimensionales o efectos paranormales en juegos de fantasía, terror o ciencia ficción.
Totalmente personalizable mediante parámetros visuales.


📝 Shader Description:

 

A shader to create a ghostly distortion effect in Godot 4.4.
It features subtle chromatic aberration, pulsating transparency, glowing fresnel edges, and a dynamic floating particle field.
Perfect for spectral characters, dimensional portals, or paranormal effects in fantasy, horror, or sci-fi games.
Fully customizable with visual parameters.

Shader code
shader_type spatial;
render_mode blend_mix, depth_draw_always, cull_back, unshaded;

group_uniforms render;

uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
uniform sampler2D albedo_texture;

uniform float opacity : hint_range(0.0, 2.0) = 0.35;
uniform vec4 ghost_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);

uniform float flicker_speed : hint_range(0.0, 5.0) = 1.2;
uniform float phase_frequency : hint_range(0.0, 1.0) = 0.4;

uniform float fresnel_strength : hint_range(0.0, 1.5) = 0.8;
uniform vec3 fresnel_color : source_color = vec3(1.0, 1.0, 1.0);

uniform float wave_amplitude: hint_range(0.0, 0.01) = 0.006;
uniform float wave_frequency: hint_range(0.0, 20.0) = 19.397;
uniform float wave_speed: hint_range(0.0, 10.0) = 3.618;
uniform float chroma_amount: hint_range(0.0, 10.0) = 1.0;

group_uniforms points;

uniform bool points_enabled = true;
uniform float point_field_scale: hint_range(1.0, 50.0) = 4.377;
uniform float point_size: hint_range(0.001, 0.008) = 0.008;
uniform float point_intensity: hint_range(0.0, 1.0) = 1.0;
uniform float point_axis_speed: hint_range(0.0, 0.5) = 0.051;
uniform int point_move_mode: hint_range(0, 3) = 1;
uniform vec3 point_color : source_color = vec3(1.0, 1.0, 1.0);

// Función de ruido
float random(vec2 st) {
    return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453123);
}

void fragment() {
    vec2 wave_offset = vec2(
        sin(SCREEN_UV.y * wave_frequency + TIME * wave_speed),
        sin(SCREEN_UV.x * wave_frequency + TIME * wave_speed)
    ) * wave_amplitude;

    vec2 distorted_uv = SCREEN_UV + wave_offset;

    vec2 red_uv   = distorted_uv + wave_offset * chroma_amount;
    vec2 blue_uv  = distorted_uv - wave_offset * chroma_amount;
    vec2 green_uv = distorted_uv;

    float r = texture(screen_texture, red_uv).r;
    float g = texture(screen_texture, green_uv).g;
    float b = texture(screen_texture, blue_uv).b;
    vec3 screen_color = vec3(r, g, b);

    float flicker = sin(TIME * flicker_speed) * 0.5 + 0.5;
    float phase = sin(TIME * phase_frequency * 6.2831) * 0.5 + 0.5;

    float fresnel_factor = pow(1.0 - dot(NORMAL, VIEW), 2.0) * fresnel_strength;
    vec3 fresnel = fresnel_color * fresnel_factor;

    vec4 base_texture = texture(albedo_texture, UV);
    vec3 base_color = base_texture.rgb * ghost_color.rgb;

    float point_accum = 0.0;
    if (points_enabled) {
        vec2 moving_uv = UV;
        vec2 offset = vec2(0.0);
        if (point_move_mode == 0) {
            offset = vec2(0.0, TIME * point_axis_speed);
        } else if (point_move_mode == 1) {
            offset = vec2(TIME * point_axis_speed, 0.0);
        } else if (point_move_mode == 2) {
            offset = vec2(TIME * point_axis_speed);
        } else if (point_move_mode == 3) {
            offset = vec2(
                sin(TIME * point_axis_speed * 1.3),
                cos(TIME * point_axis_speed * 1.7)
            );
        }

        moving_uv = fract(moving_uv + offset);
        vec2 grid_uv = moving_uv * point_field_scale;
        vec2 id = floor(grid_uv);
        vec2 f = fract(grid_uv) - 0.5;

        for (int j = -1; j <= 1; j++) {
            for (int i = -1; i <= 1; i++) {
                vec2 neighbor = vec2(float(i), float(j));
                vec2 cell_id = id + neighbor;
                vec2 point_pos = vec2(random(cell_id), random(cell_id * 1.3)) - 0.5;
                float d = length(f - point_pos);
                float point = 1.0 - smoothstep(point_size * 0.5, point_size, d);
                point_accum += point;
            }
        }

        point_accum = clamp(point_accum, 0.0, 1.0);
    }

    vec4 final_color = vec4(base_color, ghost_color.a);
    final_color.rgb = mix(final_color.rgb, screen_color, 0.6);
    final_color.rgb += fresnel;
    final_color.rgb = mix(final_color.rgb, point_color, point_intensity * point_accum);

    float final_alpha = ghost_color.a * opacity * flicker * phase;
    final_color.a = clamp(final_alpha, 0.0, 1.0);

    EMISSION = final_color.rgb;
    ALBEDO = final_color.rgb;
    ALPHA = final_color.a;
}
Tags
chromatic aberration, distortion, Emission, fantasy, fresnel, ghost, godot 4, hologram, particles, portal, sci-fi, screen effect, shader, spectral, spooky, Transparency, Unshaded, vfx, visual effect
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from annie

Dot pattern shader

PixelDither – Color quantizer with palette support

Hatching shader

Related shaders

2D shader: Out of body ghost effect (Pixel Art)

Ghost Vibration

GHOST SHINE

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments