Skip to main content

bevy_render/
globals.rs

1use crate::{
2    extract_resource::ExtractResource,
3    render_resource::{ShaderType, UniformBuffer},
4    renderer::{RenderDevice, RenderQueue},
5    Extract, ExtractSchedule, GpuResourceAppExt, 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.wesl");
19        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
20            render_app
21                .init_gpu_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)]
44#[extract_app(RenderApp)]
45pub struct GlobalsUniform {
46    /// The time since startup in seconds.
47    /// Wraps to 0 after 1 hour.
48    time: f32,
49    /// The delta time since the previous frame in seconds
50    delta_time: f32,
51    /// Frame count since the start of the app.
52    /// It wraps to zero when it reaches `u32::MAX`.
53    frame_count: u32,
54    /// WebGL2 structs must be 16 byte aligned.
55    #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
56    _webgl2_padding: f32,
57}
58
59/// The buffer containing the [`GlobalsUniform`]
60#[derive(Resource, Default)]
61pub struct GlobalsBuffer {
62    pub buffer: UniformBuffer<GlobalsUniform>,
63}
64
65fn prepare_globals_buffer(
66    render_device: Res<RenderDevice>,
67    render_queue: Res<RenderQueue>,
68    mut globals_buffer: ResMut<GlobalsBuffer>,
69    time: Res<Time>,
70    frame_count: Res<FrameCount>,
71) {
72    let buffer = globals_buffer.buffer.get_mut();
73    buffer.time = time.elapsed_secs_wrapped();
74    buffer.delta_time = time.delta_secs();
75    buffer.frame_count = frame_count.0;
76
77    globals_buffer
78        .buffer
79        .write_buffer(&render_device, &render_queue);
80}