Noise-Displaced Space Sphere

This is a 3D Raymarching shader adapted for Godot’s CanvasItem, based on a scene from Inigo Quilez on Shadertoy (view: https://www.shadertoy.com/view/lllSWr).

The shader generates a unique, continuously moving 3D object—a sphere whose surface is heavily distorted and sculpted by Fractal Brownian Motion (FBM) noise. The structure is tiled using quantized rotations, creating a dynamic, almost organic-looking structure that floats in space. The noise functions used are the classic hash-based noise implementations by IQ.

This Godot 4 adaptation maintains the full complexity of the 3D generation while exposing key parameters as Uniforms for easy control:

Parameter Type Description
U Speed float Controls the animation speed of the object’s distortion and rotation over time.
U Main Color vec4 Sets the base background color and the final color of the atmospheric fog applied to the object.
U Channel Color vec4 Sets a tint/multiplier for the texture sampled from Channel 0, which is then used for the object’s lighting and detail.
U Position vec3 Allows for camera/world translation along the X, Y, and Z axes, letting you pan around or through the object.
Channel 0 sampler2D Requires an assigned Texture to act as a color map or detail map for the object’s surface during shading.
Shader code
shader_type canvas_item;

// =============================
// original:https://www.shadertoy.com/view/lllSWr
//adaptation: GerardoLCDF
// ===============================

// Color principal/de fondo
uniform vec4 u_main_color : source_color = vec4(0.0, 0.2, 0.0, 1.0); 
// Color que se aplica al canal0
uniform vec4 u_channel_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
// Control de velocidad (multiplica el tiempo)
uniform float u_speed = 1.0;
// Desplazamiento de la cámara/mundo (XYZ)
uniform vec3 u_position = vec3(0.0, 0.0, 0.0);

uniform sampler2D channel0 : hint_default_black; 

#define T (TIME * u_speed)

// Rotation function
void r(inout vec2 v, float t) { 
    float a = t * T;
    float c = cos(a);
    float s = sin(a);
    mat2 rot_mat = mat2(vec2(c, -s), vec2(s, c)); 
    v = rot_mat * v;
}

#define smin(a,b) (1.0 / (1.0 / (a) + 1.0 / (b)))

const mat3 m = mat3( 
    vec3( 0.00, -0.80, -0.60 ), 
    vec3( 0.80,  0.36, -0.48 ), 
    vec3( 0.60, -0.48,  0.64 )  
);

float hash( float n ) {
    return fract(sin(n)*43758.5453);
}

float noise( in vec3 x ) {
    vec3 p = floor(x);
    vec3 f = fract(x);
    f = f * f * (3.0 - 2.0 * f);
    float n = p.x + p.y * 57.0 + 113.0 * p.z;
    float res = mix(mix(mix( hash(n +   0.0), hash(n +   1.0), f.x),
                        mix( hash(n +  57.0), hash(n +  58.0), f.x), f.y),
                    mix(mix( hash(n + 113.0), hash(n + 114.0), f.x),
                        mix( hash(n + 170.0), hash(n + 171.0), f.x), f.y), f.z);
    return res;
}

#define snoise(x) (2.0 * noise(x) - 1.0)

float sfbm( vec3 p ) {
    float f;
    f  = 0.5000 * snoise( p ); p = m * p * 2.02;
    f += 0.2500 * snoise( p ); p = m * p * 2.03;
    f += 0.1250 * snoise( p ); p = m * p * 2.01;
    f += 0.0625 * snoise( p );
    return f;
}

#define sfbm3(p) vec3(sfbm(p), sfbm(p - 327.67), sfbm(p + 327.67))


void fragment() {
    vec2 screen_size = 1.0 / SCREEN_PIXEL_SIZE; 


    vec4 p = vec4(FRAGCOORD.xy, 0.0, 1.0) / screen_size.y - 0.5; 
    
  
    p.x -= 0.4; // Desplazamiento original del shader
    p.xyz -= u_position;
   
    vec4 d, c; 
    
    d = p;         
    p.z += 10.0;   

    COLOR = vec4(u_main_color.rgb, 1.0); 
    
    float x1, x2, x = 1e9;
    
    const float MAX_STEPS = 100.0;
    for (float i = 1.0; i > 0.0; i -= (1.0 / MAX_STEPS))  {
        
        if (COLOR.x >= 0.99) break; 
        
        vec4 u = 0.03 * floor(p / vec4(8.0, 8.0, 1.0, 1.0) + 3.5);
        vec4 t = p;
        
        r(t.xy, u.x); r(t.xz, u.y); 

        t.xyz += sfbm3(t.xyz / 2.0 + vec3(0.5 * T, 0.0, 0.0)) * (0.6 + 8.0 * (0.5 - 0.5 * cos(T / 16.0)));
        
        vec4 texture_sample = texture(channel0, t.xy);
        c = 5.0 * texture_sample.rrrr * u_channel_color;
 
        x = abs(mod(length(t.xyz), 1.0) - 0.5); 
        x1 = length(t.xyz) - 7.0;              
        
        x = max(x, x1);                        
        
        if ((x1 > 0.1) && (p.z < 0.0)) break; 
        
        if (x < 0.01) { 
              COLOR.rgb += (1.0 - COLOR.rgb) * 0.2 * mix(u_main_color.rgb, c.rgb, i * i); 
              x = 0.1; 
        }  
        
        p += d * x; 
     }
}
Live Preview
Tags
3d, Abstract, distortion, fbm, godotshader, noise, Procedural, raymarching, SDF, sphere
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

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments