Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - add globals to mesh view bind group #5409

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 16 additions & 42 deletions assets/shaders/animate_shader.wgsl
Original file line number Diff line number Diff line change
@@ -1,39 +1,7 @@
#import bevy_pbr::mesh_types
// The time since startup data is in the globals binding which is part of the mesh_view_bindings import
#import bevy_pbr::mesh_view_bindings
Comment on lines +2 to 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about 2d users? They may not depend on bevy_pbr, but it's possible they still want to access the globals binding.

Possible solutions (imo):

  • make the globals binding available also in bevy_sprite::mesh2d_view_bindings
  • have an example with sprites that shows importing mesh_view_bindings from bevy_pbr

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll address this in a follow up PR. I honestly didn't think of that. I'll probably add the bindings to mesh2d_view_bindings. Although, I wonder if we could have some sort of "core" bindings that are shared between both.


@group(1) @binding(0)
var<uniform> mesh: Mesh;

// NOTE: Bindings must come before functions that use them!
#import bevy_pbr::mesh_functions

struct Vertex {
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
@location(2) uv: vec2<f32>,
};

struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) uv: vec2<f32>,
};

@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = mesh_position_local_to_clip(mesh.model, vec4<f32>(vertex.position, 1.0));
out.uv = vertex.uv;
return out;
}


struct Time {
time_since_startup: f32,
};
@group(2) @binding(0)
var<uniform> time: Time;


fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
let L = c.x;
let a = c.y;
Expand All @@ -43,22 +11,28 @@ fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
let m_ = L - 0.1055613458 * a - 0.0638541728 * b;
let s_ = L - 0.0894841775 * a - 1.2914855480 * b;

let l = l_*l_*l_;
let m = m_*m_*m_;
let s = s_*s_*s_;
let l = l_ * l_ * l_;
let m = m_ * m_ * m_;
let s = s_ * s_ * s_;

return vec3<f32>(
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,
);
}

struct FragmentInput {
#import bevy_pbr::mesh_vertex_output
}

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
let speed = 2.0;
let t_1 = sin(time.time_since_startup * speed) * 0.5 + 0.5;
let t_2 = cos(time.time_since_startup * speed);
// The globals binding contains various global values like time
// which is the time since startup in seconds
let t_1 = sin(globals.time * speed) * 0.5 + 0.5;
let t_2 = cos(globals.time * speed);

let distance_to_center = distance(in.uv, vec2<f32>(0.5)) * 1.4;

Expand Down
9 changes: 9 additions & 0 deletions crates/bevy_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
mod name;
mod task_pool_options;

use bevy_ecs::system::Resource;
pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable};
pub use name::*;
pub use task_pool_options::*;
Expand Down Expand Up @@ -37,6 +38,8 @@ impl Plugin for CorePlugin {

register_rust_types(app);
register_math_types(app);

app.init_resource::<FrameCount>();
}
}

Expand Down Expand Up @@ -83,3 +86,9 @@ fn register_math_types(app: &mut App) {
.register_type::<bevy_math::DQuat>()
.register_type::<bevy_math::Quat>();
}

/// Keeps a count of rendered frames since the start of the app
///
/// Wraps to 0 when it reaches the maximum u32 value
#[derive(Default, Resource, Clone, Copy)]
pub struct FrameCount(pub u32);
1 change: 1 addition & 0 deletions crates/bevy_diagnostic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" }
bevy_log = { path = "../bevy_log", version = "0.9.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.9.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
bevy_core = { path = "../bevy_core", version = "0.9.0-dev" }
22 changes: 4 additions & 18 deletions crates/bevy_diagnostic/src/frame_time_diagnostics_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
use crate::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_app::prelude::*;
use bevy_ecs::system::{Res, ResMut, Resource};
use bevy_core::FrameCount;
use bevy_ecs::system::{Res, ResMut};
use bevy_time::Time;

/// Adds "frame time" diagnostic to an App, specifically "frame time", "fps" and "frame count"
#[derive(Default)]
pub struct FrameTimeDiagnosticsPlugin;

#[derive(Resource)]
pub struct FrameTimeDiagnosticsState {
frame_count: u64,
}

impl Plugin for FrameTimeDiagnosticsPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.add_startup_system(Self::setup_system)
.insert_resource(FrameTimeDiagnosticsState { frame_count: 0 })
.add_system(Self::diagnostic_system);
}
}
Expand All @@ -36,12 +31,9 @@ impl FrameTimeDiagnosticsPlugin {
pub fn diagnostic_system(
mut diagnostics: ResMut<Diagnostics>,
time: Res<Time>,
mut state: ResMut<FrameTimeDiagnosticsState>,
frame_count: Res<FrameCount>,
) {
diagnostics.add_measurement(Self::FRAME_COUNT, || {
state.frame_count = state.frame_count.wrapping_add(1);
state.frame_count as f64
});
diagnostics.add_measurement(Self::FRAME_COUNT, || frame_count.0 as f64);

if time.delta_seconds_f64() == 0.0 {
return;
Expand All @@ -52,9 +44,3 @@ impl FrameTimeDiagnosticsPlugin {
diagnostics.add_measurement(Self::FPS, || 1.0 / time.delta_seconds_f64());
}
}

impl FrameTimeDiagnosticsState {
pub fn reset_frame_count(&mut self) {
self.frame_count = 0;
}
}
20 changes: 19 additions & 1 deletion crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use bevy_math::{Mat3A, Mat4, Vec2};
use bevy_reflect::TypeUuid;
use bevy_render::{
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
globals::{GlobalsBuffer, GlobalsUniform},
mesh::{
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
GpuBufferInfo, Mesh, MeshVertexBufferLayout,
Expand Down Expand Up @@ -383,6 +384,16 @@ impl FromWorld for MeshPipeline {
},
count: None,
},
BindGroupLayoutEntry {
binding: 9,
visibility: ShaderStages::VERTEX_FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(GlobalsUniform::min_size()),
},
count: None,
},
],
label: Some("mesh_view_layout"),
});
Expand Down Expand Up @@ -469,6 +480,7 @@ impl FromWorld for MeshPipeline {
),
}
};

MeshPipeline {
view_layout,
mesh_layout,
Expand Down Expand Up @@ -764,11 +776,13 @@ pub fn queue_mesh_view_bind_groups(
global_light_meta: Res<GlobalLightMeta>,
view_uniforms: Res<ViewUniforms>,
views: Query<(Entity, &ViewShadowBindings, &ViewClusterBindings)>,
globals_buffer: Res<GlobalsBuffer>,
) {
if let (Some(view_binding), Some(light_binding), Some(point_light_binding)) = (
if let (Some(view_binding), Some(light_binding), Some(point_light_binding), Some(globals)) = (
view_uniforms.uniforms.binding(),
light_meta.view_gpu_lights.binding(),
global_light_meta.gpu_point_lights.binding(),
globals_buffer.buffer.binding(),
) {
for (entity, view_shadow_bindings, view_cluster_bindings) in &views {
let view_bind_group = render_device.create_bind_group(&BindGroupDescriptor {
Expand Down Expand Up @@ -815,6 +829,10 @@ pub fn queue_mesh_view_bind_groups(
binding: 8,
resource: view_cluster_bindings.offsets_and_counts_binding().unwrap(),
},
BindGroupEntry {
binding: 9,
resource: globals.clone(),
},
],
label: Some("mesh_view_bind_group"),
layout: &mesh_pipeline.view_layout,
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/render/mesh_view_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ var<storage> cluster_light_index_lists: ClusterLightIndexLists;
@group(0) @binding(8)
var<storage> cluster_offsets_and_counts: ClusterOffsetsAndCounts;
#endif

@group(0) @binding(9)
var<uniform> globals: Globals;
11 changes: 11 additions & 0 deletions crates/bevy_pbr/src/render/mesh_view_types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,14 @@ struct ClusterOffsetsAndCounts {
data: array<vec4<u32>>,
};
#endif

struct Globals {
// The time since startup in seconds
IceSentry marked this conversation as resolved.
Show resolved Hide resolved
// 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.
IceSentry marked this conversation as resolved.
Show resolved Hide resolved
// It wraps to zero when it reaches the maximum value of a u32.
frame_count: u32,
}
67 changes: 67 additions & 0 deletions crates/bevy_render/src/globals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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)
IceSentry marked this conversation as resolved.
Show resolved Hide resolved
.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.
IceSentry marked this conversation as resolved.
Show resolved Hide resolved
/// 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.seconds_since_startup_wrapped_f32();
buffer.delta_time = time.delta_seconds();
buffer.frame_count = frame_count.0;

globals_buffer
.buffer
.write_buffer(&render_device, &render_queue);
}
26 changes: 25 additions & 1 deletion crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod color;
pub mod extract_component;
mod extract_param;
pub mod extract_resource;
pub mod globals;
pub mod mesh;
pub mod primitives;
pub mod rangefinder;
Expand All @@ -18,6 +19,7 @@ mod spatial_bundle;
pub mod texture;
pub mod view;

use bevy_core::FrameCount;
use bevy_hierarchy::ValidParentCheckPlugin;
pub use extract_param::Extract;

Expand All @@ -34,6 +36,7 @@ pub mod prelude {
};
}

use globals::GlobalsPlugin;
pub use once_cell;
use prelude::ComputedVisibility;

Expand Down Expand Up @@ -324,7 +327,9 @@ impl Plugin for RenderPlugin {
.add_plugin(MeshPlugin)
// NOTE: Load this after renderer initialization so that it knows about the supported
// compressed texture formats
.add_plugin(ImagePlugin);
.add_plugin(ImagePlugin)
.add_plugin(GlobalsPlugin)
.add_plugin(FrameCountPlugin);
}
}

Expand Down Expand Up @@ -358,3 +363,22 @@ fn extract(app_world: &mut World, render_app: &mut App) {
// see <https://github.com/bevyengine/bevy/issues/5082>
extract.apply_buffers(running_world);
}

pub struct FrameCountPlugin;
impl Plugin for FrameCountPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.add_system(update_frame_count);

if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.add_system_to_stage(RenderStage::Extract, extract_frame_count);
}
}
}

fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
frame_count.0 = frame_count.0.wrapping_add(1);
}

fn extract_frame_count(mut commands: Commands, frame_count: Extract<Res<FrameCount>>) {
commands.insert_resource(**frame_count);
}
Loading