The psychedelic anomaly

It can be useful for psychedelic games, simulating some anomalies…

Shader code
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx;


uniform sampler2D base_texture : source_color;
uniform bool use_texture = true;
uniform float texture_visibility : hint_range(0.0, 2.0) = 1.0; 
uniform float texture_transparency : hint_range(0.0, 1.0) = 0.7; 
uniform vec2 texture_scale = vec2(1.0, 1.0);
uniform vec2 texture_offset = vec2(0.0, 0.0);
uniform bool texture_on_top = false; // Текстура поверх эффектов или под ними


uniform vec4 nebula_color1 : source_color = vec4(0.1, 0.2, 0.6, 0.7); 
uniform vec4 nebula_color2 : source_color = vec4(0.6, 0.1, 0.5, 0.7); 
uniform vec4 nebula_color3 : source_color = vec4(0.1, 0.5, 0.3, 0.7); 
uniform vec4 star_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);


uniform float star_density : hint_range(0.0, 1.0) = 0.5;
uniform float nebula_density : hint_range(0.0, 1.0) = 0.3;
uniform float star_size : hint_range(0.1, 5.0) = 1.0;
uniform float nebula_scale : hint_range(0.1, 10.0) = 3.0;


uniform float speed : hint_range(0.0, 2.0) = 0.1;
uniform float time_scale : hint_range(0.1, 5.0) = 1.0;
uniform vec2 scroll_direction = vec2(0.1, 0.2);
uniform bool animate_stars = true;
uniform bool animate_nebula = true;
uniform bool animate_texture = false;
uniform vec2 texture_scroll_direction = vec2(0.05, 0.03);


uniform float emission_strength : hint_range(0.0, 10.0) = 1.0;
uniform float texture_emission : hint_range(0.0, 5.0) = 0.5; 
uniform float roughness_value : hint_range(0.0, 1.0) = 0.7;
uniform float metallic_value : hint_range(0.0, 1.0) = 0.3;
uniform float specular_value : hint_range(0.0, 1.0) = 0.5;


uniform bool use_rim_effect = false;
uniform float rim_power : hint_range(0.1, 10.0) = 3.0;
uniform vec4 rim_color : source_color = vec4(0.0, 0.5, 1.0, 1.0);
uniform bool use_fresnel = false;
uniform float fresnel_power : hint_range(0.1, 10.0) = 2.0;


uniform int octaves : hint_range(1, 8) = 5;
uniform float persistence : hint_range(0.1, 1.0) = 0.5;
uniform float lacunarity : hint_range(1.0, 4.0) = 2.0;


uniform int texture_blend_mode : hint_range(0, 5) = 5; // 0=Multiply, 1=Add, 2=Overlay, 3=Screen, 4=Normal, 5=Soft Light


uniform bool use_texture_mask = false;
uniform float texture_mask_threshold : hint_range(0.0, 1.0) = 0.5;
uniform bool invert_mask = false;


float random(vec2 uv) {
    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123);
}


float noise(vec2 uv) {
    vec2 i = floor(uv);
    vec2 f = fract(uv);

    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));

    vec2 u = f * f * (3.0 - 2.0 * f);

    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}


float fbm(vec2 uv) {
    float value = 0.0;
    float amplitude = 0.5;
    float frequency = 1.0;

    for (int i = 0; i < octaves; i++) {
        value += amplitude * noise(frequency * uv);
        amplitude *= persistence;
        frequency *= lacunarity;
    }

    return value;
}


float worley(vec2 uv, float scale) {
    vec2 id = floor(uv * scale);
    vec2 gv = fract(uv * scale);

    float min_dist = 1.0;

    for (int y = -1; y <= 1; y++) {
        for (int x = -1; x <= 1; x++) {
            vec2 offset = vec2(float(x), float(y));
            
            float rx = random(id + offset);
            float ry = random(id + offset + vec2(12.345, 67.890));
            vec2 pos = vec2(rx, ry) * 0.5 + 0.25;

            float dist = length(gv - pos - offset);
            min_dist = min(min_dist, dist);
        }
    }

    return min_dist;
}


vec3 blend_overlay(vec3 base, vec3 blend) {
    vec3 result;
    for(int i = 0; i < 3; i++) {
        if(base[i] < 0.5) {
            result[i] = 2.0 * base[i] * blend[i];
        } else {
            result[i] = 1.0 - 2.0 * (1.0 - base[i]) * (1.0 - blend[i]);
        }
    }
    return result;
}


vec3 blend_screen(vec3 base, vec3 blend) {
    return 1.0 - (1.0 - base) * (1.0 - blend);
}


vec3 blend_soft_light(vec3 base, vec3 blend) {
    vec3 result;
    for(int i = 0; i < 3; i++) {
        if(blend[i] < 0.5) {
            result[i] = 2.0 * base[i] * blend[i] + base[i] * base[i] * (1.0 - 2.0 * blend[i]);
        } else {
            result[i] = 2.0 * base[i] * (1.0 - blend[i]) + sqrt(base[i]) * (2.0 * blend[i] - 1.0);
        }
    }
    return result;
}

