From 3a808f46da0d403440ed62b5fb0ea6826d8dec55 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Mon, 16 Sep 2024 22:16:19 -0700 Subject: [PATCH 1/9] Shader-model. --- Cargo.lock | 1 + bevy_nannou_draw/Cargo.toml | 1 + bevy_nannou_draw/src/draw/background.rs | 15 +- bevy_nannou_draw/src/draw/drawing.rs | 105 ++-- bevy_nannou_draw/src/draw/indirect.rs | 218 +-------- bevy_nannou_draw/src/draw/instanced.rs | 192 +------- bevy_nannou_draw/src/draw/mod.rs | 120 ++--- bevy_nannou_draw/src/draw/primitive/arrow.rs | 7 +- .../src/draw/primitive/ellipse.rs | 7 +- bevy_nannou_draw/src/draw/primitive/line.rs | 7 +- bevy_nannou_draw/src/draw/primitive/mesh.rs | 25 +- bevy_nannou_draw/src/draw/primitive/path.rs | 45 +- .../src/draw/primitive/polygon.rs | 21 +- bevy_nannou_draw/src/draw/primitive/quad.rs | 7 +- bevy_nannou_draw/src/draw/primitive/rect.rs | 7 +- bevy_nannou_draw/src/draw/primitive/text.rs | 7 +- bevy_nannou_draw/src/draw/primitive/tri.rs | 7 +- bevy_nannou_draw/src/nannou.wgsl | 86 ++++ bevy_nannou_draw/src/render.rs | 457 +++++++++++++++--- examples/compute/particle_mouse.rs | 2 +- examples/compute/particle_sdf.rs | 2 +- examples/draw/draw_custom_material.rs | 4 +- examples/video/video_material.rs | 2 +- nannou/src/app.rs | 11 +- nannou_osc/src/send.rs | 2 +- 25 files changed, 698 insertions(+), 660 deletions(-) create mode 100644 bevy_nannou_draw/src/nannou.wgsl diff --git a/Cargo.lock b/Cargo.lock index dd10aae4f..f17a91069 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1114,6 +1114,7 @@ name = "bevy_nannou_draw" version = "0.1.0" dependencies = [ "bevy", + "bitflags 2.6.0", "bytemuck", "lyon", "nannou_core", diff --git a/bevy_nannou_draw/Cargo.toml b/bevy_nannou_draw/Cargo.toml index 215a0554f..d550f0693 100644 --- a/bevy_nannou_draw/Cargo.toml +++ b/bevy_nannou_draw/Cargo.toml @@ -12,6 +12,7 @@ num-traits = "0.2" bytemuck = "1.15.0" rayon = { workspace = true } uuid = "1.8" +bitflags = "2.6.0" [features] nightly = [] \ No newline at end of file diff --git a/bevy_nannou_draw/src/draw/background.rs b/bevy_nannou_draw/src/draw/background.rs index fe0b2ab3c..c32d0c8a2 100644 --- a/bevy_nannou_draw/src/draw/background.rs +++ b/bevy_nannou_draw/src/draw/background.rs @@ -1,26 +1,27 @@ use bevy::prelude::{Color, Material}; use crate::draw::{Draw, DrawCommand}; +use crate::render::ShaderModel; /// A type used to update the background colour. -pub struct Background<'a, M> +pub struct Background<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - draw: &'a Draw, + draw: &'a Draw, } /// Begin coloring the background. -pub fn new(draw: &Draw) -> Background +pub fn new(draw: &Draw) -> Background where - M: Material + Default, + SM: ShaderModel + Default, { Background { draw } } -impl<'a, M> Background<'a, M> +impl<'a, SM> Background<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Clear the background with the given color. /// diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index 78ea6c210..bf120db1f 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -13,6 +13,7 @@ use crate::draw::properties::{ SetColor, SetDimensions, SetFill, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{Draw, DrawCommand, DrawRef}; +use crate::render::{DefaultNannouShaderModel, ShaderModel}; /// A **Drawing** in progress. /// @@ -24,12 +25,12 @@ use crate::draw::{Draw, DrawCommand, DrawRef}; /// inner **geom::Graph**. This ensures the correct instantiation order is maintained within the /// graph. As a result, each **Drawing** is associated with a single, unique node. Thus a /// **Drawing** can be thought of as a way of specifying properties for a node. -pub struct Drawing<'a, T, M> +pub struct Drawing<'a, T, SM> where - M: Material + Default, + SM: ShaderModel + Default, { // The `Draw` instance used to create this drawing. - draw: DrawRef<'a, M>, + draw: DrawRef<'a, SM>, // The draw command index of the primitive being drawn. pub(crate) index: usize, // The draw command index of the material being used. @@ -55,10 +56,10 @@ pub struct DrawingContext<'a> { } /// Construct a new **Drawing** instance. -pub fn new(draw: &Draw, index: usize, material_index: usize) -> Drawing +pub fn new(draw: &Draw, index: usize, material_index: usize) -> Drawing where T: Into, - M: Material + Default, + SM: ShaderModel + Default, { let _ty = PhantomData; let finish_on_drop = true; @@ -71,9 +72,9 @@ where } } -impl<'a, T, M> Drop for Drawing<'a, T, M> +impl<'a, T, SM> Drop for Drawing<'a, T, SM> where - M: Material + Default, + SM: ShaderModel + Default, { fn drop(&mut self) { if self.finish_on_drop { @@ -100,9 +101,9 @@ impl<'a> DrawingContext<'a> { } } -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where - M: Material + Default, + SM: ShaderModel + Default, { // Shared between the **finish** method and the **Drawing**'s **Drop** implementation. // @@ -122,7 +123,7 @@ where .get_mut(self.material_index) .expect("Expected a valid material index"); if let None = material_cmd { - *material_cmd = Some(DrawCommand::Material(id)); + *material_cmd = Some(DrawCommand::ShaderModel(id)); } } DrawRef::Borrowed(_) => (), @@ -141,9 +142,9 @@ where // Map the the parent's material to a new material type, taking ownership over the // draw instance clone. - pub fn map_material(mut self, map: F) -> Drawing<'a, T, M> + pub fn map_shader_model(mut self, map: F) -> Drawing<'a, T, SM> where - F: FnOnce(M) -> M, + F: FnOnce(SM) -> SM, { self.finish_on_drop = false; @@ -155,19 +156,19 @@ where } = self; let state = draw.state.clone(); - let material = state.read().unwrap().materials[&self.draw.material] - .downcast_ref::() + let material = state.read().unwrap().shader_models[&self.draw.material] + .downcast_ref::() .unwrap() .clone(); let new_id = UntypedAssetId::Uuid { - type_id: TypeId::of::(), + type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; let material = map(material.clone()); let mut state = state.write().unwrap(); - state.materials.insert(new_id.clone(), Box::new(material)); + state.shader_models.insert(new_id.clone(), Box::new(material)); // Mark the last material as the new material so that further drawings use the same material // as the parent draw ref. state.last_material = Some(new_id.clone()); @@ -192,7 +193,7 @@ where // Map the given function onto the primitive stored within **Draw** at `index`. // // The functionn is only applied if the node has not yet been **Drawn**. - fn map_primitive(mut self, map: F) -> Drawing<'a, T2, M> + fn map_primitive(mut self, map: F) -> Drawing<'a, T2, SM> where F: FnOnce(Primitive) -> Primitive, T2: Into + Clone, @@ -222,7 +223,7 @@ where // The same as `map_primitive` but also passes a mutable reference to the vertex data to the // map function. This is useful for types that may have an unknown number of arbitrary // vertices. - fn map_primitive_with_context(mut self, map: F) -> Drawing<'a, T2, M> + fn map_primitive_with_context(mut self, map: F) -> Drawing<'a, T2, SM> where F: FnOnce(Primitive, DrawingContext) -> Primitive, T2: Into + Clone, @@ -258,7 +259,7 @@ where /// The function is only applied if the node has not yet been **Drawn**. /// /// **Panics** if the primitive does not contain type **T**. - pub fn map_ty(self, map: F) -> Drawing<'a, T2, M> + pub fn map_ty(self, map: F) -> Drawing<'a, T2, SM> where F: FnOnce(T) -> T2, T2: Into + Clone, @@ -277,7 +278,7 @@ where /// The function is only applied if the node has not yet been **Drawn**. /// /// **Panics** if the primitive does not contain type **T**. - pub(crate) fn map_ty_with_context(self, map: F) -> Drawing<'a, T2, M> + pub(crate) fn map_ty_with_context(self, map: F) -> Drawing<'a, T2, SM> where F: FnOnce(T, DrawingContext) -> T2, T2: Into + Clone, @@ -294,10 +295,10 @@ where // SetColor implementations. -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetColor + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Specify a color. @@ -450,10 +451,10 @@ where // SetDimensions implementations. -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetDimensions + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Set the absolute width for the node. @@ -509,10 +510,10 @@ where // SetPosition methods. -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetPosition + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Build with the given **Absolute** **Position** along the *x* axis. @@ -553,10 +554,10 @@ where // SetOrientation methods. -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetOrientation + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Describe orientation via the vector that points to the given target. @@ -676,10 +677,10 @@ where // SetFill methods -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetFill + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Specify the whole set of fill tessellation options. @@ -720,10 +721,10 @@ where // SetStroke methods -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetStroke + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// The start line cap as specified by the SVG spec. @@ -862,51 +863,29 @@ where } } -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { } -impl<'a, T, M> Drawing<'a, T, ExtendedMaterial> +impl<'a, T> Drawing<'a, T, DefaultNannouShaderModel> where T: Into, - M: MaterialExtension + Default, { - pub fn roughness(self, roughness: f32) -> Self { - self.map_material(|mut material| { - material.base.perceptual_roughness = roughness; - material - }) - } - - pub fn metallic(self, metallic: f32) -> Self { - self.map_material(|mut material| { - material.base.metallic = metallic; - material - }) - } - pub fn base_color>(self, color: C) -> Self { - self.map_material(|mut material| { - material.base.base_color = color.into(); - material - }) - } - - pub fn emissive>(self, color: C) -> Self { - self.map_material(|mut material| { - material.base.emissive = color.into().to_linear(); - material + self.map_shader_model(|mut model| { + model.color = color.into(); + model }) } pub fn texture(self, texture: &Handle) -> Self { - self.map_material(|mut material| { - material.base.base_color_texture = Some(texture.clone()); - material + self.map_shader_model(|mut model| { + model.texture = Some(texture.clone()); + model }) } } diff --git a/bevy_nannou_draw/src/draw/indirect.rs b/bevy_nannou_draw/src/draw/indirect.rs index dfb4e5b5e..a1b3b2337 100644 --- a/bevy_nannou_draw/src/draw/indirect.rs +++ b/bevy_nannou_draw/src/draw/indirect.rs @@ -4,58 +4,48 @@ use crate::draw::drawing::Drawing; use crate::draw::primitive::Primitive; use crate::draw::{Draw, DrawCommand}; use crate::render::{PreparedShaderModel, ShaderModel}; -use bevy::core_pipeline::core_3d::Opaque3dBinKey; -use bevy::pbr::{ - MaterialPipeline, MaterialPipelineKey, PreparedMaterial, RenderMaterialInstances, - SetMaterialBindGroup, -}; -use bevy::render::extract_component::ExtractComponentPlugin; use bevy::render::extract_instances::ExtractedInstances; use bevy::render::mesh::allocator::MeshAllocator; use bevy::render::mesh::RenderMeshBufferInfo; -use bevy::render::render_asset::{prepare_assets, RenderAsset}; -use bevy::render::render_phase::{BinnedRenderPhaseType, ViewBinnedRenderPhases}; +use bevy::render::render_asset::RenderAsset; use bevy::render::storage::{GpuShaderStorageBuffer, ShaderStorageBuffer}; -use bevy::render::view; -use bevy::render::view::VisibilitySystems; use bevy::{ core_pipeline::core_3d::Opaque3d, ecs::system::{lifetimeless::*, SystemParamItem}, pbr::{ - MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, + RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, }, prelude::*, render::{ extract_component::ExtractComponent, - mesh::{MeshVertexBufferLayoutRef, RenderMesh}, + mesh::RenderMesh, render_asset::RenderAssets, render_phase::{ - AddRenderCommand, DrawFunctions, PhaseItem, PhaseItemExtraIndex, RenderCommand, + AddRenderCommand, PhaseItem, RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass, }, - render_resource::*, - renderer::RenderDevice, - view::ExtractedView, - Render, RenderApp, RenderSet, + render_resource::* + + + , RenderApp, }, }; use rayon::prelude::*; use std::hash::Hash; use std::marker::PhantomData; -use std::ops::Range; -pub struct Indirect<'a, M> +pub struct Indirect<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - draw: &'a Draw, + draw: &'a Draw, primitive_index: Option, indirect_buffer: Option>, } -impl<'a, M> Drop for Indirect<'a, M> +impl<'a, SM> Drop for Indirect<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { fn drop(&mut self) { if let Some((index, ssbo)) = self.primitive_index.take().zip(self.indirect_buffer.take()) { @@ -64,9 +54,9 @@ where } } -pub fn new(draw: &Draw) -> Indirect +pub fn new(draw: &Draw) -> Indirect where - M: Material + Default, + SM: ShaderModel + Default, { Indirect { draw, @@ -75,11 +65,11 @@ where } } -impl<'a, M> Indirect<'a, M> +impl<'a, SM> Indirect<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - pub fn primitive(mut self, drawing: Drawing) -> Indirect<'a, M> + pub fn primitive(mut self, drawing: Drawing) -> Indirect<'a, SM> where T: Into, { @@ -93,7 +83,7 @@ where self } - pub fn buffer(mut self, ssbo: Handle) -> Indirect<'a, M> { + pub fn buffer(mut self, ssbo: Handle) -> Indirect<'a, SM> { self.indirect_buffer = Some(ssbo); self } @@ -114,11 +104,11 @@ where #[derive(Component, ExtractComponent, Clone)] pub struct IndirectMesh; -pub struct IndirectMaterialPlugin(PhantomData); +pub struct IndirectMaterialPlugin(PhantomData); -impl Default for IndirectMaterialPlugin +impl Default for IndirectMaterialPlugin where - M: Default, + SM: Default, { fn default() -> Self { IndirectMaterialPlugin(PhantomData) @@ -131,178 +121,20 @@ where SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.add_plugins(( - ExtractComponentPlugin::::default(), - ExtractComponentPlugin::>::default(), - )) - .add_systems( - PostUpdate, - view::check_visibility::>.in_set(VisibilitySystems::CheckVisibility), - ); - - app.sub_app_mut(RenderApp) - .add_render_command::>() - .init_resource::>>() - .add_systems( - Render, - (queue_indirect:: - .after(prepare_assets::>) - .in_set(RenderSet::QueueMeshes),), - ); - } - - fn finish(&self, app: &mut App) { app.sub_app_mut(RenderApp) - .init_resource::>(); - } -} - -#[allow(clippy::too_many_arguments)] -fn queue_indirect( - draw_functions: Res>, - custom_pipeline: Res>, - mut pipelines: ResMut>>, - pipeline_cache: Res, - meshes: Res>, - ( - render_mesh_instances, - indirect_meshes, - mut phases, - mut views, - shader_models, - extracted_instances, - ): ( - Res, - Query>, - ResMut>, - Query<(Entity, &ExtractedView, &Msaa)>, - Res>>, - Res>>, - ), -) where - SM: ShaderModel, - SM::Data: PartialEq + Eq + Hash + Clone, -{ - let drawn_function = draw_functions.read().id::>(); - - for (view_entity, view, msaa) in &mut views { - let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); - let Some(phase) = phases.get_mut(&view_entity) else { - continue; - }; - - let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); - for (entity) in &indirect_meshes { - let Some(shader_model) = extracted_instances.get(&entity) else { - continue; - }; - let shader_model = shader_models.get(*shader_model).unwrap(); - let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(entity) else { - continue; - }; - let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id) else { - continue; - }; - let mesh_key = - view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); - let key = MaterialPipelineKey { - mesh_key, - bind_group_data: shader_model.key.clone(), - }; - let pipeline = pipelines - .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout) - .unwrap(); - phase.add( - Opaque3dBinKey { - draw_function: drawn_function, - pipeline, - asset_id: AssetId::::invalid().untyped(), - material_bind_group_id: None, - lightmap_image: None, - }, - entity, - BinnedRenderPhaseType::NonMesh, - ); - } - } -} - -#[derive(Resource)] -struct IndirectPipeline { - mesh_pipeline: MeshPipeline, - shader_model_layout: BindGroupLayout, - vertex_shader: Option>, - fragment_shader: Option>, - marker: PhantomData, -} - -impl FromWorld for IndirectPipeline { - fn from_world(world: &mut World) -> Self { - let asset_server = world.resource::(); - let render_device = world.resource::(); - - IndirectPipeline { - mesh_pipeline: world.resource::().clone(), - shader_model_layout: SM::bind_group_layout(render_device), - vertex_shader: match ::vertex_shader() { - ShaderRef::Default => None, - ShaderRef::Handle(handle) => Some(handle), - ShaderRef::Path(path) => Some(asset_server.load(path)), - }, - fragment_shader: match ::fragment_shader() { - ShaderRef::Default => None, - ShaderRef::Handle(handle) => Some(handle), - ShaderRef::Path(path) => Some(asset_server.load(path)), - }, - marker: PhantomData, - } - } -} - -impl SpecializedMeshPipeline for IndirectPipeline -where - SM::Data: PartialEq + Eq + Hash + Clone, -{ - type Key = MaterialPipelineKey; - - fn specialize( - &self, - key: Self::Key, - layout: &MeshVertexBufferLayoutRef, - ) -> Result { - let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?; - if let Some(vertex_shader) = &self.vertex_shader { - descriptor.vertex.shader = vertex_shader.clone(); - } - - if let Some(fragment_shader) = &self.fragment_shader { - descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); - } - - descriptor - .layout - .insert(2, self.shader_model_layout.clone()); - - let pipeline = MaterialPipeline { - mesh_pipeline: self.mesh_pipeline.clone(), - material_layout: self.shader_model_layout.clone(), - vertex_shader: self.vertex_shader.clone(), - fragment_shader: self.fragment_shader.clone(), - marker: Default::default(), - }; - SM::specialize(&pipeline, &mut descriptor, layout, key)?; - Ok(descriptor) + .add_render_command::>(); } } type DrawIndirectMaterial = ( SetItemPipeline, SetMeshViewBindGroup<0>, + SetMeshBindGroup<1>, SetShaderModelBindGroup, DrawMeshIndirect, ); -struct SetShaderModelBindGroup(PhantomData); +struct SetShaderModelBindGroup(PhantomData); impl RenderCommand

for SetShaderModelBindGroup { diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index 3065e0bed..b331af727 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -39,18 +39,18 @@ use std::hash::Hash; use std::marker::PhantomData; use std::ops::Range; -pub struct Instanced<'a, M> +pub struct Instanced<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - draw: &'a Draw, + draw: &'a Draw, primitive_index: Option, range: Option>, } -impl<'a, M> Drop for Instanced<'a, M> +impl<'a, SM> Drop for Instanced<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { fn drop(&mut self) { if let Some((index, data)) = self.primitive_index.take().zip(self.range.take()) { @@ -59,9 +59,9 @@ where } } -pub fn new(draw: &Draw) -> Instanced +pub fn new(draw: &Draw) -> Instanced where - M: Material + Default, + SM: ShaderModel + Default, { Instanced { draw, @@ -70,11 +70,11 @@ where } } -impl<'a, M> Instanced<'a, M> +impl<'a, SM> Instanced<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - pub fn primitive(mut self, drawing: Drawing) -> Instanced<'a, M> + pub fn primitive(mut self, drawing: Drawing) -> Instanced<'a, SM> where T: Into, { @@ -88,7 +88,7 @@ where self } - pub fn range(mut self, range: Range) -> Instanced<'a, M> { + pub fn range(mut self, range: Range) -> Instanced<'a, SM> { self.range = Some(range); self } @@ -108,11 +108,11 @@ pub struct InstancedMesh; #[derive(Component, ExtractComponent, Clone)] pub struct InstanceRange(pub Range); -pub struct InstancedMaterialPlugin(PhantomData); +pub struct InstancedMaterialPlugin(PhantomData); -impl Default for InstancedMaterialPlugin +impl Default for InstancedMaterialPlugin where - M: Default, + SM: Default, { fn default() -> Self { InstancedMaterialPlugin(PhantomData) @@ -125,168 +125,8 @@ where SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.add_plugins(( - ExtractComponentPlugin::::default(), - ExtractComponentPlugin::::default(), - )) - .add_systems( - PostUpdate, - view::check_visibility::> - .in_set(VisibilitySystems::CheckVisibility), - ); - app.sub_app_mut(RenderApp) - .add_render_command::>() - .init_resource::>>() - .add_systems( - Render, - (queue_instanced:: - .after(prepare_assets::>) - .in_set(RenderSet::QueueMeshes),), - ); - } - - fn finish(&self, app: &mut App) { - app.sub_app_mut(RenderApp) - .init_resource::>(); - } -} - -#[allow(clippy::too_many_arguments)] -fn queue_instanced( - draw_functions: Res>, - custom_pipeline: Res>, - mut pipelines: ResMut>>, - pipeline_cache: Res, - meshes: Res>, - ( - render_mesh_instances, - instanced_meshes, - mut phases, - mut views, - shader_models, - extracted_instances, - ): ( - Res, - Query>, - ResMut>, - Query<(Entity, &ExtractedView, &Msaa)>, - Res>>, - Res>>, - ), -) where - SM: ShaderModel, - SM::Data: PartialEq + Eq + Hash + Clone, -{ - let drawn_function = draw_functions.read().id::>(); - - for (view_entity, view, msaa) in &mut views { - let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); - let Some(phase) = phases.get_mut(&view_entity) else { - continue; - }; - - let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); - for (entity) in &instanced_meshes { - let Some(shader_model) = extracted_instances.get(&entity) else { - continue; - }; - let shader_model = shader_models.get(*shader_model).unwrap(); - let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(entity) else { - continue; - }; - let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id) else { - continue; - }; - let mesh_key = - view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); - let key = MaterialPipelineKey { - mesh_key, - bind_group_data: shader_model.key.clone(), - }; - let pipeline = pipelines - .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout) - .unwrap(); - phase.add( - Opaque3dBinKey { - draw_function: drawn_function, - pipeline, - asset_id: AssetId::::invalid().untyped(), - material_bind_group_id: None, - lightmap_image: None, - }, - entity, - BinnedRenderPhaseType::NonMesh, - ); - } - } -} - -#[derive(Resource)] -struct InstancedPipeline { - mesh_pipeline: MeshPipeline, - shader_model_layout: BindGroupLayout, - vertex_shader: Option>, - fragment_shader: Option>, - marker: PhantomData, -} - -impl FromWorld for InstancedPipeline { - fn from_world(world: &mut World) -> Self { - let asset_server = world.resource::(); - let render_device = world.resource::(); - - InstancedPipeline { - mesh_pipeline: world.resource::().clone(), - shader_model_layout: SM::bind_group_layout(render_device), - vertex_shader: match ::vertex_shader() { - ShaderRef::Default => None, - ShaderRef::Handle(handle) => Some(handle), - ShaderRef::Path(path) => Some(asset_server.load(path)), - }, - fragment_shader: match ::fragment_shader() { - ShaderRef::Default => None, - ShaderRef::Handle(handle) => Some(handle), - ShaderRef::Path(path) => Some(asset_server.load(path)), - }, - marker: PhantomData, - } - } -} - -impl SpecializedMeshPipeline for InstancedPipeline -where - SM::Data: PartialEq + Eq + Hash + Clone, -{ - type Key = MaterialPipelineKey; - - fn specialize( - &self, - key: Self::Key, - layout: &MeshVertexBufferLayoutRef, - ) -> Result { - let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?; - if let Some(vertex_shader) = &self.vertex_shader { - descriptor.vertex.shader = vertex_shader.clone(); - } - - if let Some(fragment_shader) = &self.fragment_shader { - descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); - } - - descriptor - .layout - .insert(2, self.shader_model_layout.clone()); - - let pipeline = MaterialPipeline { - mesh_pipeline: self.mesh_pipeline.clone(), - material_layout: self.shader_model_layout.clone(), - vertex_shader: self.vertex_shader.clone(), - fragment_shader: self.fragment_shader.clone(), - marker: Default::default(), - }; - SM::specialize(&pipeline, &mut descriptor, layout, key)?; - Ok(descriptor) + .add_render_command::>(); } } @@ -297,7 +137,7 @@ type DrawInstancedMaterial = ( DrawMeshInstanced, ); -struct SetShaderModelBindGroup(PhantomData); +struct SetShaderModelBindGroup(PhantomData); impl RenderCommand

for SetShaderModelBindGroup { diff --git a/bevy_nannou_draw/src/draw/mod.rs b/bevy_nannou_draw/src/draw/mod.rs index 54ab47a45..3f46047ff 100644 --- a/bevy_nannou_draw/src/draw/mod.rs +++ b/bevy_nannou_draw/src/draw/mod.rs @@ -14,7 +14,7 @@ pub use self::theme::Theme; use crate::draw::indirect::Indirect; use crate::draw::instanced::Instanced; use crate::draw::mesh::MeshExt; -use crate::render::DefaultNannouMaterial; +use crate::render::{DefaultNannouShaderModel, ShaderModel}; use bevy::asset::UntypedAssetId; use bevy::prelude::*; use bevy::render::render_resource as wgpu; @@ -49,9 +49,9 @@ pub mod theme; /// See the [draw](https://github.com/nannou-org/nannou/blob/master/examples) examples for a /// variety of demonstrations of how the [Draw] type can be used! #[derive(Clone)] -pub struct Draw +pub struct Draw where - M: Material + Default, + SM: ShaderModel + Default, { /// The state of the [Draw]. /// @@ -70,24 +70,24 @@ where /// The window to which this [Draw] instance is associated. pub(crate) window: Entity, /// The type of material used by this [Draw] instance. - _material: PhantomData, + _material: PhantomData, } /// A reference to a [Draw] instance that is either borrowed or owned. #[derive(Clone)] -pub enum DrawRef<'a, M> +pub enum DrawRef<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - Borrowed(&'a Draw), - Owned(Draw), + Borrowed(&'a Draw), + Owned(Draw), } -impl<'a, M> Deref for DrawRef<'a, M> +impl<'a, SM> Deref for DrawRef<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { - type Target = Draw; + type Target = Draw; fn deref(&self) -> &Self::Target { match self { @@ -124,8 +124,8 @@ pub enum DrawCommand { Indirect(Primitive, Handle), /// A change in the rendering context occurred. Context(DrawContext), - /// A change in the material occurred. - Material(UntypedAssetId), + /// A change in the shader model occurred. + ShaderModel(UntypedAssetId), /// A change in the background color occurred. BackgroundColor(Color), } @@ -149,7 +149,7 @@ pub struct State { /// Keys are indices into the `draw_commands` Vec. drawing: HashMap, /// A map of all type erased materials used by the draw. - pub(crate) materials: HashMap>, + pub(crate) shader_models: HashMap>, /// A list of indices of primitives that are being drawn via an alternate method and /// should not be drawn ignored_drawings: HashSet, @@ -192,7 +192,7 @@ impl State { self.last_draw_context = None; self.background_color = None; self.drawing.clear(); - self.materials.clear(); + self.shader_models.clear(); self.draw_commands.clear(); self.intermediary_state.write().unwrap().reset(); } @@ -226,19 +226,19 @@ impl State { } } -impl Draw +impl Draw where - M: Material + Default, + SM: ShaderModel + Default, { pub fn new(window: Entity) -> Self { let mut state = State::default(); let context = DrawContext::default(); - let material = M::default(); + let material = SM::default(); let material_id = UntypedAssetId::Uuid { - type_id: TypeId::of::(), + type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; - state.materials.insert(material_id, Box::new(material)); + state.shader_models.insert(material_id, Box::new(material)); Draw { state: Arc::new(RwLock::new(state)), @@ -257,12 +257,12 @@ where fn insert_default_material(&mut self) { let mut state = self.state.write().unwrap(); - let material = M::default(); + let material = SM::default(); let material_id = UntypedAssetId::Uuid { - type_id: TypeId::of::(), + type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; - state.materials.insert(material_id, Box::new(material)); + state.shader_models.insert(material_id, Box::new(material)); self.material = material_id; } @@ -456,7 +456,7 @@ where } /// Produce a new [Draw] instance with the given context. - fn context(&self, context: DrawContext) -> Draw { + fn context(&self, context: DrawContext) -> Draw { let state = self.state.clone(); let material = self.material.clone(); let window = self.window; @@ -469,37 +469,37 @@ where } } - fn clone_material(&self) -> M { + fn clone_shader_model(&self) -> SM { let mut state = self.state.write().unwrap(); - let material = state.materials.get_mut(&self.material).unwrap(); + let material = state.shader_models.get_mut(&self.material).unwrap(); material - .downcast_ref::() + .downcast_ref::() .expect("Expected material to be of the correct type") .clone() } /// Produce a new [Draw] instance with a new material type. - pub fn material(&self, material: M2) -> Draw { + pub fn shader_model(&self, model: SM2) -> Draw { let context = self.context.clone(); let DrawContext { transform, .. } = context; let context = DrawContext { transform }; let state = self.state.clone(); let window = self.window; - let material_id = UntypedAssetId::Uuid { - type_id: TypeId::of::(), + let model_id = UntypedAssetId::Uuid { + type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; state .write() .unwrap() - .materials - .insert(material_id, Box::new(material)); + .shader_models + .insert(model_id, Box::new(model)); Draw { state, context, - material: material_id, + material: model_id, window, _material: PhantomData, } @@ -508,21 +508,21 @@ where // Primitives. /// Specify a color with which the background should be cleared. - pub fn background<'a>(&'a self) -> Background<'a, M> { + pub fn background<'a>(&'a self) -> Background<'a, SM> { background::new(self) } /// Draw an instanced drawing - pub fn instanced<'a>(&'a self) -> Instanced<'a, M> { + pub fn instanced<'a>(&'a self) -> Instanced<'a, SM> { instanced::new(self) } - pub fn indirect<'a>(&'a self) -> Indirect<'a, M> { + pub fn indirect<'a>(&'a self) -> Indirect<'a, SM> { indirect::new(self) } /// Add the given type to be drawn. - pub fn a(&self, primitive: T) -> Drawing + pub fn a(&self, primitive: T) -> Drawing where T: Into, Primitive: Into>, @@ -541,7 +541,7 @@ where if state.last_material.as_ref() != Some(id) { state .draw_commands - .push(Some(DrawCommand::Material(id.clone()))); + .push(Some(DrawCommand::ShaderModel(id.clone()))); state.last_material = Some(id.clone()); } @@ -560,59 +560,59 @@ where } /// Begin drawing a **Path**. - pub fn path(&self) -> Drawing { + pub fn path(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing an **Ellipse**. - pub fn ellipse(&self) -> Drawing { + pub fn ellipse(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Line**. - pub fn line(&self) -> Drawing { + pub fn line(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing an **Arrow**. - pub fn arrow(&self) -> Drawing { + pub fn arrow(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Quad**. - pub fn quad(&self) -> Drawing { + pub fn quad(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Rect**. - pub fn rect(&self) -> Drawing { + pub fn rect(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Triangle**. - pub fn tri(&self) -> Drawing { + pub fn tri(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Polygon**. - pub fn polygon(&self) -> Drawing { + pub fn polygon(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Mesh**. - pub fn mesh(&self) -> Drawing { + pub fn mesh(&self) -> Drawing { self.a(Default::default()) } /// Begin drawing a **Polyline**. /// /// Note that this is simply short-hand for `draw.path().stroke()` - pub fn polyline(&self) -> Drawing { + pub fn polyline(&self) -> Drawing { self.path().stroke() } /// Begin drawing a **Text**. - pub fn text(&self, s: &str) -> Drawing { + pub fn text(&self, s: &str) -> Drawing { let text = { let state = self.state.read().expect("lock poisoned"); let mut intermediary_state = state.intermediary_state.write().expect("lock poisoned"); @@ -641,27 +641,27 @@ where } } -impl Draw { +impl Draw { /// Produce a new [Draw] instance that will draw with the given alpha blend descriptor. pub fn alpha_blend(&self, blend_descriptor: wgpu::BlendComponent) -> Self { // TODO: check if blend is already set and only update if necessary - let mut mat = self.clone_material().clone(); - mat.extension.blend = Some(BlendState { + let mut model = self.clone_shader_model().clone(); + model.blend = Some(BlendState { color: BlendComponent::REPLACE, alpha: blend_descriptor, }); - self.material(mat) + self.shader_model(model) } /// Produce a new [Draw] instance that will draw with the given color blend descriptor. pub fn color_blend(&self, blend_descriptor: wgpu::BlendComponent) -> Self { // TODO: check if blend is already set and only update if necessary - let mut mat = self.clone_material().clone(); - mat.extension.blend = Some(BlendState { + let mut model = self.clone_shader_model().clone(); + model.blend = Some(BlendState { color: blend_descriptor, alpha: BlendComponent::REPLACE, }); - self.material(mat) + self.shader_model(model) } /// Short-hand for `color_blend`, the common use-case. @@ -671,9 +671,9 @@ impl Draw { /// Produce a new [Draw] instance that will use the given polygon mode. pub fn polygon_mode(&self, polygon_mode: wgpu::PolygonMode) -> Self { - let mut mat = self.clone_material().clone(); - mat.extension.polygon_mode = polygon_mode; - self.material(mat) + let mut model = self.clone_shader_model().clone(); + model.polygon_mode = polygon_mode; + self.shader_model(model) } } @@ -710,7 +710,7 @@ impl Default for State { theme, background_color, ignored_drawings: Default::default(), - materials: Default::default(), + shader_models: Default::default(), } } } diff --git a/bevy_nannou_draw/src/draw/primitive/arrow.rs b/bevy_nannou_draw/src/draw/primitive/arrow.rs index eb6bbf4cc..930a78753 100644 --- a/bevy_nannou_draw/src/draw/primitive/arrow.rs +++ b/bevy_nannou_draw/src/draw/primitive/arrow.rs @@ -7,6 +7,7 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{SetColor, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// A path containing only two points - a start and end. /// @@ -19,7 +20,7 @@ pub struct Arrow { } /// The drawing context for a line. -pub type DrawingArrow<'a, M> = Drawing<'a, Arrow, M>; +pub type DrawingArrow<'a, SM> = Drawing<'a, Arrow, SM>; impl Arrow { /// Short-hand for the `stroke_weight` method. @@ -84,9 +85,9 @@ impl Arrow { } } -impl<'a, M> DrawingArrow<'a, M> +impl<'a, SM> DrawingArrow<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { diff --git a/bevy_nannou_draw/src/draw/primitive/ellipse.rs b/bevy_nannou_draw/src/draw/primitive/ellipse.rs index 287989c78..cdb169e1b 100644 --- a/bevy_nannou_draw/src/draw/primitive/ellipse.rs +++ b/bevy_nannou_draw/src/draw/primitive/ellipse.rs @@ -11,6 +11,7 @@ use crate::draw::properties::{ spatial, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::Drawing; +use crate::render::ShaderModel; /// Properties related to drawing an **Ellipse**. #[derive(Clone, Debug, Default)] @@ -21,7 +22,7 @@ pub struct Ellipse { } /// The drawing context for an ellipse. -pub type DrawingEllipse<'a, M> = Drawing<'a, Ellipse, M>; +pub type DrawingEllipse<'a, SM> = Drawing<'a, Ellipse, SM>; // Ellipse-specific methods. @@ -188,9 +189,9 @@ impl Into> for Primitive { // Drawing methods. -impl<'a, M> DrawingEllipse<'a, M> +impl<'a, SM> DrawingEllipse<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self diff --git a/bevy_nannou_draw/src/draw/primitive/line.rs b/bevy_nannou_draw/src/draw/primitive/line.rs index 41248e915..2b2b96157 100644 --- a/bevy_nannou_draw/src/draw/primitive/line.rs +++ b/bevy_nannou_draw/src/draw/primitive/line.rs @@ -6,6 +6,7 @@ use crate::draw::primitive::{PathStroke, Primitive}; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{SetColor, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// A path containing only two points - a start and end. /// @@ -19,7 +20,7 @@ pub struct Line { } /// The drawing context for a line. -pub type DrawingLine<'a, M> = Drawing<'a, Line, M>; +pub type DrawingLine<'a, SM> = Drawing<'a, Line, SM>; impl Line { /// Short-hand for the `stroke_weight` method. @@ -60,9 +61,9 @@ impl Line { } } -impl<'a, M> DrawingLine<'a, M> +impl<'a, SM> DrawingLine<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { diff --git a/bevy_nannou_draw/src/draw/primitive/mesh.rs b/bevy_nannou_draw/src/draw/primitive/mesh.rs index f86096a63..0e10a6b66 100644 --- a/bevy_nannou_draw/src/draw/primitive/mesh.rs +++ b/bevy_nannou_draw/src/draw/primitive/mesh.rs @@ -9,6 +9,7 @@ use crate::draw::primitive::{Primitive, Vertex}; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{SetColor, SetOrientation, SetPosition}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// The mesh type prior to being initialised with vertices or indices. #[derive(Clone, Debug, Default)] @@ -27,7 +28,7 @@ pub struct PrimitiveMesh { #[derive(Clone, Debug, Default)] struct FillColor(Option); -pub type DrawingMesh<'a, M> = Drawing<'a, PrimitiveMesh, M>; +pub type DrawingMesh<'a, SM> = Drawing<'a, PrimitiveMesh, SM>; impl Vertexless { /// Describe the mesh with a sequence of textured points. @@ -319,9 +320,9 @@ impl PrimitiveMesh { } } -impl<'a, M> Drawing<'a, Vertexless, M> +impl<'a, SM> Drawing<'a, Vertexless, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Describe the mesh with a sequence of points. /// @@ -330,7 +331,7 @@ where /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn points(self, points: I) -> DrawingMesh<'a, M> + pub fn points(self, points: I) -> DrawingMesh<'a, SM> where I: IntoIterator, I::Item: Into, @@ -343,7 +344,7 @@ where /// Each of the points must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoColor`. - pub fn points_colored(self, points: I) -> DrawingMesh<'a, M> + pub fn points_colored(self, points: I) -> DrawingMesh<'a, SM> where I: IntoIterator, P: Into, @@ -362,7 +363,7 @@ where self, texture_handle: Handle, points: I, - ) -> DrawingMesh<'a, M> + ) -> DrawingMesh<'a, SM> where I: IntoIterator, P: Into, @@ -379,7 +380,7 @@ where /// This method assumes that the entire mesh should be coloured with a single colour. If a /// colour is not specified via one of the builder methods, a default colour will be retrieved /// from the inner `Theme`. - pub fn tris(self, tris: I) -> DrawingMesh<'a, M> + pub fn tris(self, tris: I) -> DrawingMesh<'a, SM> where I: IntoIterator>, V: Into, @@ -392,7 +393,7 @@ where /// Each of the vertices must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements `Into` /// and `color` may be of any type that implements `IntoColor`. - pub fn tris_colored(self, tris: I) -> DrawingMesh<'a, M> + pub fn tris_colored(self, tris: I) -> DrawingMesh<'a, SM> where I: IntoIterator>, P: Into, @@ -411,7 +412,7 @@ where self, texture_handle: Handle, tris: I, - ) -> DrawingMesh<'a, M> + ) -> DrawingMesh<'a, SM> where I: IntoIterator>, P: Into, @@ -425,7 +426,7 @@ where /// Each trio of `indices` describes a single triangle made up of `points`. /// /// Each point may be any type that may be converted directly into the `Vec3` type. - pub fn indexed(self, points: V, indices: I) -> DrawingMesh<'a, M> + pub fn indexed(self, points: V, indices: I) -> DrawingMesh<'a, SM> where V: IntoIterator, V::Item: Into, @@ -441,7 +442,7 @@ where /// Each of the `points` must be represented as a tuple containing the point and the color in /// that order, e.g. `(point, color)`. `point` may be of any type that implements /// `Into` and `color` may be of any type that implements `IntoColor`. - pub fn indexed_colored(self, points: V, indices: I) -> DrawingMesh<'a, M> + pub fn indexed_colored(self, points: V, indices: I) -> DrawingMesh<'a, SM> where V: IntoIterator, I: IntoIterator, @@ -464,7 +465,7 @@ where texture_handle: Handle, points: V, indices: I, - ) -> DrawingMesh<'a, M> + ) -> DrawingMesh<'a, SM> where V: IntoIterator, I: IntoIterator, diff --git a/bevy_nannou_draw/src/draw/primitive/path.rs b/bevy_nannou_draw/src/draw/primitive/path.rs index cb4e07285..1b1cfa9b6 100644 --- a/bevy_nannou_draw/src/draw/primitive/path.rs +++ b/bevy_nannou_draw/src/draw/primitive/path.rs @@ -6,6 +6,7 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{SetColor, SetFill, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing, DrawingContext}; +use crate::render::ShaderModel; /// A set of path tessellation options (FillOptions or StrokeOptions). pub trait TessellationOptions { @@ -73,19 +74,19 @@ pub struct Path { } /// The initial drawing context for a path. -pub type DrawingPathInit<'a, M> = Drawing<'a, PathInit, M>; +pub type DrawingPathInit<'a, SM> = Drawing<'a, PathInit, SM>; /// The drawing context for a path in the tessellation options state. -pub type DrawingPathOptions<'a, T, M> = Drawing<'a, PathOptions, M>; +pub type DrawingPathOptions<'a, T, SM> = Drawing<'a, PathOptions, SM>; /// The drawing context for a stroked path, prior to path event submission. -pub type DrawingPathStroke<'a, M> = Drawing<'a, PathStroke, M>; +pub type DrawingPathStroke<'a, SM> = Drawing<'a, PathStroke, SM>; /// The drawing context for a filled path, prior to path event submission. -pub type DrawingPathFill<'a, M> = Drawing<'a, PathFill, M>; +pub type DrawingPathFill<'a, SM> = Drawing<'a, PathFill, SM>; /// The drawing context for a polyline whose vertices have been specified. -pub type DrawingPath<'a, M> = Drawing<'a, Path, M>; +pub type DrawingPath<'a, SM> = Drawing<'a, Path, SM>; /// Dynamically distinguish between fill and stroke tessellation options. #[derive(Clone, Debug)] @@ -571,28 +572,28 @@ impl Path { } } -impl<'a, M> DrawingPathInit<'a, M> +impl<'a, SM> DrawingPathInit<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Specify that we want to use fill tessellation for the path. /// /// The returned building context allows for specifying the fill tessellation options. - pub fn fill(self) -> DrawingPathFill<'a, M> { + pub fn fill(self) -> DrawingPathFill<'a, SM> { self.map_ty(|ty| ty.fill()) } /// Specify that we want to use stroke tessellation for the path. /// /// The returned building context allows for specifying the stroke tessellation options. - pub fn stroke(self) -> DrawingPathStroke<'a, M> { + pub fn stroke(self) -> DrawingPathStroke<'a, SM> { self.map_ty(|ty| ty.stroke()) } } -impl<'a, M> DrawingPathFill<'a, M> +impl<'a, SM> DrawingPathFill<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Maximum allowed distance to the path when building an approximation. pub fn tolerance(self, tolerance: f32) -> Self { @@ -607,9 +608,9 @@ where } } -impl<'a, M> DrawingPathStroke<'a, M> +impl<'a, SM> DrawingPathStroke<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Short-hand for the `stroke_weight` method. pub fn weight(self, weight: f32) -> Self { @@ -622,15 +623,15 @@ where } } -impl<'a, T, M> DrawingPathOptions<'a, T, M> +impl<'a, T, SM> DrawingPathOptions<'a, T, SM> where T: TessellationOptions, - M: Material + Default, + SM: ShaderModel + Default, PathOptions: Into + Clone, Primitive: Into>>, { /// Submit the path events to be tessellated. - pub fn events(self, events: I) -> DrawingPath<'a, M> + pub fn events(self, events: I) -> DrawingPath<'a, SM> where I: IntoIterator, { @@ -638,7 +639,7 @@ where } /// Submit the path events as a polyline of points. - pub fn points(self, points: I) -> DrawingPath<'a, M> + pub fn points(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, I::Item: Into, @@ -649,7 +650,7 @@ where /// Submit the path events as a polyline of points. /// /// An event will be generated that closes the start and end points. - pub fn points_closed(self, points: I) -> DrawingPath<'a, M> + pub fn points_closed(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, I::Item: Into, @@ -657,7 +658,7 @@ where self.map_ty_with_context(|ty, ctxt| ty.points_closed(ctxt, points)) } - pub fn points_colored(self, points: I) -> DrawingPath<'a, M> + pub fn points_colored(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, P: Into, @@ -668,7 +669,7 @@ where }) } - pub fn points_colored_closed(self, points: I) -> DrawingPath<'a, M> + pub fn points_colored_closed(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, P: Into, @@ -680,7 +681,7 @@ where } /// Submit path events as a polyline of vertex points. - pub fn points_vertex(self, points: I) -> DrawingPath<'a, M> + pub fn points_vertex(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, P: Into, @@ -693,7 +694,7 @@ where /// Submit path events as a polyline of vertex points. /// /// The path with automatically close from the end point to the start point. - pub fn points_vertex_closed(self, points: I) -> DrawingPath<'a, M> + pub fn points_vertex_closed(self, points: I) -> DrawingPath<'a, SM> where I: IntoIterator, P: Into, diff --git a/bevy_nannou_draw/src/draw/primitive/polygon.rs b/bevy_nannou_draw/src/draw/primitive/polygon.rs index 3d5a3cf02..8ab3b8752 100644 --- a/bevy_nannou_draw/src/draw/primitive/polygon.rs +++ b/bevy_nannou_draw/src/draw/primitive/polygon.rs @@ -8,6 +8,7 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{orientation, position}; use crate::draw::properties::{SetColor, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// A trait implemented for all polygon draw primitives. pub trait SetPolygon: Sized { @@ -64,10 +65,10 @@ pub struct Polygon { } /// Initialised drawing state for a polygon. -pub type DrawingPolygonInit<'a, M> = Drawing<'a, PolygonInit, M>; +pub type DrawingPolygonInit<'a, SM> = Drawing<'a, PolygonInit, SM>; /// Initialised drawing state for a polygon. -pub type DrawingPolygon<'a, M> = Drawing<'a, Polygon, M>; +pub type DrawingPolygon<'a, SM> = Drawing<'a, Polygon, SM>; impl PolygonInit { /// Stroke the outline with the given color. @@ -416,10 +417,10 @@ impl draw::render::RenderPrimitive for Polygon { } } -impl<'a, T, M> Drawing<'a, T, M> +impl<'a, T, SM> Drawing<'a, T, SM> where T: SetPolygon + Into + Clone, - M: Material + Default, + SM: ShaderModel + Default, Primitive: Into>, { /// Specify no fill color and in turn no fill tessellation for the polygon. @@ -444,9 +445,9 @@ where } } -impl<'a, M> DrawingPolygonInit<'a, M> +impl<'a, SM> DrawingPolygonInit<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self @@ -457,7 +458,7 @@ where } /// Describe the polygon with a sequence of path events. - pub fn events(self, events: I) -> DrawingPolygon<'a, M> + pub fn events(self, events: I) -> DrawingPolygon<'a, SM> where I: IntoIterator, { @@ -465,7 +466,7 @@ where } /// Describe the polygon with a sequence of points. - pub fn points(self, points: I) -> DrawingPolygon<'a, M> + pub fn points(self, points: I) -> DrawingPolygon<'a, SM> where I: IntoIterator, I::Item: Into, @@ -473,7 +474,7 @@ where self.map_ty_with_context(|ty, ctxt| ty.points(ctxt, points)) } - pub fn points_colored(self, points: I) -> DrawingPolygon<'a, M> + pub fn points_colored(self, points: I) -> DrawingPolygon<'a, SM> where I: IntoIterator, P: Into, @@ -485,7 +486,7 @@ where } /// Consumes an iterator of points and converts them to an iterator yielding path events. - pub fn points_vertex(self, points: I) -> DrawingPolygon<'a, M> + pub fn points_vertex(self, points: I) -> DrawingPolygon<'a, SM> where I: IntoIterator, P: Into, diff --git a/bevy_nannou_draw/src/draw/primitive/quad.rs b/bevy_nannou_draw/src/draw/primitive/quad.rs index 42593d59c..d2e6159f7 100644 --- a/bevy_nannou_draw/src/draw/primitive/quad.rs +++ b/bevy_nannou_draw/src/draw/primitive/quad.rs @@ -10,6 +10,7 @@ use crate::draw::properties::{ spatial, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke, }; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// Properties related to drawing a **Quad**. #[derive(Clone, Debug)] @@ -20,7 +21,7 @@ pub struct Quad { } /// The drawing context for a `Quad`. -pub type DrawingQuad<'a, M> = Drawing<'a, Quad, M>; +pub type DrawingQuad<'a, SM> = Drawing<'a, Quad, SM>; // Quad-specific methods. @@ -175,9 +176,9 @@ impl Into> for Primitive { // Drawing methods. -impl<'a, M> DrawingQuad<'a, M> +impl<'a, SM> DrawingQuad<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Use the given points as the vertices (corners) of the quad. pub fn points

(self, a: P, b: P, c: P, d: P) -> Self diff --git a/bevy_nannou_draw/src/draw/primitive/rect.rs b/bevy_nannou_draw/src/draw/primitive/rect.rs index 271b371b0..1aca06ad4 100644 --- a/bevy_nannou_draw/src/draw/primitive/rect.rs +++ b/bevy_nannou_draw/src/draw/primitive/rect.rs @@ -9,6 +9,7 @@ use crate::draw::properties::spatial::{dimension, orientation, position}; use crate::draw::properties::tex_coords::SetTexCoords; use crate::draw::properties::{SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// Properties related to drawing a **Rect**. #[derive(Clone, Debug)] @@ -19,7 +20,7 @@ pub struct Rect { } /// The drawing context for a Rect. -pub type DrawingRect<'a, M> = Drawing<'a, Rect, M>; +pub type DrawingRect<'a, SM> = Drawing<'a, Rect, SM>; // Trait implementations. @@ -33,9 +34,9 @@ impl Rect { } } -impl<'a, M> DrawingRect<'a, M> +impl<'a, SM> DrawingRect<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self diff --git a/bevy_nannou_draw/src/draw/primitive/text.rs b/bevy_nannou_draw/src/draw/primitive/text.rs index b2de7080f..c68399a57 100644 --- a/bevy_nannou_draw/src/draw/primitive/text.rs +++ b/bevy_nannou_draw/src/draw/primitive/text.rs @@ -5,6 +5,7 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{self, dimension, orientation, position}; use crate::draw::properties::{SetColor, SetDimensions, SetOrientation, SetPosition}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; use crate::text::{self, Align, Font, FontSize, Justify, Layout, Scalar, Wrap}; /// Properties related to drawing the **Text** primitive. @@ -25,7 +26,7 @@ pub struct Style { } /// The drawing context for the **Text** primitive. -pub type DrawingText<'a, M> = Drawing<'a, Text, M>; +pub type DrawingText<'a, SM> = Drawing<'a, Text, SM>; impl Text { /// Begin drawing some text. @@ -156,9 +157,9 @@ impl Text { } } -impl<'a, M> DrawingText<'a, M> +impl<'a, SM> DrawingText<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// The font size to use for the text. pub fn font_size(self, size: text::FontSize) -> Self { diff --git a/bevy_nannou_draw/src/draw/primitive/tri.rs b/bevy_nannou_draw/src/draw/primitive/tri.rs index 6217044f3..959d9fdbd 100644 --- a/bevy_nannou_draw/src/draw/primitive/tri.rs +++ b/bevy_nannou_draw/src/draw/primitive/tri.rs @@ -8,6 +8,7 @@ use crate::draw::primitive::Primitive; use crate::draw::properties::spatial::{dimension, orientation, position}; use crate::draw::properties::{SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke}; use crate::draw::{self, Drawing}; +use crate::render::ShaderModel; /// Properties related to drawing a **Tri**. #[derive(Clone, Debug)] @@ -18,7 +19,7 @@ pub struct Tri { } /// The drawing context for a `Tri`. -pub type DrawingTri<'a, M> = Drawing<'a, Tri, M>; +pub type DrawingTri<'a, SM> = Drawing<'a, Tri, SM>; // Tri-specific methods. @@ -46,9 +47,9 @@ impl Tri { // Drawing methods. -impl<'a, M> DrawingTri<'a, M> +impl<'a, SM> DrawingTri<'a, SM> where - M: Material + Default, + SM: ShaderModel + Default, { /// Stroke the outline with the given color. pub fn stroke(self, color: C) -> Self diff --git a/bevy_nannou_draw/src/nannou.wgsl b/bevy_nannou_draw/src/nannou.wgsl new file mode 100644 index 000000000..49685de90 --- /dev/null +++ b/bevy_nannou_draw/src/nannou.wgsl @@ -0,0 +1,86 @@ +#import bevy_pbr::{ + mesh_functions, + forward_io::{Vertex , VertexOutput}, + mesh_view_bindings::view, + view_transformations::position_world_to_clip, +} + +const FLAGS_TEXTURE_BIT: u32 = 1u; + +struct ShaderModel { + color: vec4, + flags: u32, +}; + +@group(2) @binding(0) var model: ShaderModel; +@group(2) @binding(1) var texture: texture_2d; +@group(2) @binding(2) var texture_sampler: sampler; + +@vertex +fn vertex(vertex: Vertex) -> VertexOutput { + var out: VertexOutput; + + // Use vertex.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. + // See https://github.com/gfx-rs/naga/issues/2416 . + var world_from_local = mesh_functions::get_world_from_local(vertex.instance_index); + +#ifdef VERTEX_NORMALS + out.world_normal = mesh_functions::mesh_normal_local_to_world( + vertex.normal, + // Use vertex.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. + // See https://github.com/gfx-rs/naga/issues/2416 + vertex.instance_index + ); +#endif + +#ifdef VERTEX_POSITIONS + out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4(vertex.position, 1.0)); + out.position = position_world_to_clip(out.world_position.xyz); +#endif + +#ifdef VERTEX_UVS_A + out.uv = vertex.uv; +#endif +#ifdef VERTEX_UVS_B + out.uv_b = vertex.uv_b; +#endif + +#ifdef VERTEX_TANGENTS + out.world_tangent = mesh_functions::mesh_tangent_local_to_world( + world_from_local, + vertex.tangent, + // Use vertex.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. + // See https://github.com/gfx-rs/naga/issues/2416 + vertex.instance_index + ); +#endif + +#ifdef VERTEX_COLORS + out.color = vertex.color; +#endif + +#ifdef VERTEX_OUTPUT_INSTANCE_INDEX + // Use vertex.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. + // See https://github.com/gfx-rs/naga/issues/2416 + out.instance_index = vertex.instance_index; +#endif + + return out; +} + +@fragment +fn fragment( + mesh: VertexOutput, +) -> @location(0) vec4 { + var output_color: vec4 = model.color; + +#ifdef VERTEX_COLORS + output_color = output_color * mesh.color; +#endif + + if ((model.flags & FLAGS_TEXTURE_BIT) != 0u) { + output_color = output_color * textureSample(texture, texture_sampler, mesh.uv); + } + + return output_color; +} \ No newline at end of file diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index c1a37c3fc..a6f7e03aa 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -1,43 +1,45 @@ -use std::any::TypeId; -use std::hash::Hash; - -use bevy::asset::Asset; +use crate::draw::indirect::{IndirectMaterialPlugin, IndirectMesh}; +use crate::draw::instanced::{InstanceRange, InstancedMaterialPlugin, InstancedMesh}; +use crate::draw::mesh::MeshExt; +use crate::draw::render::{RenderContext, RenderPrimitive}; +use crate::draw::{DrawCommand, DrawContext}; +use crate::DrawHolder; use bevy::asset::UntypedAssetId; +use bevy::asset::{load_internal_asset, Asset}; +use bevy::core_pipeline::core_3d::{Opaque3d, Opaque3dBinKey}; use bevy::ecs::system::lifetimeless::SRes; use bevy::ecs::system::SystemParamItem; -use bevy::pbr::{ - DefaultOpaqueRendererMethod, ExtendedMaterial, MaterialExtension, MaterialExtensionKey, - MaterialExtensionPipeline, MaterialPipeline, MaterialProperties, MeshPipelineKey, - OpaqueRendererMethod, PreparedMaterial, StandardMaterial, -}; +use bevy::pbr::{DefaultOpaqueRendererMethod, DrawMesh, ExtendedMaterial, MaterialBindGroupId, MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, MaterialPipeline, MaterialProperties, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, StandardMaterial}; use bevy::prelude::TypePath; use bevy::prelude::*; use bevy::render::camera::RenderTarget; use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; -use bevy::render::extract_instances::ExtractInstancesPlugin; +use bevy::render::extract_instances::{ExtractInstancesPlugin, ExtractedInstances}; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; -use bevy::render::mesh::MeshVertexBufferLayoutRef; -use bevy::render::render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin}; -use bevy::render::render_resource::{ - AsBindGroup, AsBindGroupError, BindGroup, BlendState, OwnedBindingResource, PolygonMode, - RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, +use bevy::render::mesh::{MeshVertexBufferLayoutRef, RenderMesh}; +use bevy::render::render_asset::{ + prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets, }; +use bevy::render::render_phase::{ + AddRenderCommand, BinnedRenderPhaseType, DrawFunctionId, DrawFunctions, PhaseItem, + RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass, ViewBinnedRenderPhases, +}; +use bevy::render::render_resource::{AsBindGroup, AsBindGroupError, AsBindGroupShaderType, BindGroup, BindGroupId, BindGroupLayout, BlendState, OwnedBindingResource, PipelineCache, PolygonMode, RenderPipelineDescriptor, ShaderRef, ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines}; use bevy::render::renderer::RenderDevice; -use bevy::render::view::{NoFrustumCulling, RenderLayers}; +use bevy::render::texture::GpuImage; +use bevy::render::view::{ExtractedView, NoFrustumCulling, RenderLayers, VisibilitySystems}; use bevy::render::RenderSet::Render; -use bevy::render::{render_resource as wgpu, RenderApp}; +use bevy::render::{render_resource as wgpu, view, RenderApp, RenderSet}; use bevy::window::WindowRef; use lyon::lyon_tessellation::{FillTessellator, StrokeTessellator}; +use std::any::TypeId; +use std::hash::Hash; +use std::marker::PhantomData; -use crate::draw::indirect::{IndirectMaterialPlugin, IndirectMesh}; -use crate::draw::instanced::{InstanceRange, InstancedMaterialPlugin, InstancedMesh}; -use crate::draw::mesh::MeshExt; -use crate::draw::render::{RenderContext, RenderPrimitive}; -use crate::draw::{DrawCommand, DrawContext}; -use crate::DrawHolder; +pub const DEFAULT_NANNOU_SHADER_HANDLE: Handle = Handle::weak_from_u128(3086880141013591); pub trait ShaderModel: - Material + AsBindGroup + Clone + Default + Sized + Send + Sync + 'static + Asset + AsBindGroup + Clone + Default + Sized + Send + Sync + 'static { /// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader /// will be used. @@ -51,31 +53,49 @@ pub trait ShaderModel: fn fragment_shader() -> ShaderRef { ShaderRef::Default } + + /// Specializes the render pipeline descriptor for this shader model. + fn specialize( + pipeline: &ShaderModelPipeline, + descriptor: &mut RenderPipelineDescriptor, + layout: &MeshVertexBufferLayoutRef, + key: ShaderModelPipelineKey, + ) -> Result<(), SpecializedMeshPipelineError> { + Ok(()) + } + + fn draw_function(draw_functions: &DrawFunctions

) -> DrawFunctionId { + draw_functions.read().id::>() + } } pub struct NannouRenderPlugin; impl Plugin for NannouRenderPlugin { fn build(&self, app: &mut App) { + load_internal_asset!( + app, + DEFAULT_NANNOU_SHADER_HANDLE, + "nannou.wgsl", + Shader::from_wgsl + ); + app.add_systems(Startup, setup_default_texture) - .add_plugins((ExtractComponentPlugin::::default(),)) - .add_plugins(ExtractResourcePlugin::::default()) + .add_plugins(( + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + ExtractResourcePlugin::::default(), + NannouShaderModelPlugin::::default(), + )) .add_systems(Update, texture_event_handler) - .add_systems(PostUpdate, update_draw_mesh); - } -} - -#[derive(Default)] -pub struct NannouMaterialPlugin(std::marker::PhantomData); - -impl Plugin for NannouMaterialPlugin -where - M: Material + Default, - M::Data: PartialEq + Eq + Hash + Clone, -{ - fn build(&self, app: &mut App) { - app.add_plugins((MaterialPlugin::::default(),)) - .add_systems(PostUpdate, update_material::.after(update_draw_mesh)); + .add_systems( + PostUpdate, + ( + update_draw_mesh, + view::check_visibility::> + .in_set(VisibilitySystems::CheckVisibility), + ), + ); } } @@ -84,35 +104,59 @@ pub struct NannouShaderModelPlugin(std::marker::PhantomData impl Plugin for NannouShaderModelPlugin where - SM: ShaderModel, + SM: ShaderModel + Default, SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.add_plugins(( - RenderAssetPlugin::>::default(), - IndirectMaterialPlugin::::default(), - InstancedMaterialPlugin::::default(), - )) - .add_systems(PostUpdate, update_material::.after(update_draw_mesh)); + app.init_asset::() + .add_plugins(( + ExtractInstancesPlugin::>::extract_visible(), + RenderAssetPlugin::>::default(), + IndirectMaterialPlugin::::default(), + InstancedMaterialPlugin::::default(), + )) + .add_systems(PostUpdate, update_material::.after(update_draw_mesh)) + .add_systems(PostUpdate, update_material::.after(update_draw_mesh)); + + app.sub_app_mut(RenderApp) + .add_render_command::>() + .init_resource::>>() + .add_systems( + bevy::render::Render, + queue_shader_model:: + .after(prepare_assets::>) + .in_set(RenderSet::QueueMeshes), + ); + } + + fn finish(&self, app: &mut App) { + app.sub_app_mut(RenderApp) + .init_resource::>(); } } -pub struct PreparedShaderModel { +pub struct PreparedShaderModel { pub bindings: Vec<(u32, OwnedBindingResource)>, pub bind_group: BindGroup, - pub key: T::Data, + pub key: SM::Data, } -impl RenderAsset for PreparedShaderModel { - type SourceAsset = T; +impl PreparedShaderModel { + pub fn get_bind_group_id(&self) -> Option { + Some(self.bind_group.id()) + } +} + +impl RenderAsset for PreparedShaderModel { + type SourceAsset = SM; - type Param = (SRes, SRes>, T::Param); + type Param = (SRes, SRes>, SM::Param); fn prepare_asset( material: Self::SourceAsset, (render_device, pipeline, ref mut material_param): &mut SystemParamItem, ) -> Result> { - match material.as_bind_group(&pipeline.material_layout, render_device, material_param) { + match material.as_bind_group(&pipeline.shader_model_layout, render_device, material_param) { Ok(prepared) => Ok(PreparedShaderModel { bindings: prepared.bindings, bind_group: prepared.bind_group, @@ -126,29 +170,106 @@ impl RenderAsset for PreparedShaderModel { } } +/// Sets the bind group for a given [`ShaderModel`] at the configured `I` index. +pub struct SetShaderModelBindGroup(PhantomData); +impl RenderCommand

+ for SetShaderModelBindGroup +{ + type Param = ( + SRes>>, + SRes>>, + ); + type ViewQuery = (); + type ItemQuery = (); + + #[inline] + fn render<'w>( + item: &P, + _view: (), + _item_query: Option<()>, + (models, model_instances): SystemParamItem<'w, '_, Self::Param>, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + let models = models.into_inner(); + let model_instances = model_instances.into_inner(); + + let Some(material_asset_id) = model_instances.get(&item.entity()) else { + return RenderCommandResult::Skip; + }; + let Some(material) = models.get(*material_asset_id) else { + return RenderCommandResult::Skip; + }; + pass.set_bind_group(I, &material.bind_group, &[]); + RenderCommandResult::Success + } +} + +type DrawShaderModel = ( + SetItemPipeline, + SetMeshViewBindGroup<0>, + SetMeshBindGroup<1>, + SetShaderModelBindGroup, + DrawMesh, +); + // ---------------------------------------------------------------------------- // Components and Resources // ---------------------------------------------------------------------------- -pub type DefaultNannouMaterial = ExtendedMaterial; +pub type DefaultNannouShaderModel = NannouShaderModel; -pub type ExtendedNannouMaterial = ExtendedMaterial; +bitflags::bitflags! { + #[repr(transparent)] + pub struct NannouShaderModelFlags: u32 { + const TEXTURE = 1 << 0; + const NONE = 0; + const UNINITIALIZED = 0xFFFF; + } +} #[derive(Asset, AsBindGroup, TypePath, Debug, Clone, Default)] #[bind_group_data(NannouMaterialKey)] -pub struct NannouMaterial { +#[uniform(0, NannouShaderModelUniform)] +pub struct NannouShaderModel { + pub color: Color, + #[texture(1)] + #[sampler(2)] + pub texture: Option>, pub polygon_mode: PolygonMode, pub blend: Option, } +#[derive(Clone, Default, ShaderType)] +pub struct NannouShaderModelUniform { + pub color: Vec4, + pub flags: u32, +} + +impl AsBindGroupShaderType for NannouShaderModel { + fn as_bind_group_shader_type( + &self, + _images: &RenderAssets, + ) -> NannouShaderModelUniform { + let mut flags = NannouShaderModelFlags::NONE; + if self.texture.is_some() { + flags |= NannouShaderModelFlags::TEXTURE; + } + + NannouShaderModelUniform { + color: LinearRgba::from(self.color).to_vec4(), + flags: flags.bits(), + } + } +} + #[derive(Eq, PartialEq, Hash, Clone)] pub struct NannouMaterialKey { polygon_mode: PolygonMode, blend: Option, } -impl From<&NannouMaterial> for NannouMaterialKey { - fn from(material: &NannouMaterial) -> Self { +impl From<&NannouShaderModel> for NannouMaterialKey { + fn from(material: &NannouShaderModel) -> Self { Self { polygon_mode: material.polygon_mode, blend: material.blend, @@ -156,12 +277,188 @@ impl From<&NannouMaterial> for NannouMaterialKey { } } -impl MaterialExtension for NannouMaterial { +#[allow(clippy::too_many_arguments)] +fn queue_shader_model( + draw_functions: Res>, + custom_pipeline: Res>, + mut pipelines: ResMut>>, + pipeline_cache: Res, + meshes: Res>, + ( + render_mesh_instances, + nannou_meshes, + mut phases, + mut views, + shader_models, + extracted_instances, + ): ( + Res, + Query>, + ResMut>, + Query<(Entity, &ExtractedView, &Msaa)>, + Res>>, + Res>>, + ), +) where + SM: ShaderModel, + SM::Data: PartialEq + Eq + Hash + Clone, +{ + let draw_function = SM::draw_function(&draw_functions); + + for (view_entity, view, msaa) in &mut views { + let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); + let Some(phase) = phases.get_mut(&view_entity) else { + continue; + }; + + let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); + for (entity) in &nannou_meshes { + let Some(shader_model) = extracted_instances.get(&entity) else { + continue; + }; + let shader_model = shader_models.get(*shader_model).unwrap(); + let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(entity) else { + continue; + }; + let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id) else { + continue; + }; + let mesh_key = + view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); + let key = ShaderModelPipelineKey { + mesh_key, + bind_group_data: shader_model.key.clone(), + }; + let pipeline = pipelines + .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout) + .unwrap(); + phase.add( + Opaque3dBinKey { + draw_function, + pipeline, + asset_id: mesh_instance.mesh_asset_id.into(), + material_bind_group_id: shader_model.get_bind_group_id(), + lightmap_image: None, + }, + entity, + BinnedRenderPhaseType::BatchableMesh, + ); + } + } +} + +#[derive(Resource)] +pub struct ShaderModelPipeline { + mesh_pipeline: MeshPipeline, + shader_model_layout: BindGroupLayout, + vertex_shader: Option>, + fragment_shader: Option>, + marker: PhantomData, +} + +impl FromWorld for ShaderModelPipeline { + fn from_world(world: &mut World) -> Self { + let asset_server = world.resource::(); + let render_device = world.resource::(); + + ShaderModelPipeline { + mesh_pipeline: world.resource::().clone(), + shader_model_layout: SM::bind_group_layout(render_device), + vertex_shader: match ::vertex_shader() { + ShaderRef::Default => Some(DEFAULT_NANNOU_SHADER_HANDLE), + ShaderRef::Handle(handle) => Some(handle), + ShaderRef::Path(path) => Some(asset_server.load(path)), + }, + fragment_shader: match ::fragment_shader() { + ShaderRef::Default => Some(DEFAULT_NANNOU_SHADER_HANDLE), + ShaderRef::Handle(handle) => Some(handle), + ShaderRef::Path(path) => Some(asset_server.load(path)), + }, + marker: PhantomData, + } + } +} + +pub struct ShaderModelPipelineKey { + pub mesh_key: MeshPipelineKey, + pub bind_group_data: SM::Data, +} + +impl Eq for ShaderModelPipelineKey where SM::Data: PartialEq {} + +impl PartialEq for ShaderModelPipelineKey +where + SM::Data: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.mesh_key == other.mesh_key && self.bind_group_data == other.bind_group_data + } +} + +impl Clone for ShaderModelPipelineKey +where + SM::Data: Clone, +{ + fn clone(&self) -> Self { + Self { + mesh_key: self.mesh_key, + bind_group_data: self.bind_group_data.clone(), + } + } +} + +impl Hash for ShaderModelPipelineKey +where + SM::Data: Hash, +{ + fn hash(&self, state: &mut H) { + self.mesh_key.hash(state); + self.bind_group_data.hash(state); + } +} + +impl SpecializedMeshPipeline for ShaderModelPipeline +where + SM::Data: PartialEq + Eq + Hash + Clone, +{ + type Key = ShaderModelPipelineKey; + + fn specialize( + &self, + key: Self::Key, + layout: &MeshVertexBufferLayoutRef, + ) -> Result { + let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?; + if let Some(vertex_shader) = &self.vertex_shader { + descriptor.vertex.shader = vertex_shader.clone(); + } + + if let Some(fragment_shader) = &self.fragment_shader { + descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); + } + + descriptor + .layout + .insert(2, self.shader_model_layout.clone()); + + let pipeline = ShaderModelPipeline { + mesh_pipeline: self.mesh_pipeline.clone(), + shader_model_layout: self.shader_model_layout.clone(), + vertex_shader: self.vertex_shader.clone(), + fragment_shader: self.fragment_shader.clone(), + marker: Default::default(), + }; + SM::specialize(&pipeline, &mut descriptor, layout, key)?; + Ok(descriptor) + } +} + +impl ShaderModel for NannouShaderModel { fn specialize( - _pipeline: &MaterialExtensionPipeline, + _pipeline: &ShaderModelPipeline, descriptor: &mut RenderPipelineDescriptor, _layout: &MeshVertexBufferLayoutRef, - key: MaterialExtensionKey, + key: ShaderModelPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { if let Some(blend) = key.bind_group_data.blend { let fragment = descriptor.fragment.as_mut().unwrap(); @@ -213,31 +510,31 @@ fn setup_default_texture(mut commands: Commands, mut images: ResMut( +fn update_material( draw_q: Query<&DrawHolder>, mut commands: Commands, - mut materials: ResMut>, - materials_q: Query<(Entity, &UntypedMaterialId)>, + mut materials: ResMut>, + materials_q: Query<(Entity, &UntypedShaderModelId)>, ) where - M: Material, + SM: ShaderModel, { for draw in draw_q.iter() { let state = draw.state.write().unwrap(); - state.materials.iter().for_each(|(id, material)| { - if id.type_id() == TypeId::of::() { - let material = material.downcast_ref::().unwrap(); - materials.insert(id.typed(), material.clone()); + state.shader_models.iter().for_each(|(id, model)| { + if id.type_id() == TypeId::of::() { + let model = model.downcast_ref::().unwrap(); + materials.insert(id.typed(), model.clone()); } }); } - for (entity, UntypedMaterialId(id)) in materials_q.iter() { - if id.type_id() == TypeId::of::() { + for (entity, UntypedShaderModelId(id)) in materials_q.iter() { + if id.type_id() == TypeId::of::() { commands .entity(entity) - .insert(Handle::Weak(id.typed::())); + .insert(Handle::Weak(id.typed::())); } } } @@ -323,7 +620,7 @@ fn update_draw_mesh( commands.spawn(( InstancedMesh, InstanceRange(range), - UntypedMaterialId(mat_id), + UntypedShaderModelId(mat_id), mesh.clone(), Transform::default(), GlobalTransform::default(), @@ -358,7 +655,7 @@ fn update_draw_mesh( commands.spawn(( IndirectMesh, indirect_buffer, - UntypedMaterialId(mat_id), + UntypedShaderModelId(mat_id), mesh.clone(), Transform::default(), GlobalTransform::default(), @@ -373,12 +670,12 @@ fn update_draw_mesh( DrawCommand::Context(ctx) => { curr_ctx = ctx; } - DrawCommand::Material(mat_id) => { + DrawCommand::ShaderModel(model_id) => { // We switched materials, so start rendering into a new mesh - last_mat = Some(mat_id.clone()); + last_mat = Some(model_id.clone()); mesh = meshes.add(Mesh::init()); commands.spawn(( - UntypedMaterialId(mat_id), + UntypedShaderModelId(model_id), mesh.clone(), Transform::default(), GlobalTransform::default(), @@ -398,7 +695,7 @@ fn update_draw_mesh( } } -#[derive(Component)] +#[derive(Component, ExtractComponent, Clone)] pub struct NannouMesh; #[derive(Resource)] diff --git a/examples/compute/particle_mouse.rs b/examples/compute/particle_mouse.rs index 986c33a74..9def1fa33 100644 --- a/examples/compute/particle_mouse.rs +++ b/examples/compute/particle_mouse.rs @@ -165,7 +165,7 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(GRAY); - let draw = draw.material(model.material()); + let draw = draw.shader_model(model.material()); match model.shape { Shape::Circle => { draw_particles_circle(&draw); diff --git a/examples/compute/particle_sdf.rs b/examples/compute/particle_sdf.rs index 72cbc9427..0d838231f 100644 --- a/examples/compute/particle_sdf.rs +++ b/examples/compute/particle_sdf.rs @@ -232,7 +232,7 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(GRAY); - let draw = draw.material(model.material()); + let draw = draw.shader_model(model.material()); draw.indirect() .primitive(draw.rect().w_h(2.0, 2.0)) .buffer(model.indirect_params.clone()); diff --git a/examples/draw/draw_custom_material.rs b/examples/draw/draw_custom_material.rs index de9ccb76c..b0f1c6718 100644 --- a/examples/draw/draw_custom_material.rs +++ b/examples/draw/draw_custom_material.rs @@ -26,13 +26,13 @@ fn view(app: &App, model: &Model, window: Entity) { let draw = app .draw() // Initialize our draw instance with our custom material - .material(ShaderModel { color: RED.into() }); + .shader_model(ShaderModel { color: RED.into() }); draw.ellipse().x(-200.0); // We can also map the material manually draw.ellipse() - .map_material(|mut mat| { + .map_shader_model(|mut mat| { mat.color = BLUE.into(); mat }) diff --git a/examples/video/video_material.rs b/examples/video/video_material.rs index d4f1d72a4..0a3f2ca15 100644 --- a/examples/video/video_material.rs +++ b/examples/video/video_material.rs @@ -52,7 +52,7 @@ fn view(app: &App, model: &Model) { let draw = app .draw() // Initialize our draw instance with our custom material - .material(VideoShaderModel { + .shader_model(VideoShaderModel { texture: video.texture.clone(), }); diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 44539a48a..4ed5794e4 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -40,8 +40,7 @@ use bevy_inspector_egui::DefaultInspectorConfigPlugin; use crate::frame::{Frame, FramePlugin}; use crate::prelude::bevy_ecs::system::SystemState; use crate::prelude::bevy_reflect::DynamicTyped; -use crate::prelude::render::{NannouMaterialPlugin, NannouMesh, ShaderModel}; -use crate::prelude::NannouShaderModelPlugin; +use crate::prelude::render::{NannouShaderModelPlugin, NannouMesh, ShaderModel}; use crate::render::{ compute::{Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState}, NannouRenderNode, RenderApp, RenderPlugin, @@ -358,7 +357,6 @@ where SM::Data: PartialEq + Eq + Hash + Clone, { self.app.add_plugins(( - NannouMaterialPlugin::::default(), NannouShaderModelPlugin::::default(), )); self @@ -440,13 +438,6 @@ where /// initialised on the main thread. pub fn run(mut self) { self.app - // This ensures that color materials are rendered correctly. - .insert_resource(AmbientLight { - color: Color::WHITE, - // This isn't randomly chosen - // See: https://discord.com/channels/691052431525675048/866787577687310356/1229248273735487560 - brightness: 998.096, - }) .insert_resource(self.config.clone()) .insert_resource(ModelFnRes(self.model)) .insert_resource(EventFnRes(self.event)) diff --git a/nannou_osc/src/send.rs b/nannou_osc/src/send.rs index e408b58dd..645b624ea 100644 --- a/nannou_osc/src/send.rs +++ b/nannou_osc/src/send.rs @@ -24,7 +24,7 @@ pub fn default_sender_socket_addr_v4() -> SocketAddrV4 { SocketAddrV4::new(super::default_ipv4_addr(), DEFAULT_PORT) } -impl Sender { +impl Sender { /// The socket address that this `Sender`'s socket was created from. pub fn local_addr(&self) -> Result { self.socket.local_addr() From c4df15c981da6f7de3afe61250e513431a7725c6 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Thu, 26 Sep 2024 21:43:09 -0700 Subject: [PATCH 2/9] Fixes. --- bevy_nannou_draw/src/draw/drawing.rs | 30 ++--- bevy_nannou_draw/src/draw/indirect.rs | 53 ++++---- bevy_nannou_draw/src/draw/instanced.rs | 56 +++++---- bevy_nannou_draw/src/draw/mod.rs | 46 +++---- bevy_nannou_draw/src/render.rs | 168 ++++++++++++++++--------- bevy_nannou_isf/src/render.rs | 2 +- examples/draw/draw_texture.rs | 5 +- 7 files changed, 204 insertions(+), 156 deletions(-) diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index bf120db1f..bdb1ea8ff 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -33,8 +33,8 @@ where draw: DrawRef<'a, SM>, // The draw command index of the primitive being drawn. pub(crate) index: usize, - // The draw command index of the material being used. - pub(crate) material_index: usize, + // The draw command index of the shader model being used. + pub(crate) shader_model_index: usize, // Whether the **Drawing** should attempt to finish the drawing on drop. pub(crate) finish_on_drop: bool, // The node type currently being drawn. @@ -56,7 +56,7 @@ pub struct DrawingContext<'a> { } /// Construct a new **Drawing** instance. -pub fn new(draw: &Draw, index: usize, material_index: usize) -> Drawing +pub fn new(draw: &Draw, index: usize, model_index: usize) -> Drawing where T: Into, SM: ShaderModel + Default, @@ -66,7 +66,7 @@ where Drawing { draw: DrawRef::Borrowed(draw), index, - material_index, + shader_model_index: model_index, finish_on_drop, _ty, } @@ -117,10 +117,10 @@ where // If we are "Owned", that means we mutated our material and so need to // spawn a new entity just for this primitive. DrawRef::Owned(draw) => { - let id = draw.material.clone(); + let id = draw.shader_model.clone(); let material_cmd = state .draw_commands - .get_mut(self.material_index) + .get_mut(self.shader_model_index) .expect("Expected a valid material index"); if let None = material_cmd { *material_cmd = Some(DrawCommand::ShaderModel(id)); @@ -151,12 +151,12 @@ where let Drawing { ref draw, index, - material_index, + shader_model_index: material_index, .. } = self; let state = draw.state.clone(); - let material = state.read().unwrap().shader_models[&self.draw.material] + let material = state.read().unwrap().shader_models[&self.draw.shader_model] .downcast_ref::() .unwrap() .clone(); @@ -171,12 +171,12 @@ where state.shader_models.insert(new_id.clone(), Box::new(material)); // Mark the last material as the new material so that further drawings use the same material // as the parent draw ref. - state.last_material = Some(new_id.clone()); + state.last_shader_model = Some(new_id.clone()); let draw = Draw { state: draw.state.clone(), context: draw.context.clone(), - material: new_id.clone(), + shader_model: new_id.clone(), window: draw.window, _material: Default::default(), }; @@ -184,7 +184,7 @@ where Drawing { draw: DrawRef::Owned(draw), index, - material_index, + shader_model_index: material_index, finish_on_drop: true, _ty: PhantomData, } @@ -208,13 +208,13 @@ where let Drawing { ref draw, index, - material_index, + shader_model_index: material_index, .. } = self; Drawing { draw: draw.clone(), index, - material_index, + shader_model_index: material_index, finish_on_drop: true, _ty: PhantomData, } @@ -242,13 +242,13 @@ where let Drawing { ref draw, index, - material_index, + shader_model_index: material_index, .. } = self; Drawing { draw: draw.clone(), index, - material_index, + shader_model_index: material_index, finish_on_drop: true, _ty: PhantomData, } diff --git a/bevy_nannou_draw/src/draw/indirect.rs b/bevy_nannou_draw/src/draw/indirect.rs index a1b3b2337..eaa987a55 100644 --- a/bevy_nannou_draw/src/draw/indirect.rs +++ b/bevy_nannou_draw/src/draw/indirect.rs @@ -1,38 +1,32 @@ //! A shader that renders a mesh multiple times in one draw call. -use crate::draw::drawing::Drawing; -use crate::draw::primitive::Primitive; -use crate::draw::{Draw, DrawCommand}; -use crate::render::{PreparedShaderModel, ShaderModel}; -use bevy::render::extract_instances::ExtractedInstances; -use bevy::render::mesh::allocator::MeshAllocator; -use bevy::render::mesh::RenderMeshBufferInfo; -use bevy::render::render_asset::RenderAsset; -use bevy::render::storage::{GpuShaderStorageBuffer, ShaderStorageBuffer}; +use crate::{ + draw::{drawing::Drawing, primitive::Primitive, Draw, DrawCommand}, + render::{ + queue_shader_model, DrawShaderModel, PreparedShaderModel, ShaderModel, ShaderModelMesh, + }, +}; use bevy::{ - core_pipeline::core_3d::Opaque3d, + core_pipeline::core_3d::Transparent3d, ecs::system::{lifetimeless::*, SystemParamItem}, - pbr::{ - RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, - }, + pbr::{RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup}, prelude::*, render::{ - extract_component::ExtractComponent, - mesh::RenderMesh, - render_asset::RenderAssets, + extract_component::{ExtractComponent, ExtractComponentPlugin}, + extract_instances::ExtractedInstances, + mesh::{allocator::MeshAllocator, RenderMesh, RenderMeshBufferInfo}, + render_asset::{prepare_assets, RenderAsset, RenderAssets}, render_phase::{ - AddRenderCommand, PhaseItem, RenderCommand, - RenderCommandResult, SetItemPipeline, TrackedRenderPass, + AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, + SetItemPipeline, TrackedRenderPass, }, - render_resource::* - - - , RenderApp, + render_resource::*, + storage::{GpuShaderStorageBuffer, ShaderStorageBuffer}, + Render, RenderApp, RenderSet, }, }; use rayon::prelude::*; -use std::hash::Hash; -use std::marker::PhantomData; +use std::{hash::Hash, marker::PhantomData}; pub struct Indirect<'a, SM> where @@ -121,8 +115,15 @@ where SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.sub_app_mut(RenderApp) - .add_render_command::>(); + app + .sub_app_mut(RenderApp) + .add_render_command::>() + .add_systems( + Render, + queue_shader_model::, DrawIndirectMaterial> + .after(prepare_assets::>) + .in_set(RenderSet::QueueMeshes), + ); } } diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index b331af727..bd68295ed 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -1,43 +1,38 @@ //! A shader that renders a mesh multiple times in one draw call. -use crate::draw::drawing::Drawing; -use crate::draw::primitive::Primitive; -use crate::draw::{Draw, DrawCommand}; -use crate::render::{PreparedShaderModel, ShaderModel}; -use bevy::core_pipeline::core_3d::Opaque3dBinKey; -use bevy::pbr::{MaterialPipeline, MaterialPipelineKey, PreparedMaterial}; -use bevy::render::extract_component::ExtractComponentPlugin; -use bevy::render::extract_instances::ExtractedInstances; -use bevy::render::mesh::allocator::MeshAllocator; -use bevy::render::mesh::RenderMeshBufferInfo; -use bevy::render::render_asset::prepare_assets; -use bevy::render::render_phase::{BinnedRenderPhaseType, ViewBinnedRenderPhases}; -use bevy::render::storage::GpuShaderStorageBuffer; -use bevy::render::view; -use bevy::render::view::VisibilitySystems; +use crate::{ + draw::{drawing::Drawing, primitive::Primitive, Draw, DrawCommand}, + render::{queue_shader_model, PreparedShaderModel, ShaderModel}, +}; use bevy::{ - core_pipeline::core_3d::Opaque3d, + core_pipeline::core_3d::Transparent3d, ecs::system::{lifetimeless::*, SystemParamItem}, - pbr::{MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshViewBindGroup}, + pbr::{ + MaterialPipeline, MaterialPipelineKey, MeshPipeline, MeshPipelineKey, PreparedMaterial, + RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, + }, prelude::*, render::{ - extract_component::ExtractComponent, - mesh::{MeshVertexBufferLayoutRef, RenderMesh}, - render_asset::RenderAssets, + extract_component::{ExtractComponent, ExtractComponentPlugin}, + extract_instances::ExtractedInstances, + mesh::{ + allocator::MeshAllocator, MeshVertexBufferLayoutRef, RenderMesh, RenderMeshBufferInfo, + }, + render_asset::{prepare_assets, RenderAssets}, render_phase::{ - AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, - SetItemPipeline, TrackedRenderPass, + AddRenderCommand, BinnedRenderPhaseType, DrawFunctions, PhaseItem, RenderCommand, + RenderCommandResult, SetItemPipeline, TrackedRenderPass, ViewBinnedRenderPhases, }, render_resource::*, renderer::RenderDevice, - view::ExtractedView, + storage::GpuShaderStorageBuffer, + view, + view::{ExtractedView, VisibilitySystems}, Render, RenderApp, RenderSet, }, }; use rayon::prelude::*; -use std::hash::Hash; -use std::marker::PhantomData; -use std::ops::Range; +use std::{hash::Hash, marker::PhantomData, ops::Range}; pub struct Instanced<'a, SM> where @@ -126,13 +121,20 @@ where { fn build(&self, app: &mut App) { app.sub_app_mut(RenderApp) - .add_render_command::>(); + .add_render_command::>() + .add_systems( + Render, + queue_shader_model::, DrawInstancedMaterial> + .after(prepare_assets::>) + .in_set(RenderSet::QueueMeshes), + ); } } type DrawInstancedMaterial = ( SetItemPipeline, SetMeshViewBindGroup<0>, + SetMeshBindGroup<1>, SetShaderModelBindGroup, DrawMeshInstanced, ); diff --git a/bevy_nannou_draw/src/draw/mod.rs b/bevy_nannou_draw/src/draw/mod.rs index 3f46047ff..481b49905 100644 --- a/bevy_nannou_draw/src/draw/mod.rs +++ b/bevy_nannou_draw/src/draw/mod.rs @@ -66,7 +66,7 @@ where /// The current context of this [Draw] instance. context: DrawContext, /// The current material of this [Draw] instance. - material: UntypedAssetId, + shader_model: UntypedAssetId, /// The window to which this [Draw] instance is associated. pub(crate) window: Entity, /// The type of material used by this [Draw] instance. @@ -139,7 +139,7 @@ pub enum DrawCommand { /// about mutability and instead focus on creativity. Rust-lang nuances can come later. pub struct State { /// The last material used to draw an image, used to detect changes and emit commands for them. - last_material: Option, + last_shader_model: Option, /// The last context used to draw an image, used to detect changes and emit commands for them. last_draw_context: Option, /// If `Some`, the [Draw] should first clear the frame's texture with the given color. @@ -188,7 +188,7 @@ impl IntermediaryState { impl State { // Resets all state within the `Draw` instance. fn reset(&mut self) { - self.last_material = None; + self.last_shader_model = None; self.last_draw_context = None; self.background_color = None; self.drawing.clear(); @@ -233,17 +233,17 @@ where pub fn new(window: Entity) -> Self { let mut state = State::default(); let context = DrawContext::default(); - let material = SM::default(); - let material_id = UntypedAssetId::Uuid { + let model = SM::default(); + let model_id = UntypedAssetId::Uuid { type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; - state.shader_models.insert(material_id, Box::new(material)); + state.shader_models.insert(model_id, Box::new(model)); Draw { state: Arc::new(RwLock::new(state)), context, - material: material_id, + shader_model: model_id, window, _material: PhantomData, } @@ -252,18 +252,18 @@ where /// Resets all state within the `Draw` instance. pub fn reset(&mut self) { self.state.write().unwrap().reset(); - self.insert_default_material(); + self.insert_default_shader_model(); } - fn insert_default_material(&mut self) { + fn insert_default_shader_model(&mut self) { let mut state = self.state.write().unwrap(); - let material = SM::default(); - let material_id = UntypedAssetId::Uuid { + let model = SM::default(); + let model_id = UntypedAssetId::Uuid { type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; - state.shader_models.insert(material_id, Box::new(material)); - self.material = material_id; + state.shader_models.insert(model_id, Box::new(model)); + self.shader_model = model_id; } // Context changes. @@ -458,12 +458,12 @@ where /// Produce a new [Draw] instance with the given context. fn context(&self, context: DrawContext) -> Draw { let state = self.state.clone(); - let material = self.material.clone(); + let material = self.shader_model.clone(); let window = self.window; Draw { state, context, - material, + shader_model: material, window, _material: PhantomData, } @@ -471,7 +471,7 @@ where fn clone_shader_model(&self) -> SM { let mut state = self.state.write().unwrap(); - let material = state.shader_models.get_mut(&self.material).unwrap(); + let material = state.shader_models.get_mut(&self.shader_model).unwrap(); material .downcast_ref::() .expect("Expected material to be of the correct type") @@ -499,7 +499,7 @@ where Draw { state, context, - material: model_id, + shader_model: model_id, window, _material: PhantomData, } @@ -527,7 +527,7 @@ where T: Into, Primitive: Into>, { - let (index, material_index) = { + let (index, model_index) = { let mut state = self.state.write().unwrap(); // If drawing with a different context, insert the necessary command to update it. if state.last_draw_context.as_ref() != Some(&self.context) { @@ -537,12 +537,12 @@ where state.last_draw_context = Some(self.context.clone()); } - let id = &self.material; - if state.last_material.as_ref() != Some(id) { + let id = &self.shader_model; + if state.last_shader_model.as_ref() != Some(id) { state .draw_commands .push(Some(DrawCommand::ShaderModel(id.clone()))); - state.last_material = Some(id.clone()); + state.last_shader_model = Some(id.clone()); } // Insert a material slot to be used if the drawing switches materials. @@ -556,7 +556,7 @@ where state.drawing.insert(index, primitive); (index, material_index) }; - drawing::new(self, index, material_index) + drawing::new(self, index, model_index) } /// Begin drawing a **Path**. @@ -702,7 +702,7 @@ impl Default for State { let intermediary_state = Arc::new(Default::default()); let theme = Default::default(); State { - last_material, + last_shader_model: last_material, last_draw_context, draw_commands, drawing, diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index a6f7e03aa..bc5b7756e 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -1,40 +1,60 @@ -use crate::draw::indirect::{IndirectMaterialPlugin, IndirectMesh}; -use crate::draw::instanced::{InstanceRange, InstancedMaterialPlugin, InstancedMesh}; -use crate::draw::mesh::MeshExt; -use crate::draw::render::{RenderContext, RenderPrimitive}; -use crate::draw::{DrawCommand, DrawContext}; -use crate::DrawHolder; -use bevy::asset::UntypedAssetId; -use bevy::asset::{load_internal_asset, Asset}; -use bevy::core_pipeline::core_3d::{Opaque3d, Opaque3dBinKey}; -use bevy::ecs::system::lifetimeless::SRes; -use bevy::ecs::system::SystemParamItem; -use bevy::pbr::{DefaultOpaqueRendererMethod, DrawMesh, ExtendedMaterial, MaterialBindGroupId, MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, MaterialPipeline, MaterialProperties, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, StandardMaterial}; -use bevy::prelude::TypePath; -use bevy::prelude::*; -use bevy::render::camera::RenderTarget; -use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; -use bevy::render::extract_instances::{ExtractInstancesPlugin, ExtractedInstances}; -use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; -use bevy::render::mesh::{MeshVertexBufferLayoutRef, RenderMesh}; -use bevy::render::render_asset::{ - prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets, +use crate::{ + draw::{ + indirect::{IndirectMaterialPlugin, IndirectMesh}, + instanced::{InstanceRange, InstancedMaterialPlugin, InstancedMesh}, + mesh::MeshExt, + render::{RenderContext, RenderPrimitive}, + DrawCommand, DrawContext, + }, + DrawHolder, }; -use bevy::render::render_phase::{ - AddRenderCommand, BinnedRenderPhaseType, DrawFunctionId, DrawFunctions, PhaseItem, - RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass, ViewBinnedRenderPhases, +use bevy::{ + asset::{load_internal_asset, Asset, UntypedAssetId}, + core_pipeline::core_3d::Transparent3d, + ecs::{ + query::QueryFilter, + system::{lifetimeless::SRes, SystemParamItem}, + }, + pbr::{ + DefaultOpaqueRendererMethod, DrawMesh, ExtendedMaterial, MaterialBindGroupId, + MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, MaterialPipeline, + MaterialProperties, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, + RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, StandardMaterial, + }, + prelude::{TypePath, *}, + render::{ + camera::RenderTarget, + extract_component::{ExtractComponent, ExtractComponentPlugin}, + extract_instances::{ExtractInstancesPlugin, ExtractedInstances}, + extract_resource::{ExtractResource, ExtractResourcePlugin}, + mesh::{MeshVertexBufferLayoutRef, RenderMesh}, + render_asset::{ + prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets, + }, + render_phase::{ + AddRenderCommand, BinnedRenderPhaseType, DrawFunctionId, DrawFunctions, PhaseItem, + PhaseItemExtraIndex, RenderCommand, RenderCommandResult, SetItemPipeline, + TrackedRenderPass, ViewBinnedRenderPhases, ViewSortedRenderPhases, + }, + render_resource as wgpu, + render_resource::{ + AsBindGroup, AsBindGroupError, AsBindGroupShaderType, BindGroup, BindGroupId, + BindGroupLayout, BlendState, OwnedBindingResource, PipelineCache, PolygonMode, + RenderPipelineDescriptor, ShaderRef, ShaderType, SpecializedMeshPipeline, + SpecializedMeshPipelineError, SpecializedMeshPipelines, + }, + renderer::RenderDevice, + texture::GpuImage, + view, + view::{ExtractedView, NoFrustumCulling, RenderLayers, VisibilitySystems}, + RenderApp, RenderSet, + RenderSet::Render, + }, + window::WindowRef, }; -use bevy::render::render_resource::{AsBindGroup, AsBindGroupError, AsBindGroupShaderType, BindGroup, BindGroupId, BindGroupLayout, BlendState, OwnedBindingResource, PipelineCache, PolygonMode, RenderPipelineDescriptor, ShaderRef, ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines}; -use bevy::render::renderer::RenderDevice; -use bevy::render::texture::GpuImage; -use bevy::render::view::{ExtractedView, NoFrustumCulling, RenderLayers, VisibilitySystems}; -use bevy::render::RenderSet::Render; -use bevy::render::{render_resource as wgpu, view, RenderApp, RenderSet}; -use bevy::window::WindowRef; use lyon::lyon_tessellation::{FillTessellator, StrokeTessellator}; -use std::any::TypeId; -use std::hash::Hash; -use std::marker::PhantomData; +use std::{any::TypeId, hash::Hash, marker::PhantomData}; +use bevy::render::storage::ShaderStorageBuffer; pub const DEFAULT_NANNOU_SHADER_HANDLE: Handle = Handle::weak_from_u128(3086880141013591); @@ -63,10 +83,6 @@ pub trait ShaderModel: ) -> Result<(), SpecializedMeshPipelineError> { Ok(()) } - - fn draw_function(draw_functions: &DrawFunctions

) -> DrawFunctionId { - draw_functions.read().id::>() - } } pub struct NannouRenderPlugin; @@ -84,6 +100,12 @@ impl Plugin for NannouRenderPlugin { .add_plugins(( ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::>::default(), + ExtractComponentPlugin::::default(), ExtractResourcePlugin::::default(), NannouShaderModelPlugin::::default(), )) @@ -92,7 +114,7 @@ impl Plugin for NannouRenderPlugin { PostUpdate, ( update_draw_mesh, - view::check_visibility::> + view::check_visibility::> .in_set(VisibilitySystems::CheckVisibility), ), ); @@ -100,7 +122,7 @@ impl Plugin for NannouRenderPlugin { } #[derive(Default)] -pub struct NannouShaderModelPlugin(std::marker::PhantomData); +pub struct NannouShaderModelPlugin(PhantomData); impl Plugin for NannouShaderModelPlugin where @@ -115,15 +137,14 @@ where IndirectMaterialPlugin::::default(), InstancedMaterialPlugin::::default(), )) - .add_systems(PostUpdate, update_material::.after(update_draw_mesh)) .add_systems(PostUpdate, update_material::.after(update_draw_mesh)); app.sub_app_mut(RenderApp) - .add_render_command::>() + .add_render_command::>() .init_resource::>>() .add_systems( bevy::render::Render, - queue_shader_model:: + queue_shader_model::, DrawShaderModel> .after(prepare_assets::>) .in_set(RenderSet::QueueMeshes), ); @@ -204,7 +225,7 @@ impl RenderCommand

} } -type DrawShaderModel = ( +pub type DrawShaderModel = ( SetItemPipeline, SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, @@ -278,8 +299,8 @@ impl From<&NannouShaderModel> for NannouMaterialKey { } #[allow(clippy::too_many_arguments)] -fn queue_shader_model( - draw_functions: Res>, +pub(crate) fn queue_shader_model( + draw_functions: Res>, custom_pipeline: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, @@ -293,8 +314,8 @@ fn queue_shader_model( extracted_instances, ): ( Res, - Query>, - ResMut>, + Query<(Entity, &DrawIndex), QF>, + ResMut>, Query<(Entity, &ExtractedView, &Msaa)>, Res>>, Res>>, @@ -302,8 +323,10 @@ fn queue_shader_model( ) where SM: ShaderModel, SM::Data: PartialEq + Eq + Hash + Clone, + QF: QueryFilter, + RC: 'static, { - let draw_function = SM::draw_function(&draw_functions); + let draw_function = draw_functions.read().id::(); for (view_entity, view, msaa) in &mut views { let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); @@ -312,11 +335,13 @@ fn queue_shader_model( }; let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); - for (entity) in &nannou_meshes { + for (entity, draw_idx) in &nannou_meshes { let Some(shader_model) = extracted_instances.get(&entity) else { continue; }; - let shader_model = shader_models.get(*shader_model).unwrap(); + let Some(shader_model) = shader_models.get(*shader_model) else { + continue; + }; let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(entity) else { continue; }; @@ -332,17 +357,15 @@ fn queue_shader_model( let pipeline = pipelines .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout) .unwrap(); - phase.add( - Opaque3dBinKey { - draw_function, - pipeline, - asset_id: mesh_instance.mesh_asset_id.into(), - material_bind_group_id: shader_model.get_bind_group_id(), - lightmap_image: None, - }, + + phase.add(Transparent3d { + distance: draw_idx.0 as f32, + pipeline, entity, - BinnedRenderPhaseType::BatchableMesh, - ); + draw_function, + batch_range: Default::default(), + extra_index: PhaseItemExtraIndex(0), + }); } } } @@ -577,7 +600,7 @@ fn update_draw_mesh( let draw_state = draw.state.read().unwrap(); let intermediary_state = draw_state.intermediary_state.read().unwrap(); - for cmd in draw_cmds { + for (idx, cmd) in draw_cmds.enumerate() { match cmd { DrawCommand::Primitive(prim) => { // Info required during rendering. @@ -629,6 +652,7 @@ fn update_draw_mesh( ViewVisibility::default(), NannouMesh, NoFrustumCulling, + DrawIndex(idx), window_layers.clone(), )); } @@ -664,6 +688,7 @@ fn update_draw_mesh( ViewVisibility::default(), NannouMesh, NoFrustumCulling, + DrawIndex(idx), window_layers.clone(), )); } @@ -682,8 +707,10 @@ fn update_draw_mesh( Visibility::default(), InheritedVisibility::default(), ViewVisibility::default(), + ShaderModelMesh, NannouMesh, NoFrustumCulling, + DrawIndex(idx), window_layers.clone(), )); } @@ -692,12 +719,29 @@ fn update_draw_mesh( } } } + + check_and_despawn_empty_mesh(&mut meshes, &mut mesh); + } +} + +fn check_and_despawn_empty_mesh(meshes: &mut ResMut>, mesh: &mut Handle) { + if let Some(m) = meshes.get(&*mesh) { + // Remove the mesh if it has no vertices, which can happen if the user draws nothing + if !m.count_vertices() > 0 { + meshes.remove(&*mesh); + } } } +#[derive(Component, ExtractComponent, Clone)] +pub struct DrawIndex(pub usize); + #[derive(Component, ExtractComponent, Clone)] pub struct NannouMesh; +#[derive(Component, ExtractComponent, Clone)] +pub struct ShaderModelMesh; + #[derive(Resource)] pub struct NannouRender { pub mesh: Handle, diff --git a/bevy_nannou_isf/src/render.rs b/bevy_nannou_isf/src/render.rs index 725e1f97b..f00ac95ef 100644 --- a/bevy_nannou_isf/src/render.rs +++ b/bevy_nannou_isf/src/render.rs @@ -1,6 +1,6 @@ use bevy::asset::embedded_asset; use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; -use bevy::core_pipeline::core_3d::{Opaque3d, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT}; +use bevy::core_pipeline::core_3d::{CORE_3D_DEPTH_FORMAT}; use bevy::core_pipeline::fullscreen_vertex_shader::{ fullscreen_shader_vertex_state, FULLSCREEN_SHADER_HANDLE, }; diff --git a/examples/draw/draw_texture.rs b/examples/draw/draw_texture.rs index 3d4d2d02a..8d1822fac 100644 --- a/examples/draw/draw_texture.rs +++ b/examples/draw/draw_texture.rs @@ -12,7 +12,7 @@ struct Model { fn model(app: &App) -> Model { // Create a new window! - app.new_window().size(512, 512).view(view).build(); + app.new_window().size(512, 512).primary().view(view).build(); // Load the image from disk and upload it to a GPU texture. let assets = app.assets_path(); let img_path = assets.join("images").join("nature").join("nature_1.jpg"); @@ -25,5 +25,6 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(BLACK); let win = app.window_rect(); - draw.rect().x_y(win.x(), win.y()).texture(&model.texture); + draw.rect().x_y(win.x(), win.y()) + .texture(&model.texture); } From c27fb1cddaecd1bc2e267dc8cfbf976929447b24 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Thu, 26 Sep 2024 22:10:20 -0700 Subject: [PATCH 3/9] Fixes. --- examples/draw/draw_blend.rs | 1 - nannou/src/render/mod.rs | 34 ++++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/examples/draw/draw_blend.rs b/examples/draw/draw_blend.rs index 58e587f2d..87bd02565 100644 --- a/examples/draw/draw_blend.rs +++ b/examples/draw/draw_blend.rs @@ -54,7 +54,6 @@ fn view(app: &App) { let hue = i as f32 / n_circles as f32; let color = Color::hsl(hue, 1.0, 0.5); draw.ellipse() - // .color_blend(desc.clone()) .radius(radius) .color(color) .x(radius + animate_radius); diff --git a/nannou/src/render/mod.rs b/nannou/src/render/mod.rs index 9cefc5c37..4903a076e 100644 --- a/nannou/src/render/mod.rs +++ b/nannou/src/render/mod.rs @@ -1,21 +1,27 @@ -use crate::app::{ModelHolder, RenderFnRes}; -use crate::frame::Frame; -use crate::prelude::bevy_render::extract_component::ExtractComponent; -use crate::prelude::bevy_render::extract_resource::extract_resource; -use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; -use bevy::ecs::query::QueryItem; +use crate::{ + app::{ModelHolder, RenderFnRes}, + frame::Frame, + prelude::bevy_render::{ + extract_component::ExtractComponent, extract_resource::extract_resource, + }, +}; pub use bevy::prelude::*; -use bevy::render::extract_resource::ExtractResource; -use bevy::render::render_graph::{ - NodeRunError, RenderGraphApp, RenderGraphContext, RenderLabel, ViewNode, ViewNodeRunner, +use bevy::{ + core_pipeline::core_3d::graph::{Core3d, Node3d}, + ecs::query::QueryItem, + render::{ + extract_resource::ExtractResource, + render_graph::{ + NodeRunError, RenderGraphApp, RenderGraphContext, RenderLabel, ViewNode, ViewNodeRunner, + }, + render_resource::SpecializedComputePipeline, + renderer::RenderContext, + view::{ExtractedView, ExtractedWindows, ViewTarget}, + }, }; -use bevy::render::render_resource::SpecializedComputePipeline; -use bevy::render::renderer::RenderContext; -use bevy::render::view::{ExtractedView, ExtractedWindows, ViewTarget}; use bevy_nannou::prelude::AsBindGroup; use noise::NoiseFn; -use std::hash::Hash; -use std::ops::Deref; +use std::{hash::Hash, ops::Deref}; pub mod compute; From ebc74c8b006ac1c302a03dba4dcb969f70e263a7 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Thu, 26 Sep 2024 22:20:42 -0700 Subject: [PATCH 4/9] Cleanup names. --- bevy_nannou_draw/src/draw/drawing.rs | 34 +++++----- bevy_nannou_draw/src/draw/indirect.rs | 4 +- bevy_nannou_draw/src/draw/instanced.rs | 4 +- bevy_nannou_draw/src/draw/mod.rs | 40 +++++------ bevy_nannou_draw/src/render.rs | 50 +++++++------- bevy_nannou_isf/src/asset.rs | 2 +- examples/Cargo.toml | 14 ++-- ...ial.wgsl => draw_custom_shader_model.wgsl} | 6 +- ...aterial.wgsl => particle_mouse_model.wgsl} | 0 ..._material.wgsl => particle_sdf_model.wgsl} | 0 ...w_video_material.wgsl => video_model.wgsl} | 0 examples/compute/particle_mouse.rs | 8 +-- examples/compute/particle_sdf.rs | 8 +-- ...aterial.rs => draw_custom_shader_model.rs} | 8 +-- examples/draw/draw_material.rs | 66 ------------------- examples/draw/draw_material_bloom.rs | 58 ---------------- ...ideo_material.rs => video_shader_model.rs} | 6 +- 17 files changed, 89 insertions(+), 219 deletions(-) rename examples/assets/{draw_custom_material.wgsl => draw_custom_shader_model.wgsl} (54%) rename examples/assets/shaders/{particle_mouse_material.wgsl => particle_mouse_model.wgsl} (100%) rename examples/assets/shaders/{particle_sdf_material.wgsl => particle_sdf_model.wgsl} (100%) rename examples/assets/{draw_video_material.wgsl => video_model.wgsl} (100%) rename examples/draw/{draw_custom_material.rs => draw_custom_shader_model.rs} (71%) delete mode 100644 examples/draw/draw_material.rs delete mode 100644 examples/draw/draw_material_bloom.rs rename examples/video/{video_material.rs => video_shader_model.rs} (84%) diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index bdb1ea8ff..7ccb2ba48 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -114,16 +114,16 @@ where Err(err) => eprintln!("drawing failed to borrow state and finish: {}", err), Ok(mut state) => { match &self.draw { - // If we are "Owned", that means we mutated our material and so need to + // If we are "Owned", that means we mutated our shader model and so need to // spawn a new entity just for this primitive. DrawRef::Owned(draw) => { let id = draw.shader_model.clone(); - let material_cmd = state + let shader_model_cmd = state .draw_commands .get_mut(self.shader_model_index) - .expect("Expected a valid material index"); - if let None = material_cmd { - *material_cmd = Some(DrawCommand::ShaderModel(id)); + .expect("Expected a valid shdaer model index"); + if let None = shader_model_cmd { + *shader_model_cmd = Some(DrawCommand::ShaderModel(id)); } } DrawRef::Borrowed(_) => (), @@ -140,7 +140,7 @@ where self.finish_inner() } - // Map the the parent's material to a new material type, taking ownership over the + // Map the the parent's shader model to a new shader model type, taking ownership over the // draw instance clone. pub fn map_shader_model(mut self, map: F) -> Drawing<'a, T, SM> where @@ -151,12 +151,12 @@ where let Drawing { ref draw, index, - shader_model_index: material_index, + shader_model_index: shader_model_index, .. } = self; let state = draw.state.clone(); - let material = state.read().unwrap().shader_models[&self.draw.shader_model] + let shader_model = state.read().unwrap().shader_models[&self.draw.shader_model] .downcast_ref::() .unwrap() .clone(); @@ -166,10 +166,10 @@ where uuid: Uuid::new_v4(), }; - let material = map(material.clone()); + let shader_model = map(shader_model.clone()); let mut state = state.write().unwrap(); - state.shader_models.insert(new_id.clone(), Box::new(material)); - // Mark the last material as the new material so that further drawings use the same material + state.shader_models.insert(new_id.clone(), Box::new(shader_model)); + // Mark the last shader model as the new model so that further drawings use the same model // as the parent draw ref. state.last_shader_model = Some(new_id.clone()); @@ -178,13 +178,13 @@ where context: draw.context.clone(), shader_model: new_id.clone(), window: draw.window, - _material: Default::default(), + _shader_model: Default::default(), }; Drawing { draw: DrawRef::Owned(draw), index, - shader_model_index: material_index, + shader_model_index, finish_on_drop: true, _ty: PhantomData, } @@ -208,13 +208,13 @@ where let Drawing { ref draw, index, - shader_model_index: material_index, + shader_model_index, .. } = self; Drawing { draw: draw.clone(), index, - shader_model_index: material_index, + shader_model_index, finish_on_drop: true, _ty: PhantomData, } @@ -242,13 +242,13 @@ where let Drawing { ref draw, index, - shader_model_index: material_index, + shader_model_index, .. } = self; Drawing { draw: draw.clone(), index, - shader_model_index: material_index, + shader_model_index, finish_on_drop: true, _ty: PhantomData, } diff --git a/bevy_nannou_draw/src/draw/indirect.rs b/bevy_nannou_draw/src/draw/indirect.rs index eaa987a55..aaeb6c939 100644 --- a/bevy_nannou_draw/src/draw/indirect.rs +++ b/bevy_nannou_draw/src/draw/indirect.rs @@ -160,10 +160,10 @@ impl RenderCommand

let Some(asset_id) = instances.get(&item.entity()) else { return RenderCommandResult::Skip; }; - let Some(material) = models.get(*asset_id) else { + let Some(model) = models.get(*asset_id) else { return RenderCommandResult::Skip; }; - pass.set_bind_group(I, &material.bind_group, &[]); + pass.set_bind_group(I, &model.bind_group, &[]); RenderCommandResult::Success } } diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index bd68295ed..f8425f608 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -164,10 +164,10 @@ impl RenderCommand

let Some(asset_id) = instances.get(&item.entity()) else { return RenderCommandResult::Skip; }; - let Some(material) = models.get(*asset_id) else { + let Some(shader_model) = models.get(*asset_id) else { return RenderCommandResult::Skip; }; - pass.set_bind_group(I, &material.bind_group, &[]); + pass.set_bind_group(I, &shader_model.bind_group, &[]); RenderCommandResult::Success } } diff --git a/bevy_nannou_draw/src/draw/mod.rs b/bevy_nannou_draw/src/draw/mod.rs index 481b49905..2d42e63b2 100644 --- a/bevy_nannou_draw/src/draw/mod.rs +++ b/bevy_nannou_draw/src/draw/mod.rs @@ -65,12 +65,12 @@ where pub state: Arc>, /// The current context of this [Draw] instance. context: DrawContext, - /// The current material of this [Draw] instance. + /// The current type erased shader model of this [Draw] instance. shader_model: UntypedAssetId, /// The window to which this [Draw] instance is associated. pub(crate) window: Entity, - /// The type of material used by this [Draw] instance. - _material: PhantomData, + /// The type of shader model used by this [Draw] instance. + _shader_model: PhantomData, } /// A reference to a [Draw] instance that is either borrowed or owned. @@ -112,7 +112,7 @@ impl Default for DrawContext { } } -/// Commands generated by drawing that instruct how to create the meshes and materials that will be +/// Commands generated by drawing that instruct how to create the meshes and shader model that will be /// rendered. #[derive(Clone, Debug)] pub enum DrawCommand { @@ -138,7 +138,7 @@ pub enum DrawCommand { /// drawing stuff. In order to be friendlier to new users, we want to avoid requiring them to think /// about mutability and instead focus on creativity. Rust-lang nuances can come later. pub struct State { - /// The last material used to draw an image, used to detect changes and emit commands for them. + /// The last shader model used to draw an image, used to detect changes and emit commands for them. last_shader_model: Option, /// The last context used to draw an image, used to detect changes and emit commands for them. last_draw_context: Option, @@ -148,7 +148,7 @@ pub struct State { /// /// Keys are indices into the `draw_commands` Vec. drawing: HashMap, - /// A map of all type erased materials used by the draw. + /// A map of all type erased shader models used by the draw. pub(crate) shader_models: HashMap>, /// A list of indices of primitives that are being drawn via an alternate method and /// should not be drawn @@ -245,7 +245,7 @@ where context, shader_model: model_id, window, - _material: PhantomData, + _shader_model: PhantomData, } } @@ -458,27 +458,27 @@ where /// Produce a new [Draw] instance with the given context. fn context(&self, context: DrawContext) -> Draw { let state = self.state.clone(); - let material = self.shader_model.clone(); + let shader_model = self.shader_model.clone(); let window = self.window; Draw { state, context, - shader_model: material, + shader_model, window, - _material: PhantomData, + _shader_model: PhantomData, } } fn clone_shader_model(&self) -> SM { let mut state = self.state.write().unwrap(); - let material = state.shader_models.get_mut(&self.shader_model).unwrap(); - material + let shader_model = state.shader_models.get_mut(&self.shader_model).unwrap(); + shader_model .downcast_ref::() - .expect("Expected material to be of the correct type") + .expect("Expected shader model to be of the correct type") .clone() } - /// Produce a new [Draw] instance with a new material type. + /// Produce a new [Draw] instance with a new shader model type. pub fn shader_model(&self, model: SM2) -> Draw { let context = self.context.clone(); let DrawContext { transform, .. } = context; @@ -501,7 +501,7 @@ where context, shader_model: model_id, window, - _material: PhantomData, + _shader_model: PhantomData, } } @@ -545,8 +545,8 @@ where state.last_shader_model = Some(id.clone()); } - // Insert a material slot to be used if the drawing switches materials. - let material_index = state.draw_commands.len(); + // Insert a model slot to be used if the drawing switches models. + let shader_model_index = state.draw_commands.len(); state.draw_commands.push(None); // The primitive will be inserted in the next element. @@ -554,7 +554,7 @@ where let primitive: Primitive = primitive.into(); state.draw_commands.push(None); state.drawing.insert(index, primitive); - (index, material_index) + (index, shader_model_index) }; drawing::new(self, index, model_index) } @@ -694,7 +694,7 @@ impl Default for IntermediaryState { impl Default for State { fn default() -> Self { - let last_material = None; + let last_shader_model = None; let last_draw_context = None; let background_color = Default::default(); let draw_commands = Default::default(); @@ -702,7 +702,7 @@ impl Default for State { let intermediary_state = Arc::new(Default::default()); let theme = Default::default(); State { - last_shader_model: last_material, + last_shader_model, last_draw_context, draw_commands, drawing, diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index bc5b7756e..0c4edd0a1 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -61,13 +61,13 @@ pub const DEFAULT_NANNOU_SHADER_HANDLE: Handle = Handle::weak_from_u128( pub trait ShaderModel: Asset + AsBindGroup + Clone + Default + Sized + Send + Sync + 'static { - /// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader + /// Returns this shader model's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader /// will be used. fn vertex_shader() -> ShaderRef { ShaderRef::Default } - /// Returns this material's fragment shader. If [`ShaderRef::Default`] is returned, the default mesh fragment shader + /// Returns this shader model's fragment shader. If [`ShaderRef::Default`] is returned, the default mesh fragment shader /// will be used. #[allow(unused_variables)] fn fragment_shader() -> ShaderRef { @@ -137,7 +137,7 @@ where IndirectMaterialPlugin::::default(), InstancedMaterialPlugin::::default(), )) - .add_systems(PostUpdate, update_material::.after(update_draw_mesh)); + .add_systems(PostUpdate, update_shader_model::.after(update_draw_mesh)); app.sub_app_mut(RenderApp) .add_render_command::>() @@ -174,17 +174,17 @@ impl RenderAsset for PreparedShaderModel { type Param = (SRes, SRes>, SM::Param); fn prepare_asset( - material: Self::SourceAsset, - (render_device, pipeline, ref mut material_param): &mut SystemParamItem, + shader_model: Self::SourceAsset, + (render_device, pipeline, ref mut shader_model_param): &mut SystemParamItem, ) -> Result> { - match material.as_bind_group(&pipeline.shader_model_layout, render_device, material_param) { + match shader_model.as_bind_group(&pipeline.shader_model_layout, render_device, shader_model_param) { Ok(prepared) => Ok(PreparedShaderModel { bindings: prepared.bindings, bind_group: prepared.bind_group, key: prepared.data, }), Err(AsBindGroupError::RetryNextUpdate) => { - Err(PrepareAssetError::RetryNextUpdate(material)) + Err(PrepareAssetError::RetryNextUpdate(shader_model)) } Err(other) => Err(PrepareAssetError::AsBindGroupError(other)), } @@ -214,13 +214,13 @@ impl RenderCommand

let models = models.into_inner(); let model_instances = model_instances.into_inner(); - let Some(material_asset_id) = model_instances.get(&item.entity()) else { + let Some(shader_model_asset_id) = model_instances.get(&item.entity()) else { return RenderCommandResult::Skip; }; - let Some(material) = models.get(*material_asset_id) else { + let Some(model) = models.get(*shader_model_asset_id) else { return RenderCommandResult::Skip; }; - pass.set_bind_group(I, &material.bind_group, &[]); + pass.set_bind_group(I, &model.bind_group, &[]); RenderCommandResult::Success } } @@ -290,10 +290,10 @@ pub struct NannouMaterialKey { } impl From<&NannouShaderModel> for NannouMaterialKey { - fn from(material: &NannouShaderModel) -> Self { + fn from(shader_model: &NannouShaderModel) -> Self { Self { - polygon_mode: material.polygon_mode, - blend: material.blend, + polygon_mode: shader_model.polygon_mode, + blend: shader_model.blend, } } } @@ -535,11 +535,11 @@ fn setup_default_texture(mut commands: Commands, mut images: ResMut( +fn update_shader_model( draw_q: Query<&DrawHolder>, mut commands: Commands, - mut materials: ResMut>, - materials_q: Query<(Entity, &UntypedShaderModelId)>, + mut models: ResMut>, + models_q: Query<(Entity, &UntypedShaderModelId)>, ) where SM: ShaderModel, { @@ -548,12 +548,12 @@ fn update_material( state.shader_models.iter().for_each(|(id, model)| { if id.type_id() == TypeId::of::() { let model = model.downcast_ref::().unwrap(); - materials.insert(id.typed(), model.clone()); + models.insert(id.typed(), model.clone()); } }); } - for (entity, UntypedShaderModelId(id)) in materials_q.iter() { + for (entity, UntypedShaderModelId(id)) in models_q.iter() { if id.type_id() == TypeId::of::() { commands .entity(entity) @@ -592,7 +592,7 @@ fn update_draw_mesh( let mut fill_tessellator = FillTessellator::new(); let mut stroke_tessellator = StrokeTessellator::new(); - let mut last_mat = None; + let mut last_shader_model = None; let mut mesh = meshes.add(Mesh::init()); let mut curr_ctx: DrawContext = Default::default(); @@ -639,11 +639,11 @@ fn update_draw_mesh( let mut mesh = Mesh::init(); prim.render_primitive(ctxt, &mut mesh); let mesh = meshes.add(mesh); - let mat_id = last_mat.expect("No material set for instanced draw command"); + let model_id = last_shader_model.expect("No shader model set for instanced draw command"); commands.spawn(( InstancedMesh, InstanceRange(range), - UntypedShaderModelId(mat_id), + UntypedShaderModelId(model_id), mesh.clone(), Transform::default(), GlobalTransform::default(), @@ -675,11 +675,11 @@ fn update_draw_mesh( let mut mesh = Mesh::init(); prim.render_primitive(ctxt, &mut mesh); let mesh = meshes.add(mesh); - let mat_id = last_mat.expect("No material set for instanced draw command"); + let model_id = last_shader_model.expect("No shader model set for instanced draw command"); commands.spawn(( IndirectMesh, indirect_buffer, - UntypedShaderModelId(mat_id), + UntypedShaderModelId(model_id), mesh.clone(), Transform::default(), GlobalTransform::default(), @@ -696,8 +696,8 @@ fn update_draw_mesh( curr_ctx = ctx; } DrawCommand::ShaderModel(model_id) => { - // We switched materials, so start rendering into a new mesh - last_mat = Some(model_id.clone()); + // We switched models, so start rendering into a new mesh + last_shader_model = Some(model_id.clone()); mesh = meshes.add(Mesh::init()); commands.spawn(( UntypedShaderModelId(model_id), diff --git a/bevy_nannou_isf/src/asset.rs b/bevy_nannou_isf/src/asset.rs index 46ed9804c..16f495c72 100644 --- a/bevy_nannou_isf/src/asset.rs +++ b/bevy_nannou_isf/src/asset.rs @@ -95,7 +95,7 @@ impl AssetLoader for IsfLoader { } } -// 4. Plugin to register the asset loader and material +// 4. Plugin to register the asset loader pub struct IsfAssetPlugin; impl Plugin for IsfAssetPlugin { diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 06e638d6d..a21893b26 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -85,19 +85,13 @@ path = "draw/draw_blend.rs" name = "draw_capture" path = "draw/draw_capture.rs" [[example]] -name = "draw_custom_material" -path = "draw/draw_custom_material.rs" +name = "draw_custom_shader_model" +path = "draw/draw_custom_shader_model.rs" required-features = ["nannou/hot_reload"] [[example]] name = "draw_loop" path = "draw/draw_loop.rs" [[example]] -name = "draw_material" -path = "draw/draw_material.rs" -[[example]] -name = "draw_material_bloom" -path = "draw/draw_material_bloom.rs" -[[example]] name = "draw_mesh" path = "draw/draw_mesh.rs" [[example]] @@ -232,8 +226,8 @@ name = "simple_video" path = "video/simple_video.rs" required-features = ["video"] [[example]] -name = "video_material" -path = "video/video_material.rs" +name = "video_shader_model" +path = "video/video_shader_model.rs" required-features = ["video"] # WebGPU diff --git a/examples/assets/draw_custom_material.wgsl b/examples/assets/draw_custom_shader_model.wgsl similarity index 54% rename from examples/assets/draw_custom_material.wgsl rename to examples/assets/draw_custom_shader_model.wgsl index 95180787a..b96bda574 100644 --- a/examples/assets/draw_custom_material.wgsl +++ b/examples/assets/draw_custom_shader_model.wgsl @@ -1,14 +1,14 @@ #import bevy_pbr::forward_io::VertexOutput -struct CustomMaterial { +struct CustomShaderModel { color: vec4, }; -@group(2) @binding(0) var material: CustomMaterial; +@group(2) @binding(0) var shader_model: CustomShaderModel; @fragment fn fragment( mesh: VertexOutput, ) -> @location(0) vec4 { - return material.color; + return shader_model.color; } diff --git a/examples/assets/shaders/particle_mouse_material.wgsl b/examples/assets/shaders/particle_mouse_model.wgsl similarity index 100% rename from examples/assets/shaders/particle_mouse_material.wgsl rename to examples/assets/shaders/particle_mouse_model.wgsl diff --git a/examples/assets/shaders/particle_sdf_material.wgsl b/examples/assets/shaders/particle_sdf_model.wgsl similarity index 100% rename from examples/assets/shaders/particle_sdf_material.wgsl rename to examples/assets/shaders/particle_sdf_model.wgsl diff --git a/examples/assets/draw_video_material.wgsl b/examples/assets/video_model.wgsl similarity index 100% rename from examples/assets/draw_video_material.wgsl rename to examples/assets/video_model.wgsl diff --git a/examples/compute/particle_mouse.rs b/examples/compute/particle_mouse.rs index 9def1fa33..796a27879 100644 --- a/examples/compute/particle_mouse.rs +++ b/examples/compute/particle_mouse.rs @@ -27,7 +27,7 @@ struct Model { } impl Model { - fn material(&self) -> ShaderModel { + fn shader_model(&self) -> ShaderModel { ShaderModel { particles: self.particles.clone(), } @@ -81,8 +81,8 @@ impl Compute for ComputeModel { } #[shader_model( - fragment = "shaders/particle_mouse_material.wgsl", - vertex = "shaders/particle_mouse_material.wgsl" + fragment = "shaders/particle_mouse_model.wgsl", + vertex = "shaders/particle_mouse_model.wgsl" )] struct ShaderModel { #[storage(0, read_only, visibility(vertex))] @@ -165,7 +165,7 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(GRAY); - let draw = draw.shader_model(model.material()); + let draw = draw.shader_model(model.shader_model()); match model.shape { Shape::Circle => { draw_particles_circle(&draw); diff --git a/examples/compute/particle_sdf.rs b/examples/compute/particle_sdf.rs index 0d838231f..e69c1ce53 100644 --- a/examples/compute/particle_sdf.rs +++ b/examples/compute/particle_sdf.rs @@ -29,7 +29,7 @@ struct Model { } impl Model { - fn material(&self) -> ShaderModel { + fn shader_model(&self) -> ShaderModel { ShaderModel { particles: self.particles.clone(), } @@ -119,8 +119,8 @@ impl Compute for ComputeModel { // Our shader model that will be used to render the particles #[shader_model( - fragment = "shaders/particle_sdf_material.wgsl", - vertex = "shaders/particle_sdf_material.wgsl" + fragment = "shaders/particle_sdf_model.wgsl", + vertex = "shaders/particle_sdf_model.wgsl" )] struct ShaderModel { #[storage(0, read_only, visibility(vertex))] @@ -232,7 +232,7 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(GRAY); - let draw = draw.shader_model(model.material()); + let draw = draw.shader_model(model.shader_model()); draw.indirect() .primitive(draw.rect().w_h(2.0, 2.0)) .buffer(model.indirect_params.clone()); diff --git a/examples/draw/draw_custom_material.rs b/examples/draw/draw_custom_shader_model.rs similarity index 71% rename from examples/draw/draw_custom_material.rs rename to examples/draw/draw_custom_shader_model.rs index b0f1c6718..474f95cd2 100644 --- a/examples/draw/draw_custom_material.rs +++ b/examples/draw/draw_custom_shader_model.rs @@ -3,7 +3,7 @@ use nannou::prelude::*; fn main() { nannou::app(model) .simple_window(view) - // Register our custom material to make it available for use in our drawing + // Register our custom shader model to make it available for use in our drawing .shader_model::() .run() } @@ -11,7 +11,7 @@ fn main() { struct Model {} // This struct defines the data that will be passed to your shader -#[shader_model(fragment = "draw_custom_material.wgsl")] +#[shader_model(fragment = "draw_custom_shader_model.wgsl")] struct ShaderModel { #[uniform(0)] color: LinearRgba, @@ -25,12 +25,12 @@ fn view(app: &App, model: &Model, window: Entity) { // Begin drawing let draw = app .draw() - // Initialize our draw instance with our custom material + // Initialize our draw instance with our custom shader model .shader_model(ShaderModel { color: RED.into() }); draw.ellipse().x(-200.0); - // We can also map the material manually + // We can also map the shader model manually draw.ellipse() .map_shader_model(|mut mat| { mat.color = BLUE.into(); diff --git a/examples/draw/draw_material.rs b/examples/draw/draw_material.rs deleted file mode 100644 index 317a841ce..000000000 --- a/examples/draw/draw_material.rs +++ /dev/null @@ -1,66 +0,0 @@ -use nannou::prelude::light_consts::lux::DIRECT_SUNLIGHT; -use nannou::prelude::primitive::polygon::PolygonOptions; -use nannou::prelude::*; - -fn main() { - nannou::app(model).update(update).run(); -} - -struct Model { - window: Entity, - light: Entity, -} - -fn model(app: &App) -> Model { - let light = app.new_light().color(WHITE).illuminance(1000.0).build(); - let window = app - .new_window() - .size_pixels(1024, 512) - .light(light) - .view(view) - .build(); - - Model { light, window } -} - -fn update(app: &App, model: &mut Model) { - let light = app.light(model.light); - let window_rect = app.window_rect(); - let window_center = window_rect.xy(); - let mouse_x = app.mouse().x; - let mouse_y = app.mouse().y; - let norm_mouse_x = (mouse_x / window_rect.w()) + 0.5; - let norm_mouse_y = (mouse_y / window_rect.h()) + 0.5; - - // Calculate the light's position based on time t - let time = app.time(); - let radius = window_rect.w().min(window_rect.h()) * 0.4; - let light_x = window_center.x + radius * (time * 2.0 * PI).cos(); - let light_y = window_center.y + radius * (time * 2.0 * PI).sin(); - - let light_color = Color::hsl((1.0 - norm_mouse_x) * 360.0, 1.0, 0.5); - light - .color(light_color) - .illuminance(norm_mouse_y * DIRECT_SUNLIGHT) - .x_y_z(light_x, light_y, 1000.0) - .look_at(Vec2::ZERO); -} - -fn view(app: &App, model: &Model) { - // Begin drawing - let draw = app.draw(); - - for y in -2..=2 { - for x in -5..=5 { - let x01 = (x + 5) as f32 / 10.0; - let y01 = (y + 2) as f32 / 2.0; - - draw.ellipse() - .w_h(50.0, 50.0) - .x_y_z(x as f32 * 100.0, y as f32 * 100.0, 10.0) - .roughness(x01) - .metallic(y01) - .color(Color::gray(0.5)); - } - } -} diff --git a/examples/draw/draw_material_bloom.rs b/examples/draw/draw_material_bloom.rs deleted file mode 100644 index a0e2def2b..000000000 --- a/examples/draw/draw_material_bloom.rs +++ /dev/null @@ -1,58 +0,0 @@ -use nannou::prelude::*; - -fn main() { - nannou::app(model).update(update).run(); -} - -struct Model { - window: Entity, - camera: Entity, -} - -fn model(app: &App) -> Model { - let camera = app - .new_camera() - // HDR is required for bloom to work. - .hdr(true) - // Pick a default bloom settings. This also can be configured manually. - .bloom_settings(BloomSettings::OLD_SCHOOL) - .build(); - - let window = app - .new_window() - .camera(camera) - .size_pixels(1024, 1024) - .view(view) - .build(); - - Model { camera, window } -} - -fn update(app: &App, model: &mut Model) { - let camera = app.camera(model.camera); - let window_rect = app.window_rect(); - let norm_mouse_y = (app.mouse().y / window_rect.w()) + 0.5; - - camera.bloom_intensity(norm_mouse_y.clamp(0.0, 0.8)); -} - -fn view(app: &App, model: &Model) { - // Begin drawing - let draw = app.draw(); - let window_rect = app.window_rect(); - let norm_mouse_x = (app.mouse().x / window_rect.w()) + 0.5; - - // Use the normalized mouse coordinate to create an initial color. - let color_hsl = Color::hsl((1.0 - norm_mouse_x) * 360.0, 1.0, 0.5); - - // Convert the color to linear RGBA and multiply (for emissives, values outside of 1.0 are used). - let mut color_linear_rgb: LinearRgba = color_hsl.into(); - color_linear_rgb = color_linear_rgb * 5.0; - - let t = app.time(); - - draw.tri() - .width(100.0) - .emissive(color_linear_rgb) - .color(WHITE); -} diff --git a/examples/video/video_material.rs b/examples/video/video_shader_model.rs similarity index 84% rename from examples/video/video_material.rs rename to examples/video/video_shader_model.rs index 0a3f2ca15..87afe68a2 100644 --- a/examples/video/video_material.rs +++ b/examples/video/video_shader_model.rs @@ -3,7 +3,7 @@ use nannou::prelude::*; fn main() { nannou::app(model) - // Register our custom material to make it available for use in our drawing + // Register our custom shader model to make it available for use in our drawing .shader_model::() .run(); } @@ -16,7 +16,7 @@ struct Model { } // This struct defines the data that will be passed to your shader -#[shader_model(fragment = "draw_video_material.wgsl")] +#[shader_model(fragment = "video_model.wgsl")] struct VideoShaderModel { #[texture(0)] #[sampler(1)] @@ -51,7 +51,7 @@ fn view(app: &App, model: &Model) { let draw = app .draw() - // Initialize our draw instance with our custom material + // Initialize our draw instance with our custom shader model .shader_model(VideoShaderModel { texture: video.texture.clone(), }); From bbbb640fdf3c28c073d19775817d34eab639b93f Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Thu, 26 Sep 2024 22:38:22 -0700 Subject: [PATCH 5/9] Material -> ShaderModel --- bevy_nannou_derive/src/lib.rs | 10 -------- .../tests/shader_model_tests.rs | 24 +++++++++---------- bevy_nannou_draw/src/draw/background.rs | 2 +- bevy_nannou_draw/src/draw/drawing.rs | 1 - bevy_nannou_draw/src/draw/indirect.rs | 14 +++++------ bevy_nannou_draw/src/draw/instanced.rs | 15 ++++++------ bevy_nannou_draw/src/render.rs | 21 ++++++++-------- nannou/src/app.rs | 8 ------- 8 files changed, 37 insertions(+), 58 deletions(-) diff --git a/bevy_nannou_derive/src/lib.rs b/bevy_nannou_derive/src/lib.rs index 93b8a8546..8fbe7062a 100644 --- a/bevy_nannou_derive/src/lib.rs +++ b/bevy_nannou_derive/src/lib.rs @@ -38,16 +38,6 @@ pub fn shader_model(attr: TokenStream, item: TokenStream) -> TokenStream { #fragment_shader_impl } } - - impl #impl_generics ::nannou::prelude::Material for #name #ty_generics #where_clause { - fn vertex_shader() -> ::nannou::prelude::ShaderRef { - ::vertex_shader() - } - - fn fragment_shader() -> ::nannou::prelude::ShaderRef { - ::fragment_shader() - } - } }; TokenStream::from(expanded) diff --git a/bevy_nannou_derive/tests/shader_model_tests.rs b/bevy_nannou_derive/tests/shader_model_tests.rs index 3897e626f..79e0a44d0 100644 --- a/bevy_nannou_derive/tests/shader_model_tests.rs +++ b/bevy_nannou_derive/tests/shader_model_tests.rs @@ -3,58 +3,58 @@ use bevy_nannou_derive::shader_model; use bevy_nannou_draw::render::ShaderModel; #[shader_model] -struct TestMaterial {} +struct TestShaderModel {} #[test] fn test_default_shaders() { - assert!(matches!(TestMaterial::vertex_shader(), ShaderRef::Default)); + assert!(matches!(TestShaderModel::vertex_shader(), ShaderRef::Default)); assert!(matches!( - TestMaterial::fragment_shader(), + TestShaderModel::fragment_shader(), ShaderRef::Default )); } #[shader_model(vertex = "custom_vertex.wgsl")] -struct TestVertexMaterial {} +struct TestVertexShaderModel {} #[test] fn test_custom_vertex_shader() { assert!(matches!( - TestVertexMaterial::vertex_shader(), + TestVertexShaderModel::vertex_shader(), ShaderRef::Path(_) )); assert!(matches!( - TestVertexMaterial::fragment_shader(), + TestVertexShaderModel::fragment_shader(), ShaderRef::Default )); } #[shader_model(fragment = "custom_fragment.wgsl")] -struct TestFragmentMaterial {} +struct TestFragmentShaderModel {} #[test] fn test_custom_fragment_shader() { assert!(matches!( - TestFragmentMaterial::vertex_shader(), + TestFragmentShaderModel::vertex_shader(), ShaderRef::Default )); assert!(matches!( - TestFragmentMaterial::fragment_shader(), + TestFragmentShaderModel::fragment_shader(), ShaderRef::Path(_) )); } #[shader_model(vertex = "custom_vertex.wgsl", fragment = "custom_fragment.wgsl")] -struct TestBothMaterial {} +struct TestBothShaderModel {} #[test] fn test_both_custom_shaders() { assert!(matches!( - TestBothMaterial::vertex_shader(), + TestBothShaderModel::vertex_shader(), ShaderRef::Path(_) )); assert!(matches!( - TestBothMaterial::fragment_shader(), + TestBothShaderModel::fragment_shader(), ShaderRef::Path(_) )); } diff --git a/bevy_nannou_draw/src/draw/background.rs b/bevy_nannou_draw/src/draw/background.rs index c32d0c8a2..812d3f9dd 100644 --- a/bevy_nannou_draw/src/draw/background.rs +++ b/bevy_nannou_draw/src/draw/background.rs @@ -1,4 +1,4 @@ -use bevy::prelude::{Color, Material}; +use bevy::prelude::{Color}; use crate::draw::{Draw, DrawCommand}; use crate::render::ShaderModel; diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index 7ccb2ba48..810ada86b 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -2,7 +2,6 @@ use std::any::TypeId; use std::marker::PhantomData; use bevy::asset::UntypedAssetId; -use bevy::pbr::{ExtendedMaterial, MaterialExtension}; use bevy::prelude::*; use lyon::path::PathEvent; use lyon::tessellation::{FillOptions, LineCap, LineJoin, StrokeOptions}; diff --git a/bevy_nannou_draw/src/draw/indirect.rs b/bevy_nannou_draw/src/draw/indirect.rs index aaeb6c939..2a5e38e14 100644 --- a/bevy_nannou_draw/src/draw/indirect.rs +++ b/bevy_nannou_draw/src/draw/indirect.rs @@ -98,18 +98,18 @@ where #[derive(Component, ExtractComponent, Clone)] pub struct IndirectMesh; -pub struct IndirectMaterialPlugin(PhantomData); +pub struct IndirectShaderModelPlugin(PhantomData); -impl Default for IndirectMaterialPlugin +impl Default for IndirectShaderModelPlugin where SM: Default, { fn default() -> Self { - IndirectMaterialPlugin(PhantomData) + IndirectShaderModelPlugin(PhantomData) } } -impl Plugin for IndirectMaterialPlugin +impl Plugin for IndirectShaderModelPlugin where SM: ShaderModel, SM::Data: PartialEq + Eq + Hash + Clone, @@ -117,17 +117,17 @@ where fn build(&self, app: &mut App) { app .sub_app_mut(RenderApp) - .add_render_command::>() + .add_render_command::>() .add_systems( Render, - queue_shader_model::, DrawIndirectMaterial> + queue_shader_model::, DrawIndirectShaderModel> .after(prepare_assets::>) .in_set(RenderSet::QueueMeshes), ); } } -type DrawIndirectMaterial = ( +type DrawIndirectShaderModel = ( SetItemPipeline, SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index f8425f608..216da60f3 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -8,7 +8,6 @@ use bevy::{ core_pipeline::core_3d::Transparent3d, ecs::system::{lifetimeless::*, SystemParamItem}, pbr::{ - MaterialPipeline, MaterialPipelineKey, MeshPipeline, MeshPipelineKey, PreparedMaterial, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, }, prelude::*, @@ -103,35 +102,35 @@ pub struct InstancedMesh; #[derive(Component, ExtractComponent, Clone)] pub struct InstanceRange(pub Range); -pub struct InstancedMaterialPlugin(PhantomData); +pub struct InstancedShaderModelPlugin(PhantomData); -impl Default for InstancedMaterialPlugin +impl Default for InstancedShaderModelPlugin where SM: Default, { fn default() -> Self { - InstancedMaterialPlugin(PhantomData) + InstancedShaderModelPlugin(PhantomData) } } -impl Plugin for InstancedMaterialPlugin +impl Plugin for InstancedShaderModelPlugin where SM: ShaderModel, SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { app.sub_app_mut(RenderApp) - .add_render_command::>() + .add_render_command::>() .add_systems( Render, - queue_shader_model::, DrawInstancedMaterial> + queue_shader_model::, DrawInstancedShaderModel> .after(prepare_assets::>) .in_set(RenderSet::QueueMeshes), ); } } -type DrawInstancedMaterial = ( +type DrawInstancedShaderModel = ( SetItemPipeline, SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index 0c4edd0a1..c0170dd18 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -1,7 +1,7 @@ use crate::{ draw::{ - indirect::{IndirectMaterialPlugin, IndirectMesh}, - instanced::{InstanceRange, InstancedMaterialPlugin, InstancedMesh}, + indirect::{IndirectShaderModelPlugin, IndirectMesh}, + instanced::{InstanceRange, InstancedShaderModelPlugin, InstancedMesh}, mesh::MeshExt, render::{RenderContext, RenderPrimitive}, DrawCommand, DrawContext, @@ -16,10 +16,9 @@ use bevy::{ system::{lifetimeless::SRes, SystemParamItem}, }, pbr::{ - DefaultOpaqueRendererMethod, DrawMesh, ExtendedMaterial, MaterialBindGroupId, - MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, MaterialPipeline, - MaterialProperties, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, - RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, StandardMaterial, + DefaultOpaqueRendererMethod, DrawMesh, + MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, + RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, }, prelude::{TypePath, *}, render::{ @@ -134,8 +133,8 @@ where .add_plugins(( ExtractInstancesPlugin::>::extract_visible(), RenderAssetPlugin::>::default(), - IndirectMaterialPlugin::::default(), - InstancedMaterialPlugin::::default(), + IndirectShaderModelPlugin::::default(), + InstancedShaderModelPlugin::::default(), )) .add_systems(PostUpdate, update_shader_model::.after(update_draw_mesh)); @@ -249,7 +248,7 @@ bitflags::bitflags! { } #[derive(Asset, AsBindGroup, TypePath, Debug, Clone, Default)] -#[bind_group_data(NannouMaterialKey)] +#[bind_group_data(NannouBindGroupData)] #[uniform(0, NannouShaderModelUniform)] pub struct NannouShaderModel { pub color: Color, @@ -284,12 +283,12 @@ impl AsBindGroupShaderType for NannouShaderModel { } #[derive(Eq, PartialEq, Hash, Clone)] -pub struct NannouMaterialKey { +pub struct NannouBindGroupData { polygon_mode: PolygonMode, blend: Option, } -impl From<&NannouShaderModel> for NannouMaterialKey { +impl From<&NannouShaderModel> for NannouBindGroupData { fn from(shader_model: &NannouShaderModel) -> Self { Self { polygon_mode: shader_model.polygon_mode, diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 4ed5794e4..9233d9b06 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -362,14 +362,6 @@ where self } - /// Load a fragment shader asset from the given path for use with the nannou `Draw` API. - #[cfg(feature = "nightly")] - pub fn init_fragment_shader(mut self) -> Self { - self.app - .add_plugins(NannouShaderModelPlugin::>::default()); - self - } - pub fn compute(mut self, compute_fn: ComputeUpdateFn) -> Self { let render_app = self.app.sub_app_mut(bevy::render::RenderApp); render_app.insert_resource(ComputeShaderHandle(CM::shader())); From a34a603850aec4c516f36558a12123e2c220213c Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Thu, 26 Sep 2024 22:50:38 -0700 Subject: [PATCH 6/9] Fmt. --- .../tests/shader_model_tests.rs | 5 +++- bevy_nannou_draw/src/draw/background.rs | 2 +- bevy_nannou_draw/src/draw/drawing.rs | 4 ++- bevy_nannou_draw/src/draw/indirect.rs | 3 +-- bevy_nannou_draw/src/draw/instanced.rs | 4 +-- bevy_nannou_draw/src/render.rs | 26 ++++++++++++------- bevy_nannou_isf/src/render.rs | 2 +- examples/draw/draw_texture.rs | 3 +-- nannou/src/app.rs | 7 +++-- 9 files changed, 32 insertions(+), 24 deletions(-) diff --git a/bevy_nannou_derive/tests/shader_model_tests.rs b/bevy_nannou_derive/tests/shader_model_tests.rs index 79e0a44d0..3039a953b 100644 --- a/bevy_nannou_derive/tests/shader_model_tests.rs +++ b/bevy_nannou_derive/tests/shader_model_tests.rs @@ -7,7 +7,10 @@ struct TestShaderModel {} #[test] fn test_default_shaders() { - assert!(matches!(TestShaderModel::vertex_shader(), ShaderRef::Default)); + assert!(matches!( + TestShaderModel::vertex_shader(), + ShaderRef::Default + )); assert!(matches!( TestShaderModel::fragment_shader(), ShaderRef::Default diff --git a/bevy_nannou_draw/src/draw/background.rs b/bevy_nannou_draw/src/draw/background.rs index 812d3f9dd..8c6db9e42 100644 --- a/bevy_nannou_draw/src/draw/background.rs +++ b/bevy_nannou_draw/src/draw/background.rs @@ -1,4 +1,4 @@ -use bevy::prelude::{Color}; +use bevy::prelude::Color; use crate::draw::{Draw, DrawCommand}; use crate::render::ShaderModel; diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index 810ada86b..b8f89f252 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -167,7 +167,9 @@ where let shader_model = map(shader_model.clone()); let mut state = state.write().unwrap(); - state.shader_models.insert(new_id.clone(), Box::new(shader_model)); + state + .shader_models + .insert(new_id.clone(), Box::new(shader_model)); // Mark the last shader model as the new model so that further drawings use the same model // as the parent draw ref. state.last_shader_model = Some(new_id.clone()); diff --git a/bevy_nannou_draw/src/draw/indirect.rs b/bevy_nannou_draw/src/draw/indirect.rs index 2a5e38e14..6de57cde0 100644 --- a/bevy_nannou_draw/src/draw/indirect.rs +++ b/bevy_nannou_draw/src/draw/indirect.rs @@ -115,8 +115,7 @@ where SM::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app - .sub_app_mut(RenderApp) + app.sub_app_mut(RenderApp) .add_render_command::>() .add_systems( Render, diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index 216da60f3..b13cd1389 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -7,9 +7,7 @@ use crate::{ use bevy::{ core_pipeline::core_3d::Transparent3d, ecs::system::{lifetimeless::*, SystemParamItem}, - pbr::{ - RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, - }, + pbr::{RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup}, prelude::*, render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index c0170dd18..00e8b3bfc 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -1,13 +1,14 @@ use crate::{ draw::{ - indirect::{IndirectShaderModelPlugin, IndirectMesh}, - instanced::{InstanceRange, InstancedShaderModelPlugin, InstancedMesh}, + indirect::{IndirectMesh, IndirectShaderModelPlugin}, + instanced::{InstanceRange, InstancedMesh, InstancedShaderModelPlugin}, mesh::MeshExt, render::{RenderContext, RenderPrimitive}, DrawCommand, DrawContext, }, DrawHolder, }; +use bevy::render::storage::ShaderStorageBuffer; use bevy::{ asset::{load_internal_asset, Asset, UntypedAssetId}, core_pipeline::core_3d::Transparent3d, @@ -16,8 +17,7 @@ use bevy::{ system::{lifetimeless::SRes, SystemParamItem}, }, pbr::{ - DefaultOpaqueRendererMethod, DrawMesh, - MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, + DefaultOpaqueRendererMethod, DrawMesh, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, }, prelude::{TypePath, *}, @@ -53,7 +53,6 @@ use bevy::{ }; use lyon::lyon_tessellation::{FillTessellator, StrokeTessellator}; use std::{any::TypeId, hash::Hash, marker::PhantomData}; -use bevy::render::storage::ShaderStorageBuffer; pub const DEFAULT_NANNOU_SHADER_HANDLE: Handle = Handle::weak_from_u128(3086880141013591); @@ -136,7 +135,10 @@ where IndirectShaderModelPlugin::::default(), InstancedShaderModelPlugin::::default(), )) - .add_systems(PostUpdate, update_shader_model::.after(update_draw_mesh)); + .add_systems( + PostUpdate, + update_shader_model::.after(update_draw_mesh), + ); app.sub_app_mut(RenderApp) .add_render_command::>() @@ -176,7 +178,11 @@ impl RenderAsset for PreparedShaderModel { shader_model: Self::SourceAsset, (render_device, pipeline, ref mut shader_model_param): &mut SystemParamItem, ) -> Result> { - match shader_model.as_bind_group(&pipeline.shader_model_layout, render_device, shader_model_param) { + match shader_model.as_bind_group( + &pipeline.shader_model_layout, + render_device, + shader_model_param, + ) { Ok(prepared) => Ok(PreparedShaderModel { bindings: prepared.bindings, bind_group: prepared.bind_group, @@ -638,7 +644,8 @@ fn update_draw_mesh( let mut mesh = Mesh::init(); prim.render_primitive(ctxt, &mut mesh); let mesh = meshes.add(mesh); - let model_id = last_shader_model.expect("No shader model set for instanced draw command"); + let model_id = + last_shader_model.expect("No shader model set for instanced draw command"); commands.spawn(( InstancedMesh, InstanceRange(range), @@ -674,7 +681,8 @@ fn update_draw_mesh( let mut mesh = Mesh::init(); prim.render_primitive(ctxt, &mut mesh); let mesh = meshes.add(mesh); - let model_id = last_shader_model.expect("No shader model set for instanced draw command"); + let model_id = + last_shader_model.expect("No shader model set for instanced draw command"); commands.spawn(( IndirectMesh, indirect_buffer, diff --git a/bevy_nannou_isf/src/render.rs b/bevy_nannou_isf/src/render.rs index f00ac95ef..8c091cc2b 100644 --- a/bevy_nannou_isf/src/render.rs +++ b/bevy_nannou_isf/src/render.rs @@ -1,6 +1,6 @@ use bevy::asset::embedded_asset; use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; -use bevy::core_pipeline::core_3d::{CORE_3D_DEPTH_FORMAT}; +use bevy::core_pipeline::core_3d::CORE_3D_DEPTH_FORMAT; use bevy::core_pipeline::fullscreen_vertex_shader::{ fullscreen_shader_vertex_state, FULLSCREEN_SHADER_HANDLE, }; diff --git a/examples/draw/draw_texture.rs b/examples/draw/draw_texture.rs index 8d1822fac..ba39ea5ff 100644 --- a/examples/draw/draw_texture.rs +++ b/examples/draw/draw_texture.rs @@ -25,6 +25,5 @@ fn view(app: &App, model: &Model) { let draw = app.draw(); draw.background().color(BLACK); let win = app.window_rect(); - draw.rect().x_y(win.x(), win.y()) - .texture(&model.texture); + draw.rect().x_y(win.x(), win.y()).texture(&model.texture); } diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 9233d9b06..6a38eefee 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -40,7 +40,7 @@ use bevy_inspector_egui::DefaultInspectorConfigPlugin; use crate::frame::{Frame, FramePlugin}; use crate::prelude::bevy_ecs::system::SystemState; use crate::prelude::bevy_reflect::DynamicTyped; -use crate::prelude::render::{NannouShaderModelPlugin, NannouMesh, ShaderModel}; +use crate::prelude::render::{NannouMesh, NannouShaderModelPlugin, ShaderModel}; use crate::render::{ compute::{Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState}, NannouRenderNode, RenderApp, RenderPlugin, @@ -356,9 +356,8 @@ where SM: ShaderModel, SM::Data: PartialEq + Eq + Hash + Clone, { - self.app.add_plugins(( - NannouShaderModelPlugin::::default(), - )); + self.app + .add_plugins((NannouShaderModelPlugin::::default(),)); self } From 8d66064dd8cd2fa150d561c7e36d7c6fbe59d01f Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Sun, 29 Sep 2024 15:03:50 -0700 Subject: [PATCH 7/9] Rename NannouMesh -> NannouTransient. --- bevy_nannou_draw/src/render.rs | 10 +++++----- nannou/src/app.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index 00e8b3bfc..b133f1c88 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -97,7 +97,7 @@ impl Plugin for NannouRenderPlugin { app.add_systems(Startup, setup_default_texture) .add_plugins(( ExtractComponentPlugin::::default(), - ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), ExtractComponentPlugin::::default(), @@ -656,7 +656,7 @@ fn update_draw_mesh( Visibility::default(), InheritedVisibility::default(), ViewVisibility::default(), - NannouMesh, + NannouTransient, NoFrustumCulling, DrawIndex(idx), window_layers.clone(), @@ -693,7 +693,7 @@ fn update_draw_mesh( Visibility::default(), InheritedVisibility::default(), ViewVisibility::default(), - NannouMesh, + NannouTransient, NoFrustumCulling, DrawIndex(idx), window_layers.clone(), @@ -715,7 +715,7 @@ fn update_draw_mesh( InheritedVisibility::default(), ViewVisibility::default(), ShaderModelMesh, - NannouMesh, + NannouTransient, NoFrustumCulling, DrawIndex(idx), window_layers.clone(), @@ -744,7 +744,7 @@ fn check_and_despawn_empty_mesh(meshes: &mut ResMut>, mesh: &mut Ha pub struct DrawIndex(pub usize); #[derive(Component, ExtractComponent, Clone)] -pub struct NannouMesh; +pub struct NannouTransient; #[derive(Component, ExtractComponent, Clone)] pub struct ShaderModelMesh; diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 6a38eefee..95a14716f 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -40,7 +40,7 @@ use bevy_inspector_egui::DefaultInspectorConfigPlugin; use crate::frame::{Frame, FramePlugin}; use crate::prelude::bevy_ecs::system::SystemState; use crate::prelude::bevy_reflect::DynamicTyped; -use crate::prelude::render::{NannouMesh, NannouShaderModelPlugin, ShaderModel}; +use crate::prelude::render::{NannouTransient, NannouShaderModelPlugin, ShaderModel}; use crate::render::{ compute::{Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState}, NannouRenderNode, RenderApp, RenderPlugin, @@ -1075,7 +1075,7 @@ where fn first( mut commands: Commands, bg_color_q: Query>, - meshes_q: Query>, + meshes_q: Query>, ) where M: 'static + Send + Sync, { From 03202bc9a180e9cc439d01c0467ae41163e877c2 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Sun, 29 Sep 2024 15:05:48 -0700 Subject: [PATCH 8/9] Ci. --- nannou/src/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 95a14716f..f878acd3a 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -40,7 +40,7 @@ use bevy_inspector_egui::DefaultInspectorConfigPlugin; use crate::frame::{Frame, FramePlugin}; use crate::prelude::bevy_ecs::system::SystemState; use crate::prelude::bevy_reflect::DynamicTyped; -use crate::prelude::render::{NannouTransient, NannouShaderModelPlugin, ShaderModel}; +use crate::prelude::render::{NannouShaderModelPlugin, NannouTransient, ShaderModel}; use crate::render::{ compute::{Compute, ComputeModel, ComputePlugin, ComputeShaderHandle, ComputeState}, NannouRenderNode, RenderApp, RenderPlugin, From eba013d068c964de4d15b7b0ad5a32823c41a0ed Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Sun, 29 Sep 2024 15:40:16 -0700 Subject: [PATCH 9/9] Remove check... breaks things. --- bevy_nannou_draw/src/render.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index b133f1c88..aacbb3bf1 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -726,17 +726,6 @@ fn update_draw_mesh( } } } - - check_and_despawn_empty_mesh(&mut meshes, &mut mesh); - } -} - -fn check_and_despawn_empty_mesh(meshes: &mut ResMut>, mesh: &mut Handle) { - if let Some(m) = meshes.get(&*mesh) { - // Remove the mesh if it has no vertices, which can happen if the user draws nothing - if !m.count_vertices() > 0 { - meshes.remove(&*mesh); - } } }