bevy_elements 0.5.1

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 water readback kernels, dispatched on readback ticks only:
//
//   downsample_depth     box mean of `water` over ds × ds cells (ds = 1 up to 1024², 2 above)
//   downsample_velocity  2 × 2 mean of `velocity` weighted by depth: Σ d v / Σ d, 0 where
//                        Σ d < 1e-3 m
//
// All bindings are read_write so the two entry points share one layout.

import bevy_elements::grid::GridParams;

struct HydroParams {
    grid: GridParams,
    sim: vec4<f32>,
    weather: vec4<f32>,
    misc: vec4<f32>,
    flags: vec4<u32>,
    erosion: vec4<f32>,
    thermal: vec4<f32>,
    // y: depth readback downsample factor.
    extra: vec4<f32>,
}

@group(0) @binding(0) var<uniform> params: HydroParams;
@group(0) @binding(1) var<storage, read_write> water: array<f32>;
@group(0) @binding(2) var<storage, read_write> velocity: array<vec2<f32>>;
@group(0) @binding(3) var<storage, read_write> depth_rb: array<f32>;
@group(0) @binding(4) var<storage, read_write> velocity_rb: array<vec2<f32>>;

const MIN_DEPTH_SUM: f32 = 1e-3;

@compute @workgroup_size(8, 8, 1)
fn downsample_depth(@builtin(global_invocation_id) id: vec3<u32>) {
    let ds = u32(params.extra.y);
    let out_size = params.grid.size / ds;
    if id.x >= out_size.x || id.y >= out_size.y {
        return;
    }
    var sum = 0.0;
    for (var j = 0u; j < ds; j += 1u) {
        for (var i = 0u; i < ds; i += 1u) {
            sum += water[(id.y * ds + j) * params.grid.size.x + id.x * ds + i];
        }
    }
    depth_rb[id.y * out_size.x + id.x] = sum / f32(ds * ds);
}

@compute @workgroup_size(8, 8, 1)
fn downsample_velocity(@builtin(global_invocation_id) id: vec3<u32>) {
    let out_size = params.grid.size / 2u;
    if id.x >= out_size.x || id.y >= out_size.y {
        return;
    }
    var weight = 0.0;
    var momentum = vec2<f32>(0.0);
    for (var j = 0u; j < 2u; j += 1u) {
        for (var i = 0u; i < 2u; i += 1u) {
            let k = (id.y * 2u + j) * params.grid.size.x + id.x * 2u + i;
            weight += water[k];
            momentum += water[k] * velocity[k];
        }
    }
    var mean = vec2<f32>(0.0);
    if weight >= MIN_DEPTH_SUM {
        mean = momentum / weight;
    }
    velocity_rb[id.y * out_size.x + id.x] = mean;
}