void fragment() {
    
    vec2 base_uv = UV;

    
    vec2 moving_uv = base_uv;
    if (animate_nebula) {
        moving_uv += TIME * speed * scroll_direction;
    }

    
    vec2 texture_uv = base_uv * texture_scale + texture_offset;
    if (animate_texture) {
        texture_uv += TIME * speed * texture_scroll_direction;
    }
    vec4 texture_color = texture(base_texture, texture_uv);

    
    float texture_mask = 1.0;
    if (use_texture_mask) {
        texture_mask = fbm(base_uv * 2.0);
        texture_mask = step(texture_mask_threshold, texture_mask);
        if (invert_mask) {
            texture_mask = 1.0 - texture_mask;
        }
    }

    
    float nebula = fbm(moving_uv * nebula_scale);
    nebula = smoothstep(0.4 - nebula_density * 0.4, 0.6 + nebula_density * 0.4, nebula);

    
    float star_scale = 500.0 / star_size;
    float star_field = step(1.0 - star_density, random(floor(base_uv * star_scale)));
    float star_twinkle = 0.5;
    if (animate_stars) {
        star_twinkle = 0.5 + 0.5 * sin(TIME * time_scale + random(floor(base_uv * 50.0)) * 10.0);
    }
    float stars = star_field * star_twinkle;

    
    float star_clusters = 1.0 - worley(base_uv, 5.0);
    star_clusters = pow(star_clusters, 8.0) * 0.7;

    
    float color_mix = fbm(moving_uv * 2.0 + (animate_nebula ? TIME * 0.05 : 0.0));
    vec4 nebula_mix;
    if (color_mix < 0.33) {
        nebula_mix = mix(nebula_color1, nebula_color2, color_mix * 3.0);
    } else if (color_mix < 0.66) {
        nebula_mix = mix(nebula_color2, nebula_color3, (color_mix - 0.33) * 3.0);
    } else {
        nebula_mix = mix(nebula_color3, nebula_color1, (color_mix - 0.66) * 3.0);
    }

    
    vec4 final_color = mix(vec4(0.0, 0.0, 0.0, 1.0), nebula_mix, nebula * nebula_mix.a * texture_transparency);
    final_color += stars * star_color * texture_transparency;
    final_color += star_clusters * star_color * 0.5 * texture_transparency;

    
    if (use_texture) {
        vec4 blended_texture = texture_color * vec4(vec3(1.0), texture_visibility * texture_mask);

        if (!texture_on_top) {
            
            if (texture_blend_mode == 0) {
                
                final_color.rgb = mix(blended_texture.rgb, final_color.rgb * blended_texture.rgb, texture_transparency);
            } else if (texture_blend_mode == 1) {
                
                final_color.rgb = blended_texture.rgb + final_color.rgb * texture_transparency;
            } else if (texture_blend_mode == 2) {
                
                final_color.rgb = blend_overlay(blended_texture.rgb, final_color.rgb);
            } else if (texture_blend_mode == 3) {
                
                final_color.rgb = blend_screen(blended_texture.rgb, final_color.rgb);
            } else if (texture_blend_mode == 4) {
                
                final_color.rgb = mix(blended_texture.rgb, final_color.rgb, texture_transparency);
            } else if (texture_blend_mode == 5) {
                
                final_color.rgb = blend_soft_light(blended_texture.rgb, final_color.rgb);
            }
        } else {
            
            vec3 base = final_color.rgb;
            vec3 blend = blended_texture.rgb;

            if (texture_blend_mode == 0) {
                
                final_color.rgb = mix(base, base * blend, blended_texture.a);
            } else if (texture_blend_mode == 1) {
                
                final_color.rgb = base + blend * blended_texture.a;
            } else if (texture_blend_mode == 2) {
                
                final_color.rgb = mix(base, blend_overlay(base, blend), blended_texture.a);
            } else if (texture_blend_mode == 3) {
                
                final_color.rgb = mix(base, blend_screen(base, blend), blended_texture.a);
            } else if (texture_blend_mode == 4) {
                
                final_color.rgb = mix(base, blend, blended_texture.a);
            } else if (texture_blend_mode == 5) {
                
                final_color.rgb = mix(base, blend_soft_light(base, blend), blended_texture.a);
            }
        }
    }

    
    float rim = 0.0;
    if (use_rim_effect) {
        rim = 1.0 - max(dot(NORMAL, VIEW), 0.0);
        rim = pow(rim, rim_power);
        final_color.rgb += rim * rim_color.rgb;
    }

    
    if (use_fresnel) {
        float fresnel = pow(1.0 - dot(NORMAL, VIEW), fresnel_power);
        final_color.rgb += fresnel * nebula_mix.rgb * 0.5;
    }

    
    ALBEDO = final_color.rgb;

    
    if (use_texture && texture_on_top) {
        EMISSION = mix(final_color.rgb * emission_strength, texture_color.rgb * texture_emission, texture_color.a * texture_visibility);
    } else {
        EMISSION = final_color.rgb * emission_strength;
    }

    ROUGHNESS = roughness_value;
    METALLIC = metallic_value;
    SPECULAR = specular_value;
}
Tags
shader
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 WhyNilliana

Glass Shader

My Little Pony 3D ( v. 1.0 )

RTX filter for your game (brightness, ripples and other effects)

Related shaders

A magical anomaly

guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
skuncc
7 months ago

I’m going to use this.