Planet Coffee

This shader generates a dynamic planetary map using a sophisticated 4D Smooth Noise algorithm. The primary advantage of this method is the creation of a perfect equirectangular texture, ensuring there are no visible seams or “pinching” at the poles when applied to a sphere or used as an environment map.

The visual effect is deeply inspired by fluid dynamics—resembling the organic movement of coffee mixing with milk—and utilizes Fractal Brownian Motion (FBM) combined with domain warping. The 4D noise allows the pattern to evolve fluidly over time without needing to physically shift coordinates, preserving the integrity of the spherical projection.

Parameters (Uniforms)

Parameter Type Description
colorA vec3 Deep base color for low-density areas.
colorB vec3 Mid-tone color for noise transitions.
colorC vec3 Accent color for turbulence peaks.
discomode bool Toggles between static colors and an animated chromatic cycle.
speed float Velocity multiplier for the noise animation.
Shader code
shader_type canvas_item;

uniform vec3 colorA : source_color = vec3(0.2, 0.0, 0.1);
uniform vec3 colorB : source_color = vec3(0.7, 0.3, 0.4);
uniform vec3 colorC : source_color = vec3(1.0, 0.2, 0.4);
uniform bool discomode = false;
uniform float speed : hint_range(0.1, 2.0) = 1.0;

#define iTime (TIME * speed)

float rand(vec4 p) {
    return fract(sin(p.x*1234. + p.y*2345. + p.z*3456. + p.w*4567.) * 5678.);
}

float smoothnoise(vec4 p) {
    const vec2 e = vec2(0.0, 1.0);
    vec4 i = floor(p);    // integer
    vec4 f = fract(p);    // fract
    
    f = f*f*(3. - 2.*f);
    
    return mix(mix(mix(mix(rand(i + e.xxxx),
                           rand(i + e.yxxx), f.x),
                       mix(rand(i + e.xyxx),
                           rand(i + e.yyxx), f.x), f.y),
                   mix(mix(rand(i + e.xxyx),
                           rand(i + e.yxyx), f.x),
                       mix(rand(i + e.xyyx),
                           rand(i + e.yyyx), f.x), f.y), f.z),
               mix(mix(mix(rand(i + e.xxxy),
                           rand(i + e.yxxy), f.x),
                       mix(rand(i + e.xyxy),
                           rand(i + e.yyxy), f.x), f.y),
                   mix(mix(rand(i + e.xxyy),
                           rand(i + e.yxyy), f.x),
                       mix(rand(i + e.xyyy),
                           rand(i + e.yyyy), f.x), f.y), f.z), f.w);
}

float fbm(vec3 x) {
    float v = 0.0;
    float a = 0.5;
    vec3 shift = vec3(1.0);
    for (int i = 0; i < 10; ++i) {
        v += a * smoothnoise(vec4(x, cos(iTime * 0.002) * 200.0));
        x = x * 2.0 + shift;
        a *= 0.5;
    }
    return v;
}

vec3 uvTo3D(vec2 uv) {
    float theta = uv.x * 2.0 * 3.14159265359; // Longitud
    float phi = uv.y * 3.14159265359; // Latitud
    float x = sin(phi) * cos(theta);
    float y = sin(phi) * sin(theta);
    float z = cos(phi);
    return vec3(x, y, z);
}

float max3 (vec3 v) {
  return max (max (v.x, v.y), v.z);
}

void fragment() {
    vec3 col_a = colorA;
    vec3 col_b = colorB;
    vec3 col_c = colorC;
    
    if(discomode){
        col_a = vec3(sin(iTime), sin(iTime + 7.0), cos(iTime));
        col_b = vec3(cos(iTime), cos(iTime + 7.0), sin(iTime));
        col_c = vec3(sin(iTime), cos(iTime), sin(iTime + 0.5));
    }
    
    vec2 uv = UV;
    vec3 pos = uvTo3D(uv);
    
    pos.y += sin(iTime / 5.0);
    pos.x += cos(iTime / 5.0);
    pos.z += sin(iTime / 5.0);
    
    float fbmm = fbm(pos);
    vec3 q = vec3(fbmm, sin(fbmm), cos(fbmm));
    vec3 r = vec3(fbmm, sin(fbmm), cos(fbmm));
    float v = fbm(pos + 5.0 * r + iTime * 0.005);
    
    vec3 col_top = vec3(1.0);
    vec3 col_bot = vec3(0.0);
    
    vec3 res_color = mix(col_a, col_b, clamp(r, 0.0, 1.0));
    res_color = mix(res_color, col_c, clamp(q, 0.0, 1.0));
    
    float poss = v * 2.0 - 1.0;
    res_color = mix(res_color, col_top, clamp(poss, 0.0, 1.0));
    res_color = mix(res_color, col_bot, clamp(-poss, 0.0, 1.0));
    
    res_color = res_color / max(max3(res_color), 0.001);
    
    res_color = (clamp((0.4 * pow(v, 3.0) + pow(v, 2.0) + 0.5 * v), 0.0, 1.0) * 0.9 + 0.1) * res_color;

    COLOR = vec4(res_color, 1.0);
}
Live Preview
Tags
4DNoise, animated, Equirectangular, fbm, FluidDynamics, godotshader, planet, Procedural, space
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