AAA Fake Volumetric Clouds

A stylized procedural sky shader that fakes volumetric clouds using layered 2D noise and dynamic lighting.

 

Features:

– Fake volumetric cloud shading

– Dynamic sun lighting

– Horizon color blending

– Animated cloud evolution

– Adjustable cloud density and softness

– Optimized for real-time use

– Distance fading for atmospheric depth

 

Designed for stylized and semi-realistic skies in Godot 4.

Tutorial will be uploaded soon 

Shader code
//BY VELVET KATANA STUDIOS
//no copyrights but please support if you can, thank you 

shader_type sky;
render_mode use_half_res_pass;

// =====================================================
// TEXTURES
// =====================================================

uniform sampler2D base_sky_texture : source_color;
uniform sampler2D cloud_noise_texture : source_color;

// =====================================================
// SKY
// =====================================================

uniform float sky_exposure :
    hint_range(0.1, 5.0) = 1.0;

uniform vec3 sky_tint : source_color =
    vec3(1.0);

// =====================================================
// CLOUD SHAPE
// =====================================================

uniform float cloud_scale = 1.9;

uniform float cloud_density :
    hint_range(0.0, 1.0) = 0.52;

uniform float cloud_softness :
    hint_range(0.01, 1.0) = 0.16;

uniform float detail_strength :
    hint_range(0.0, 2.0) = 0.7;

uniform float cloud_contrast :
    hint_range(0.5, 3.0) = 1.35;

// =====================================================
// CLOUD COLORS
// =====================================================

uniform vec3 cloud_bright_color : source_color =
    vec3(1.0, 1.0, 1.0);

uniform vec3 cloud_mid_color : source_color =
    vec3(0.82, 0.84, 0.88);

uniform vec3 cloud_dark_color : source_color =
    vec3(0.50, 0.54, 0.62);

uniform float cloud_brightness :
    hint_range(0.0, 3.0) = 1.15;

// =====================================================
// ATMOSPHERIC CLOUD BLENDING
// =====================================================

uniform float atmosphere_blend :
    hint_range(0.0, 1.0) = 0.22;

uniform float atmosphere_horizon_strength :
    hint_range(0.0, 2.0) = 1.0;

uniform float atmosphere_zenith_strength :
    hint_range(0.0, 2.0) = 0.35;

// =====================================================
// MOVEMENT
// =====================================================

uniform vec2 cloud_direction =
    vec2(0.0, -1.0);

uniform float cloud_speed = 0.01;

// cloud evolution
uniform float cloud_evolution_speed :
    hint_range(0.0, 0.1) = 0.01;

// edge turbulence
uniform float edge_warp_strength :
    hint_range(0.0, 1.0) = 0.08;

uniform float edge_warp_scale = 3.0;

// =====================================================
// CLOUD DISTRIBUTION
// =====================================================

uniform float horizon_fade :
    hint_range(0.0, 1.0) = 0.18;

uniform float zenith_density :
    hint_range(0.0, 2.0) = 1.0;

uniform float horizon_blend :
    hint_range(0.0, 1.0) = 0.35;

// =====================================================
// SUN
// =====================================================

// same direction as DirectionalLight3D
uniform vec3 sun_direction =
    vec3(0.4, 0.5, 0.2);

uniform vec3 sun_color : source_color =
    vec3(1.0, 0.96, 0.88);

// tiny realistic point sun
uniform float sun_size :
    hint_range(0.0005, 0.05) = 0.004;

uniform float sun_intensity :
    hint_range(0.0, 30.0) = 14.0;

// =====================================================
// RANDOM LIGHT PATCHES
// =====================================================

uniform float random_light_strength :
    hint_range(0.0, 2.0) = 0.4;

uniform float random_light_scale = 0.7;

// =====================================================

