bevy/crates/bevy_render/src/globals.rs

68 lines
2 KiB
Rust
Raw Normal View History

add globals to mesh view bind group (#5409) # Objective - It's often really useful to have access to the time when writing shaders. ## Solution - Add a UnifformBuffer in the mesh view bind group - This buffer contains the time, delta time and a wrapping frame count https://user-images.githubusercontent.com/8348954/180130314-97948c2a-2d11-423d-a9c4-fb5c9d1892c7.mp4 --- ## Changelog - Added a `GlobalsUniform` at position 9 of the mesh view bind group ## Notes The implementation is currently split between bevy_render and bevy_pbr because I was basing my implementation on the `ViewPlugin`. I'm not sure if that's the right way to structure it. I named this `globals` instead of just time because we could potentially add more things to it. ## References in other engines - Godot: <https://docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/canvas_item_shader.html#global-built-ins> - Global time since startup, in seconds, by default resets to 0 after 3600 seconds - Doesn't seem to have anything else - Unreal: <https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/ExpressionReference/Constant/> - Generic time value that updates every frame. Can be paused or scaled. - Frame count node, doesn't seem to be an equivalent for shaders: <https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/Utilities/GetFrameCount/> - Unity: <https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html> - time since startup in seconds. No mention of time wrapping. Stored as a `vec4(t/20, t, t*2, t*3)` where `t` is the value in seconds - Also has delta time, sin time and cos time - ShaderToy: <https://www.shadertoy.com/howto> - iTime is the time since startup in seconds. - iFrameRate - iTimeDelta - iFrame frame counter Co-authored-by: Charles <IceSentry@users.noreply.github.com>
2022-09-28 04:20:27 +00:00
use crate::{
extract_resource::ExtractResource,
render_resource::{ShaderType, UniformBuffer},
renderer::{RenderDevice, RenderQueue},
Extract, RenderApp, RenderStage,
};
use bevy_app::{App, Plugin};
use bevy_core::FrameCount;
use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
use bevy_time::Time;
pub struct GlobalsPlugin;
impl Plugin for GlobalsPlugin {
fn build(&self, app: &mut App) {
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app
.init_resource::<GlobalsBuffer>()
.init_resource::<Time>()
.add_system_to_stage(RenderStage::Extract, extract_time)
.add_system_to_stage(RenderStage::Prepare, prepare_globals_buffer);
}
}
}
fn extract_time(mut commands: Commands, time: Extract<Res<Time>>) {
commands.insert_resource(time.clone());
}
/// Contains global values useful when writing shaders.
/// Currently only contains values related to time.
#[derive(Default, Clone, Resource, ExtractResource, Reflect, ShaderType)]
#[reflect(Resource)]
pub struct GlobalsUniform {
/// The time since startup in seconds.
/// Wraps to 0 after 1 hour.
time: f32,
/// The delta time since the previous frame in seconds
delta_time: f32,
/// Frame count since the start of the app.
/// It wraps to zero when it reaches the maximum value of a u32.
frame_count: u32,
}
/// The buffer containing the [`GlobalsUniform`]
#[derive(Resource, Default)]
pub struct GlobalsBuffer {
pub buffer: UniformBuffer<GlobalsUniform>,
}
fn prepare_globals_buffer(
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mut globals_buffer: ResMut<GlobalsBuffer>,
time: Res<Time>,
frame_count: Res<FrameCount>,
) {
let buffer = globals_buffer.buffer.get_mut();
buffer.time = time.elapsed_seconds_wrapped();
add globals to mesh view bind group (#5409) # Objective - It's often really useful to have access to the time when writing shaders. ## Solution - Add a UnifformBuffer in the mesh view bind group - This buffer contains the time, delta time and a wrapping frame count https://user-images.githubusercontent.com/8348954/180130314-97948c2a-2d11-423d-a9c4-fb5c9d1892c7.mp4 --- ## Changelog - Added a `GlobalsUniform` at position 9 of the mesh view bind group ## Notes The implementation is currently split between bevy_render and bevy_pbr because I was basing my implementation on the `ViewPlugin`. I'm not sure if that's the right way to structure it. I named this `globals` instead of just time because we could potentially add more things to it. ## References in other engines - Godot: <https://docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/canvas_item_shader.html#global-built-ins> - Global time since startup, in seconds, by default resets to 0 after 3600 seconds - Doesn't seem to have anything else - Unreal: <https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/ExpressionReference/Constant/> - Generic time value that updates every frame. Can be paused or scaled. - Frame count node, doesn't seem to be an equivalent for shaders: <https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/Utilities/GetFrameCount/> - Unity: <https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html> - time since startup in seconds. No mention of time wrapping. Stored as a `vec4(t/20, t, t*2, t*3)` where `t` is the value in seconds - Also has delta time, sin time and cos time - ShaderToy: <https://www.shadertoy.com/howto> - iTime is the time since startup in seconds. - iFrameRate - iTimeDelta - iFrame frame counter Co-authored-by: Charles <IceSentry@users.noreply.github.com>
2022-09-28 04:20:27 +00:00
buffer.delta_time = time.delta_seconds();
buffer.frame_count = frame_count.0;
globals_buffer
.buffer
.write_buffer(&render_device, &render_queue);
}