Abstract 3D

This is a Volumetric Raymarcher shader adapted for Godot’s CanvasItem that creates a highly fluid, abstract 3D environment using Simplex Noise (snoise). The effect simulates flying through a continuous volume of density, often resulting in a cloud tunnel, wormhole, or liquid space effect.

The shader works by:

  1. Generating Noise: Utilizing a full implementation of Simplex Noise to calculate a smooth, turbulent density value at any point in 3D space (p).

  2. Raymarching: Stepping a virtual camera (cam) through the volume along the ray direction (rd).

  3. Volume Visualization: The color and intensity of the scene are determined by the distance (c) traveled until the ray hits a density threshold (d > 0.5).

This Godot adaptation exposes key parameters to control the scene’s appearance and motion:

Parameter Type Description
movement_speed float Controls the angular speed of the camera’s circular motion in the XY plane.
movement_scale float Controls the radius of the camera’s circular motion in the XY plane.
color_1 vec4 The foreground color (the color of the noise volume/cloud).
color_2 vec4 The background color (the color of deep space/shadows).
Shader code
shader_type canvas_item;

uniform float movement_speed : hint_range(0.0, 1.0) = 0.1;
uniform float movement_scale : hint_range(0.0, 5.0) = 2.0;
uniform vec4 color_1 : source_color = vec4(0.0, 0.63, 0.49, 1);  
uniform vec4 color_2 : source_color = vec4(0.16, 0.16, 0.16,1); 

vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 permute(vec4 x) { return mod289(((x * 34.0) + 1.0) * x); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }

float snoise(vec3 v) {
    const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
    const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
    vec3 i = floor(v + dot(v, C.yyy));
    vec3 x0 = v - i + dot(i, C.xxx);
    vec3 g = step(x0.yzx, x0.xyz);
    vec3 l = 1.0 - g;
    vec3 i1 = min(g.xyz, l.zxy);
    vec3 i2 = max(g.xyz, l.zxy);
    vec3 x1 = x0 - i1 + C.xxx;
    vec3 x2 = x0 - i2 + C.yyy;
    vec3 x3 = x0 - D.yyy;
    i = mod289(i);
    vec4 p = permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + i.x + vec4(0.0, i1.x, i2.x, 1.0));
    float n_ = 0.142857142857;
    vec3 ns = n_ * D.wyz - D.xzx;
    vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
    vec4 x_ = floor(j * ns.z);
    vec4 y_ = floor(j - 7.0 * x_);
    vec4 x = x_ * ns.x + ns.yyyy;
    vec4 y = y_ * ns.x + ns.yyyy;
    vec4 h = 1.0 - abs(x) - abs(y);
    vec4 b0 = vec4(x.xy, y.xy);
    vec4 b1 = vec4(x.zw, y.zw);
    vec4 s0 = floor(b0) * 2.0 + 1.0;
    vec4 s1 = floor(b1) * 2.0 + 1.0;
    vec4 sh = -step(h, vec4(0.0));
    vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
    vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
    vec3 p0 = vec3(a0.xy, h.x);
    vec3 p1 = vec3(a0.zw, h.y);
    vec3 p2 = vec3(a1.xy, h.z);
    vec3 p3 = vec3(a1.zw, h.w);
    vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
    p0 *= norm.x;
    p1 *= norm.y;
    p2 *= norm.z;
    p3 *= norm.w;
    vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
    m = m * m;
    return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
}

void fragment() {
    vec2 uv = (UV * 2.0 - 1.0);
    float aspect_ratio = (1.0 / SCREEN_PIXEL_SIZE).x / (1.0 / SCREEN_PIXEL_SIZE).y;
    uv.x *= aspect_ratio;

    vec2 xy_plane_motion = vec2(cos(TIME * movement_speed), sin(TIME * movement_speed)) * movement_scale;
    vec3 cam = vec3(xy_plane_motion, TIME * 0.08);
    vec3 ro = vec3(0.0, 0.0, 0.0); 
    vec3 rd = normalize(vec3(uv.xy, 1.0)); 

    float c = 4.0;
    for (float step = 0.0; step < 64.0; step += 1.0) {
        vec3 p = cam + ro + ((rd * 0.08) * step);
        float d = snoise(p);
        c = length(cam - p);
        if (d > 0.5 && c > 1.0) {
            break;
        }
    }

    c = (c > 4.0) ? 0.0 : (4.0 - c) * 0.25;
    COLOR = vec4(mix(color_2.rgb, color_1.rgb, c) * c, 1.0);
}
Tags
3DNoise, Abstract, animated, cloud, godotshader, raymarching, SimplexNoise, Tunnel, volumetric, Wormhole
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 Gerardo LCDF

Reflective Crystalline Voronoi

Chromatic Spin

Noise-Displaced Space Sphere

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments