bevy_render/
globals.rs

1use crate::{
2    extract_resource::ExtractResource,
3    render_resource::{ShaderType, UniformBuffer},
4    renderer::{RenderDevice, RenderQueue},
5    Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
6};
7use bevy_app::{App, Plugin};
8use bevy_diagnostic::FrameCount;
9use bevy_ecs::prelude::*;
10use bevy_reflect::prelude::*;
11use bevy_shader::load_shader_library;
12use bevy_time::Time;
13
14pub struct GlobalsPlugin;
15
16impl Plugin for GlobalsPlugin {
17    fn build(&self, app: &mut App) {
18        load_shader_library!(app, "globals.wgsl");
19        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
20            render_app
21                .init_resource::<GlobalsBuffer>()
22                .init_resource::<Time>()
23                .add_systems(ExtractSchedule, (extract_frame_count, extract_time))
24                .add_systems(
25                    Render,
26                    prepare_globals_buffer.in_set(RenderSystems::PrepareResources),
27                );
28        }
29    }
30}
31
32fn extract_frame_count(mut commands: Commands, frame_count: Extract<Res<FrameCount>>) {
33    commands.insert_resource(**frame_count);
34}
35
36fn extract_time(mut commands: Commands, time: Extract<Res<Time>>) {
37    commands.insert_resource(**time);
38}
39
40/// Contains global values useful when writing shaders.
41/// Currently only contains values related to time.
42#[derive(Default, Clone, Resource, ExtractResource, Reflect, ShaderType)]
43#[reflect(Resource, Default, Clone)]
44pub struct GlobalsUniform {
45    /// The time since startup in seconds.
46    /// Wraps to 0 after 1 hour.
47    time: f32,
48    /// The delta time since the previous frame in seconds
49    delta_time: f32,
50    /// Frame count since the start of the app.
51    /// It wraps to zero when it reaches the maximum value of a u32.
52    frame_count: u32,
53    /// WebGL2 structs must be 16 byte aligned.
54    #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
55    _wasm_padding: f32,
56}
57
58/// The buffer containing the [`GlobalsUniform`]
59#[derive(Resource, Default)]
60pub struct GlobalsBuffer {
61    pub buffer: UniformBuffer<GlobalsUniform>,
62}
63
64fn prepare_globals_buffer(
65    render_device: Res<RenderDevice>,
66    render_queue: Res<RenderQueue>,
67    mut globals_buffer: ResMut<GlobalsBuffer>,
68    time: Res<Time>,
69    frame_count: Res<FrameCount>,
70) {
71    let buffer = globals_buffer.buffer.get_mut();
72    buffer.time = time.elapsed_secs_wrapped();
73    buffer.delta_time = time.delta_secs();
74    buffer.frame_count = frame_count.0;
75
76    globals_buffer
77        .buffer
78        .write_buffer(&render_device, &render_queue);
79}