bevy_volumetric_clouds/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod compute;
4/// Controls the compute shader which renders the volumetric clouds.
5pub mod config;
6/// A utility plugin to control the camera using keyboard and mouse.
7#[cfg(feature = "fly_camera")]
8pub mod fly_camera;
9mod images;
10mod render;
11mod skybox;
12#[cfg(feature = "debug")]
13mod ui;
14mod uniforms;
15use bevy::prelude::*;
16
17#[cfg(feature = "debug")]
18use self::ui::ui_system;
19#[cfg(feature = "debug")]
20use bevy_egui::EguiPrimaryContextPass;
21
22use crate::{
23    compute::CameraMatrices,
24    config::CloudsConfig,
25    images::build_images,
26    render::{CloudsMaterial, CloudsShaderPlugin},
27    skybox::{SkyboxMaterials, init_skybox_mesh, setup_daylight, update_skybox_transform},
28    uniforms::CloudsImage,
29};
30
31use self::compute::CloudsComputePlugin;
32
33/// A plugin for rendering clouds.
34///
35/// The configuration of the clouds can be changed using the [`CloudsConfig`] resource.
36pub struct CloudsPlugin;
37
38impl Plugin for CloudsPlugin {
39    fn build(&self, app: &mut App) {
40        app.insert_resource(CloudsConfig::default())
41            .add_plugins((CloudsComputePlugin, CloudsShaderPlugin))
42            .add_systems(Startup, (clouds_setup, setup_daylight))
43            .add_systems(
44                PostUpdate,
45                (update_skybox_transform, update_camera_matrices)
46                    .after(TransformSystems::Propagate),
47            );
48        #[cfg(feature = "debug")]
49        app.add_systems(EguiPrimaryContextPass, ui_system);
50    }
51}
52
53fn clouds_setup(
54    mut commands: Commands,
55    images: ResMut<Assets<Image>>,
56    meshes: ResMut<Assets<Mesh>>,
57    mut materials: ResMut<Assets<CloudsMaterial>>,
58) {
59    let (cloud_render_image, cloud_atlas_image, cloud_worley_image, sky_image) =
60        build_images(images);
61
62    let material = materials.add(CloudsMaterial {
63        cloud_render_image: cloud_render_image.clone(),
64        cloud_atlas_image: cloud_atlas_image.clone(),
65        cloud_worley_image: cloud_worley_image.clone(),
66        sky_image: sky_image.clone(),
67    });
68    init_skybox_mesh(
69        &mut commands,
70        meshes,
71        SkyboxMaterials::from_one_material(MeshMaterial3d(material.clone())),
72    );
73    commands.insert_resource(CloudsImage {
74        cloud_render_image,
75        cloud_atlas_image,
76        cloud_worley_image,
77        sky_image,
78    });
79    commands.insert_resource(CameraMatrices {
80        translation: Vec3::ZERO,
81        inverse_camera_projection: Mat4::IDENTITY,
82        inverse_camera_view: Mat4::IDENTITY,
83    });
84}
85
86fn update_camera_matrices(
87    cam_query: Single<(&GlobalTransform, &Camera)>,
88    mut config: ResMut<CameraMatrices>,
89) {
90    let (camera_transform, camera) = *cam_query;
91    config.translation = camera_transform.translation();
92    config.inverse_camera_view = camera_transform.to_matrix();
93    config.inverse_camera_projection = camera.computed.clip_from_view.inverse();
94}