void sky() {

    vec2 uv = SKY_COORDS;

    // =================================================
    // BASE SKY
    // =================================================

    vec3 base_sky =
        texture(base_sky_texture, uv).rgb;

    base_sky *= sky_tint * sky_exposure;

    vec3 dir = normalize(EYEDIR);

    // =================================================
    // CLOUD PROJECTION
    // =================================================

    vec2 cloud_uv = dir.xz;

    cloud_uv /= max(dir.y + 0.15, 0.15);

    cloud_uv *= cloud_scale;

    cloud_uv +=
        cloud_direction
        * TIME
        * cloud_speed;

    // =================================================
    // CLOUD EVOLUTION
    // =================================================

    vec2 evolution_offset =
        vec2(
            sin(TIME * cloud_evolution_speed),
            cos(TIME * cloud_evolution_speed * 0.83)
        ) * 0.35;

    vec2 macro_shift =
        vec2(
            sin(TIME * 0.003),
            cos(TIME * 0.0027)
        ) * 0.12;

    // =================================================
    // NOISE
    // =================================================

    float base_noise =
        texture(
            cloud_noise_texture,
            cloud_uv + macro_shift
        ).r;

    float secondary_noise =
        texture(
            cloud_noise_texture,
            cloud_uv * 0.55
            + vec2(0.23, 0.37)
            + evolution_offset * 0.4
        ).r;

    float detail_noise =
        texture(
            cloud_noise_texture,
            cloud_uv * 2.4
            + evolution_offset
        ).r;

    float noise =
        base_noise +
        secondary_noise * 0.5 -
        detail_noise * detail_strength;

    // =================================================
    // EDGE TURBULENCE
    // =================================================

    float edge_noise =
        texture(
            cloud_noise_texture,
            cloud_uv * edge_warp_scale
            + evolution_offset * 1.7
        ).r;

    edge_noise =
        (edge_noise - 0.5)
        * edge_warp_strength;

    noise +=
        edge_noise *
        (1.0 - abs(noise - 0.5) * 2.0);

    noise = clamp(noise, 0.0, 1.0);

    noise = pow(noise, cloud_contrast);

    // =================================================
    // CLOUD MASK
    // =================================================

    float clouds = smoothstep(
        cloud_density,
        cloud_density + cloud_softness,
        noise
    );

    float overhead_mask =
        pow(max(dir.y, 0.0), 0.35);

    clouds *= mix(
        horizon_fade,
        zenith_density,
        overhead_mask
    );

    // =================================================
    // LIGHT DIRECTION
    // =================================================

    vec3 light_dir =
        normalize(-sun_direction);

    float sun_dot =
        dot(dir, light_dir);

    // =================================================
    // POINT SUN WITH CLOUD OCCLUSION
    // =================================================

    float sun_core =
        smoothstep(
            1.0 - sun_size,
            1.0 - sun_size * 0.35,
            sun_dot
        );

    // sharp glow
    float sun_glow =
        pow(
            clamp(sun_dot, 0.0, 1.0),
            120.0
        );

    // wide atmospheric glow
    float wide_glow =
        pow(
            clamp(sun_dot, 0.0, 1.0),
            18.0
        ) * 0.18;

    // =================================================
    // CLOUD THICKNESS
    // =================================================

    float thickness =
        smoothstep(0.2, 0.9, noise);

    // =================================================
    // CLOUD OCCLUSION
    // =================================================

    float glow_occlusion =
        1.0 - clouds;

    glow_occlusion *=
        1.0 - thickness * 0.85;

    float sun_visibility =
        1.0 - clouds * 0.92;

    // =================================================
    // FINAL SUN LIGHT
    // =================================================

    vec3 sun_light =
        sun_color
        * sun_core
        * sun_intensity
        * sun_visibility;

    vec3 glow_light =
        sun_color
        * (
            sun_glow * 1.4 +
            wide_glow
        )
        * glow_occlusion;

    // =================================================
    // CLOUD LIGHTING
    // =================================================

    float sun_height =
        light_dir.y;

    // 1 = day
    // 0 = sunset
    float day_factor =
        clamp(
            sun_height * 3.0,
            0.0,
            1.0
        );

    // top lit during day
    float top_light =
        max(dir.y, 0.0);

    // bottom lit during sunset
    float bottom_light =
        pow(
            1.0 - max(dir.y, 0.0),
            1.5
        );

    // invert lighting direction
    float vertical_light =
        mix(
            bottom_light,
            top_light,
            day_factor
        );

    float sun_wrap =
        pow(
            clamp(
                dot(dir, light_dir) * 0.5 + 0.5,
                0.0,
                1.0
            ),
            1.5
        );

    // glowing cloud edges
    float edge_light =
        pow(
            1.0 - thickness,
            2.2
        ) * vertical_light
        * sun_wrap;

    // dense body shadowing
    float body_shadow =
        thickness * mix(
            0.45,
            0.75,
            day_factor
        );

    // =================================================
    // RANDOM LIGHT SCATTERING
    // =================================================

    float random_light =
        texture(
            cloud_noise_texture,
            cloud_uv * random_light_scale
            + evolution_offset * 0.2
        ).r;

    random_light =
        smoothstep(
            0.6,
            0.92,
            random_light
        );

    // =================================================
    // FINAL LIGHTING
    // =================================================

    float lighting =
        edge_light * 1.3
        + random_light
            * random_light_strength
        - body_shadow
        - thickness * 0.15;

    lighting = clamp(lighting, 0.0, 1.0);

    // =================================================
    // CLOUD COLOR
    // =================================================

    vec3 cloud_color =
        mix(
            cloud_dark_color,
            cloud_mid_color,
            lighting
        );

    cloud_color =
        mix(
            cloud_color,
            cloud_bright_color,
            edge_light
        );

    // =================================================
    // ATMOSPHERIC BLENDING
    // =================================================

    float atmosphere_factor =
        mix(
            atmosphere_horizon_strength,
            atmosphere_zenith_strength,
            max(dir.y, 0.0)
        );

    atmosphere_factor *= atmosphere_blend;

    cloud_color = mix(
        cloud_color,
        base_sky,
        atmosphere_factor
    );

    cloud_color *= cloud_brightness;

    // =================================================
    // HORIZON ATMOSPHERE
    // =================================================

    float horizon_amount =
        pow(
            1.0 - max(dir.y, 0.0),
            2.5
        );

    cloud_color = mix(
        cloud_color,
        base_sky,
        horizon_amount * horizon_blend
    );

    // =================================================
    // FINAL SKY
    // =================================================

    vec3 sky_with_sun =
        base_sky +
        glow_light +
        sun_light;

    vec3 final_color =
        mix(
            sky_with_sun,
            cloud_color,
            clouds
        );

    COLOR = final_color;
}
Tags
animated clouds, atmosphere, clouds, dynamic sky, fake volumetric, godot4, lighting, noise, optimized, Procedural, sky, stylized, volumetric
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

guest

0 Comments
Oldest
Newest Most Voted