2d Lava Lamp

a simple shader for making blob lamps. To use this, you’ll need 2 diferent sprites one for the body, and one for any other parts of the blob lamp, such as the base and cap.

The pramiters used are:
top = 0.0 – top edge of the blob lamp, starting from the top (0 is the top of the sprite, 1 is the bottom of the sprite)
bottom = 1.0  – bottom edge of the blob lamp, starting from the top (0 is the top of the sprite, 1 is the bottom of the sprite)
blob_threshold = 1.5 – Threshold for blob visability – higher gives a sharper blob
random_seed = 0.0 – Randomise the blobs by changing this.
blob_scale_x = 1.0 – Scaling the width of the blobs
blob_scale_y = 1.0 – Scaling the height of the blobs
blobs_enabled = true – Turn on or off the blobs.
blob_speed = 1.0 – The speed the blobs move. Generally, a value of 0.5 to 1.2 make for a fairly realistic visual display.

background_edge : source_color = vec4(0.1, 0.0, 0.2, 1.0) – The edge colour of the background
background_center : source_color = vec4(0.5, 0.0, 0.8, 1.0) – The center colour of the background
background_alpha = 0.5 – How transparent is the background

blob_top : source_color = vec4(1.0, 0.4, 0.4, 1.0) – The darker colour of the blobs near the top of the lamp
blob_bottom : source_color = vec4(1.0, 1.0, 0.3, 1.0) – The lighter colour of the blobs near the bottom of the lamp

blob_alpha = 1.0 – how transparent are the blobs. This should always be the same or higher than the background

Shader code
// This is a 2D CanvasItem shader
shader_type canvas_item;

// Uniforms for configuration
uniform float top = 1.0;                      // Top of the blob area
uniform float bottom = 0.0;                   // Bottom of the blob area
uniform float blob_threshold = 1.5;           // Threshold for blob visibility
uniform float random_seed = 0.0;              // Unique random seed per object
uniform float blob_scale_x = 1.0;             // Scale factor for blob size (X axis)
uniform float blob_scale_y = 1.0;             // Scale factor for blob size (Y axis)
uniform bool blobs_enabled = true;            // Enable or disable blobs
uniform float blob_speed = 1.0;               // Speed of the blob movement

// Background gradient colors with adjustable alpha
uniform vec4 background_edge : source_color = vec4(0.1, 0.0, 0.2, 1.0);
uniform vec4 background_center : source_color = vec4(0.5, 0.0, 0.8, 1.0);
uniform float background_alpha = 0.5;         // Background transparency (0.0 to 1.0)

// Blob gradient colors with adjustable alpha
uniform vec4 blob_top : source_color = vec4(1.0, 0.4, 0.4, 1.0);
uniform vec4 blob_bottom : source_color = vec4(1.0, 1.0, 0.3, 1.0);
uniform float blob_alpha = 1.0;               // Blob transparency (0.0 to 1.0)

// Function to generate a pseudo-random value based on seed
float random(vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898, 78.233)) + random_seed) * 43758.5453123);
}

// Function to calculate oscillation for blob movement
float oscillate(float time, float offset, float speed) {
    return 0.5 + 0.5 * sin(time * speed + offset);
}

void fragment() {
    // Sample the base texture and respect its transparency
    vec4 base_color = texture(TEXTURE, UV);
    float base_alpha = base_color.a; // Use the alpha of the base texture

    // Background gradient based on UV.x
    vec4 background_color = mix(background_edge, background_center, abs(0.5 - UV.x) * 2.0);
    background_color.a *= background_alpha; // Apply adjustable background transparency

    // If blobs are disabled, show only the background
    if (!blobs_enabled) {
        COLOR = background_color * base_alpha; // Combine with base texture transparency
    } else {
        // Blob centers and radii (fixed size array)
        const int blob_count = 6;
        vec3 blob_centers[blob_count];
        for (int i = 0; i < blob_count; i++) {
            float random_offset = random(vec2(float(i), 0.0)); // Random per blob
            blob_centers[i] = vec3(
                0.4 + 0.2 * random(vec2(float(i), 1.0)), // X position with some randomization
                bottom + oscillate(TIME, random_offset, blob_speed * (0.1 + 0.3 * random(vec2(float(i), 2.0)))) * (top - bottom), // Ensure blobs start at bottom and move up
                0.03 + 0.05 * random(vec2(float(i), 3.0)) // Base radius (without scaling)
            );
        }

        // Calculate blob influence with independent X and Y scaling
        float influence = 0.0;
        for (int i = 0; i < blob_count; i++) {
            vec2 scaled_uv = vec2(UV.x / blob_scale_x, UV.y / blob_scale_y);
            vec2 scaled_center = vec2(blob_centers[i].x / blob_scale_x, blob_centers[i].y / blob_scale_y);
            float distance_to_blob = distance(scaled_uv, scaled_center);
            influence += blob_centers[i].z / (distance_to_blob + 0.01); // Avoid division by zero
        }

        // Adjusted blob color blending to apply gradient from bottom to top
        float gradient_position = clamp((UV.y - bottom) / (top - bottom), 0.0, 1.0);
        vec4 blob_color = mix(blob_bottom, blob_top, gradient_position);
        blob_color.a *= blob_alpha; // Apply adjustable blob transparency

        // Determine the final color based on influence
        vec4 final_color = background_color;
        if (influence > blob_threshold) {
            final_color = blob_color;
        } else {
            final_color = mix(background_color, blob_color, pow(influence / blob_threshold, 2.0));
        }

        // Combine with the base texture transparency
        final_color.a *= base_alpha;

        // Output the final color
        COLOR = final_color;
    }
}
Tags
80s, blob lamp, lava lamp, retro
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.

Related shaders

Lava Shader

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments