diff --git a/bevy_nannou_draw/src/draw/render/instancing.wgsl b/bevy_nannou_draw/src/draw/render/instancing.wgsl index 856022536..4957824a0 100644 --- a/bevy_nannou_draw/src/draw/render/instancing.wgsl +++ b/bevy_nannou_draw/src/draw/render/instancing.wgsl @@ -1,4 +1,4 @@ -#import bevy_pbr::mesh_functions::{get_model_matrix, mesh_position_local_to_clip} +#import bevy_pbr::mesh_functions::{get_world_from_local, mesh_position_local_to_clip} struct Vertex { @location(0) position: vec3, @@ -23,7 +23,7 @@ fn vertex(vertex: Vertex) -> VertexOutput { // index in the Mesh array. This index could be passed in via another // uniform instead but it's unnecessary for the example. out.clip_position = mesh_position_local_to_clip( - get_model_matrix(0u), + get_world_from_local(0u), vec4(position, 1.0) ); out.color = vec4(1.0, 0.0, 0.0, 1.0); diff --git a/examples/assets/shaders/particle_mouse.wgsl b/examples/assets/shaders/particle_mouse_compute.wgsl similarity index 81% rename from examples/assets/shaders/particle_mouse.wgsl rename to examples/assets/shaders/particle_mouse_compute.wgsl index b3a26f0c2..b53eff11f 100644 --- a/examples/assets/shaders/particle_mouse.wgsl +++ b/examples/assets/shaders/particle_mouse_compute.wgsl @@ -8,27 +8,6 @@ struct Particle { @group(0) @binding(1) var mouse: vec2; @group(0) @binding(2) var resolution: vec2; - -struct VertexOutput { - @builtin(position) clip_position: vec4, - @location(0) color: vec4, -}; - -@vertex -fn vertex(@builtin(vertex_index) vertex_index: u32) -> VertexOutput { - let particle = particles[vertex_index]; - - var out: VertexOutput; - out.clip_position = vec4(particle.position, 0.0, 1.0); - out.color = particle.color; - return out; -} - -@fragment -fn fragment(in: VertexOutput) -> @location(0) vec4 { - return in.color; -} - fn random(seed: vec2) -> f32 { return fract(sin(dot(seed, vec2(12.9898, 78.233))) * 43758.5453); } diff --git a/examples/assets/shaders/particle_mouse_material.wgsl b/examples/assets/shaders/particle_mouse_material.wgsl new file mode 100644 index 000000000..d1e073388 --- /dev/null +++ b/examples/assets/shaders/particle_mouse_material.wgsl @@ -0,0 +1,34 @@ +#import bevy_pbr::mesh_functions::{get_world_from_local, mesh_position_local_to_clip} +#import bevy_pbr::forward_io::{Vertex} + +struct Particle { + position: vec2, + velocity: vec2, + color: vec4, +}; + +@group(2) @binding(0) var particles: array; + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) color: vec4, +}; + +@vertex +fn vertex(vertex: Vertex) -> VertexOutput { + let particle = particles[vertex.instance_index]; + var out: VertexOutput; + let position = vec4(particle.position, 0.0, 1.0);; + out.clip_position = mesh_position_local_to_clip( + get_world_from_local(0u), + position + ); + + out.color = particle.color; + return out; +} + +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4 { + return in.color; +} \ No newline at end of file diff --git a/examples/compute/game_of_life.rs b/examples/compute/game_of_life.rs index caea09c1d..3dfbff27e 100644 --- a/examples/compute/game_of_life.rs +++ b/examples/compute/game_of_life.rs @@ -42,7 +42,7 @@ impl Compute for ComputeModel { "shaders/game_of_life.wgsl".into() } - fn shader_entry(state: &Self::State) -> &'static str { + fn entry(state: &Self::State) -> &'static str { match state { State::Init => "init", State::Update(_) => "update", diff --git a/examples/compute/particle_mouse.rs b/examples/compute/particle_mouse.rs index ac0c45de6..ffc992b5f 100644 --- a/examples/compute/particle_mouse.rs +++ b/examples/compute/particle_mouse.rs @@ -1,9 +1,9 @@ -use bytemuck::{Pod, Zeroable}; use nannou::prelude::bevy_render::renderer::RenderDevice; +use nannou::prelude::bevy_render::storage::ShaderStorageBuffer; use nannou::prelude::*; use std::sync::Arc; -const NUM_PARTICLES: u32 = 10000; +const NUM_PARTICLES: u32 = 1000; const WORKGROUP_SIZE: u32 = 64; fn main() { @@ -11,11 +11,11 @@ fn main() { } struct Model { - particles: Buffer, + particles: Handle, } -#[derive(Default, Clone, Copy, Pod, Zeroable)] #[repr(C)] +#[derive(ShaderType, Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)] struct Particle { position: Vec2, velocity: Vec2, @@ -31,8 +31,8 @@ enum State { #[derive(AsBindGroup, Clone)] struct ComputeModel { - #[storage(0, buffer, visibility(compute, vertex))] - particles: Buffer, + #[storage(0, visibility(compute))] + particles: Handle, #[uniform(1)] mouse: Vec2, #[uniform(2)] @@ -46,7 +46,7 @@ impl Compute for ComputeModel { "shaders/particle_mouse.wgsl".into() } - fn shader_entry(state: &Self::State) -> &'static str { + fn entry(state: &Self::State) -> &'static str { match state { State::Init => "init", State::Update => "update", @@ -58,14 +58,12 @@ impl Compute for ComputeModel { } } -#[derive(AsBindGroup, Asset, TypePath, Clone)] +#[derive(AsBindGroup, Asset, TypePath, Clone, Default)] struct DrawMaterial { - #[storage(0, buffer, visibility(compute, vertex))] - particles: Buffer, + #[storage(0, visibility(vertex))] + particles: Handle, } - - impl Material for DrawMaterial { fn vertex_shader() -> ShaderRef { "shaders/particle_mouse.wgsl".into() @@ -83,18 +81,23 @@ fn model(app: &App) -> Model { .size(1024, 768) .view(view) .build(); - let device = app.resource_mut::(); - let particles = device.create_buffer_with_data(&BufferInitDescriptor { - label: Some("ParticleBuffer"), - contents: bytemuck::cast_slice(&vec![Particle::default(); NUM_PARTICLES as usize]), - usage: BufferUsages::STORAGE | BufferUsages::VERTEX, - }); + // Create a buffer to store the particles. + let particle_size = Particle::min_size().get() as usize; + let mut particles = ShaderStorageBuffer::with_size( + NUM_PARTICLES as usize * particle_size, + RenderAssetUsages::RENDER_WORLD, + ); + particles.buffer_description.usage |= BufferUsages::STORAGE | BufferUsages::VERTEX; + + let particles = app.assets_mut().add(particles.clone()); Model { particles } } -fn update(app: &App, model: &mut Model) {} +fn update(app: &App, model: &mut Model) { + +} fn compute(app: &App, model: &Model, state: State, view: Entity) -> (State, ComputeModel) { let window = app.main_window(); @@ -114,12 +117,13 @@ fn compute(app: &App, model: &Model, state: State, view: Entity) -> (State, Comp } fn view(app: &App, model: &Model) { - let draw = app.draw() - .material(DrawMaterial { - particles: model.particles.clone(), - }); - draw.background() - .color(BLACK); - draw.polyline() - .points(vec![Vec2::ZERO; NUM_PARTICLES as usize]); + let draw = app.draw().material(DrawMaterial { + particles: model.particles.clone(), + }); + draw.background().color(BLACK); + + for _ in 0..NUM_PARTICLES { + draw.rect() + .w_h(1.0, 1.0); + } } diff --git a/nannou/src/app.rs b/nannou/src/app.rs index d8955cc45..88f748a9f 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -56,8 +56,8 @@ use crate::prelude::bevy_ecs::system::SystemState; use crate::prelude::render::NannouMesh; use crate::prelude::NannouMaterialPlugin; use crate::render::{ - Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState, NannouRenderNode, - RenderApp, RenderPlugin, + compute::{Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState}, + NannouRenderNode, RenderApp, RenderPlugin }; use crate::window::WindowUserFunctions; use crate::{camera, geom, light, window}; @@ -258,8 +258,7 @@ where primary_window: None, exit_condition: ExitCondition::OnAllClosed, ..default() - }) - .set(ImagePlugin::default_nearest()), + }), #[cfg(feature = "egui")] bevy_egui::EguiPlugin, NannouPlugin, diff --git a/nannou/src/prelude.rs b/nannou/src/prelude.rs index 347c93687..42eb248bd 100644 --- a/nannou/src/prelude.rs +++ b/nannou/src/prelude.rs @@ -10,6 +10,7 @@ pub use bevy_egui::egui; pub use crate::frame::*; pub use crate::render::*; +pub use crate::render::compute::*; pub use crate::wgpu; pub use crate::wgpu::util::{BufferInitDescriptor, DeviceExt}; pub use bevy_nannou::prelude::*; diff --git a/nannou/src/render.rs b/nannou/src/render/compute.rs similarity index 71% rename from nannou/src/render.rs rename to nannou/src/render/compute.rs index 4ea1ff793..603bbdf8a 100644 --- a/nannou/src/render.rs +++ b/nannou/src/render/compute.rs @@ -6,6 +6,7 @@ use crate::prelude::bevy_render::{Extract, MainWorld}; use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; use bevy::ecs::entity::{EntityHash, EntityHashMap}; use bevy::ecs::query::QueryItem; +use bevy::ecs::system::StaticSystemParam; pub use bevy::prelude::*; use bevy::render::extract_component::ExtractComponentPlugin; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; @@ -37,131 +38,6 @@ use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; use wgpu::ComputePassDescriptor; -pub(crate) struct RenderPlugin(std::marker::PhantomData); - -impl Default for RenderPlugin -where - M: Send + Sync + Clone + 'static, -{ - fn default() -> Self { - Self(std::marker::PhantomData) - } -} - -impl Plugin for RenderPlugin -where - M: Send + Sync + Clone + 'static, -{ - fn build(&self, app: &mut App) { - let Some(render_app) = app.get_sub_app_mut(bevy::render::RenderApp) else { - return; - }; - - render_app.add_systems( - ExtractSchedule, - ( - extract_resource::>, - extract_resource::>, - ), - ); - } - - fn finish(&self, app: &mut App) { - let Some(render_app) = app.get_sub_app_mut(bevy::render::RenderApp) else { - return; - }; - - render_app - .add_render_graph_node::>>( - Core3d, - NannouRenderNodeLabel, - ) - .add_render_graph_edges( - Core3d, - ( - Node3d::MainTransparentPass, - NannouRenderNodeLabel, - Node3d::EndMainPass, - ), - ); - } -} - -pub struct RenderApp<'w> { - current_view: Option, - world: &'w World, -} - -impl<'w> RenderApp<'w> { - pub fn new(world: &'w World) -> Self { - Self { - current_view: None, - world, - } - } - - /// Get the elapsed seconds since startup. - pub fn time(&self) -> f32 { - let time = self.world.resource::