bevy_elements 0.7.8

Living environments for Bevy: sun, moon and stars, climate-driven weather, GPU wind, volumetric clouds, rain, snow and fog, lightning, terrain with hydraulic and thermal erosion, flooding, snow cover, wetness and dust — simulated in compute shaders.
Documentation
// The example ground: StandardMaterial lighting scaled by the cloud shadow map, as the research
// note's consumer mapping prescribes (docs/research/clouds.md, "Cloud shadow map"):
//
//     uv = (P.xz − l.xz · P.y / l.y − origin) / extent,   T = map(uv).r  (1 outside the map)
//
// The sun light already carries the factor 0.25 + 0.75 · T̄ for the camera; the pixel is scaled by
// the ratio of its own factor to the camera's.

import bevy_pbr::render::{
    pbr_fragment::pbr_input_from_standard_material,
    pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing},
    forward_io::{VertexOutput, FragmentOutput},
};

struct CloudShadowParams {
    // xy: map origin (world XZ), z: map extent, w: camera transmittance.
    map: vec4<f32>,
    // xyz: unit direction toward the light.
    light: vec4<f32>,
}

@group(constants::MATERIAL_BIND_GROUP) @binding(100) var<uniform> cloud: CloudShadowParams;
@group(constants::MATERIAL_BIND_GROUP) @binding(101) var cloud_map: texture_2d<f32>;
@group(constants::MATERIAL_BIND_GROUP) @binding(102) var cloud_sampler: sampler;

@fragment
fn fragment(in: VertexOutput, @builtin(front_facing) is_front: bool) -> FragmentOutput {
    var pbr_input = pbr_input_from_standard_material(in, is_front);

    var out: FragmentOutput;
    out.color = apply_pbr_lighting(pbr_input);

    let l = cloud.light.xyz;
    var t = 1.0;
    if l.y > 0.1 {
        let p = in.world_position.xyz;
        let uv = (p.xz - l.xz * (p.y / l.y) - cloud.map.xy) / cloud.map.z;
        if all(uv >= vec2<f32>(0.0)) && all(uv <= vec2<f32>(1.0)) {
            t = textureSampleLevel(cloud_map, cloud_sampler, uv, 0.0).r;
        }
    }
    let here = 0.25 + 0.75 * t;
    let camera = max(0.25 + 0.75 * cloud.map.w, 0.01);
    out.color = vec4<f32>(out.color.rgb * (here / camera), out.color.a);
    out.color = main_pass_post_lighting_processing(pbr_input, out.color);
    return out;
}