From 521b3a5fa9a66a379517aad3901e9c04a93feb20 Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Sun, 9 Jun 2024 22:46:14 -0700 Subject: [PATCH] Add custom material example. --- bevy_nannou_draw/src/draw/drawing.rs | 24 +++++---- bevy_nannou_draw/src/draw/mod.rs | 8 +-- .../src/draw/properties/material.rs | 8 --- bevy_nannou_draw/src/draw/properties/mod.rs | 1 - examples/Cargo.toml | 4 ++ examples/assets/draw_custom_material.wgsl | 14 ++++++ examples/draw/draw_custom_material.rs | 50 +++++++++++++++++++ examples/draw/draw_fragment_shader.rs | 4 +- nannou/src/app.rs | 10 ++++ nannou/src/prelude.rs | 2 + 10 files changed, 98 insertions(+), 27 deletions(-) delete mode 100644 bevy_nannou_draw/src/draw/properties/material.rs create mode 100644 examples/assets/draw_custom_material.wgsl create mode 100644 examples/draw/draw_custom_material.rs diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index 015ad6363..4c0e2ec71 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -9,7 +9,6 @@ use lyon::tessellation::{FillOptions, LineCap, LineJoin, StrokeOptions}; use uuid::Uuid; use crate::draw::primitive::Primitive; -use crate::draw::properties::material::SetMaterial; use crate::draw::properties::{ SetColor, SetDimensions, SetFill, SetOrientation, SetPosition, SetStroke, }; @@ -183,7 +182,7 @@ where // Map the the parent's material to a new material type, taking ownership over the // draw instance clone. - fn map_material(mut self, map: F) -> Drawing<'a, T, M> + pub fn map_material(mut self, map: F) -> Drawing<'a, T, M> where F: FnOnce(M) -> M, { @@ -198,6 +197,7 @@ where .downcast_ref::() .unwrap() .clone(); + let new_id = UntypedAssetId::Uuid { type_id: TypeId::of::(), uuid: Uuid::new_v4(), @@ -837,7 +837,7 @@ where impl<'a, T, M> Drawing<'a, T, M> where - T: SetMaterial + Into + Clone, + T: Into + Clone, M: Material + Default, Primitive: Into>, { @@ -849,13 +849,17 @@ where M: MaterialExtension + Default, { pub fn roughness(mut self, roughness: f32) -> Self { - // self.draw.material.base.perceptual_roughness = roughness; - self + self.map_material(|mut material| { + material.base.perceptual_roughness = roughness; + material + }) } pub fn metallic(mut self, metallic: f32) -> Self { - // self.draw.material.base.metallic = metallic; - self + self.map_material(|mut material| { + material.base.metallic = metallic; + material + }) } pub fn base_color(mut self, color: Color) -> Self { @@ -866,7 +870,9 @@ where } pub fn emissive(mut self, color: Color) -> Self { - // self.draw.material.base.emissive = color; - self + self.map_material(|mut material| { + material.base.emissive = color.linear(); + material + }) } } diff --git a/bevy_nannou_draw/src/draw/mod.rs b/bevy_nannou_draw/src/draw/mod.rs index 1c7879746..bb5caa81e 100644 --- a/bevy_nannou_draw/src/draw/mod.rs +++ b/bevy_nannou_draw/src/draw/mod.rs @@ -490,6 +490,7 @@ where type_id: TypeId::of::(), uuid: Uuid::new_v4(), }; + state .write() .unwrap() @@ -644,13 +645,6 @@ where /// Drain any remaining `drawing`s and convert them to draw commands. pub fn finish_remaining_drawings(&self) { let mut state = self.state.write().unwrap(); - let id = &self.material; - if state.last_material.as_ref() != Some(id) { - state - .draw_commands - .push(Some(DrawCommand::Material(id.clone()))); - state.last_material = Some(id.clone()); - } state.finish_remaining_drawings() } } diff --git a/bevy_nannou_draw/src/draw/properties/material.rs b/bevy_nannou_draw/src/draw/properties/material.rs deleted file mode 100644 index 3d371b63f..000000000 --- a/bevy_nannou_draw/src/draw/properties/material.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bevy::prelude::Material; - -pub trait SetMaterial: Sized -where - M: Material + Default, -{ - fn material_mut(&mut self) -> &mut M; -} diff --git a/bevy_nannou_draw/src/draw/properties/mod.rs b/bevy_nannou_draw/src/draw/properties/mod.rs index 39681dd1e..19ae76920 100644 --- a/bevy_nannou_draw/src/draw/properties/mod.rs +++ b/bevy_nannou_draw/src/draw/properties/mod.rs @@ -15,6 +15,5 @@ pub use self::stroke::SetStroke; pub mod color; pub mod fill; -pub mod material; pub mod spatial; pub mod stroke; diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 9ecd882a5..e5076dcf8 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -76,6 +76,10 @@ path = "draw/draw_blend.rs" name = "draw_capture" path = "draw/draw_capture.rs" [[example]] +name = "draw_custom_material" +path = "draw/draw_custom_material.rs" +required-features = ["nannou/hot_reload"] +[[example]] name = "draw_fragment_shader" path = "draw/draw_fragment_shader.rs" required-features = ["nannou/nightly", "nannou/hot_reload"] diff --git a/examples/assets/draw_custom_material.wgsl b/examples/assets/draw_custom_material.wgsl new file mode 100644 index 000000000..95180787a --- /dev/null +++ b/examples/assets/draw_custom_material.wgsl @@ -0,0 +1,14 @@ +#import bevy_pbr::forward_io::VertexOutput + +struct CustomMaterial { + color: vec4, +}; + +@group(2) @binding(0) var material: CustomMaterial; + +@fragment +fn fragment( + mesh: VertexOutput, +) -> @location(0) vec4 { + return material.color; +} diff --git a/examples/draw/draw_custom_material.rs b/examples/draw/draw_custom_material.rs new file mode 100644 index 000000000..a97f3df8d --- /dev/null +++ b/examples/draw/draw_custom_material.rs @@ -0,0 +1,50 @@ +use nannou::prelude::*; +use nannou::prelude::primitive::Primitive; + +fn main() { + nannou::app(model) + .simple_window(view) + // Register our custom material to make it available for use in our drawing + .init_custom_material::() + .run() +} + +struct Model {} + +// This struct defines the data that will be passed to your shader +#[derive(Asset, TypePath, AsBindGroup, Debug, Clone, Default)] +struct CustomMaterial { + #[uniform(0)] + color: LinearRgba, +} + +impl Material for CustomMaterial { + fn fragment_shader() -> ShaderRef { + "draw_custom_material.wgsl".into() + } +} + + +fn model(app: &App) -> Model { + Model {} +} + +fn view(app: &App, model: &Model, window: Entity) { + // Begin drawing + let draw = app.draw() + // Initialize our draw instance with our custom material + .material(CustomMaterial { + color: RED.into(), + }); + + draw.ellipse() + .x(-200.0); + + // We can also map the material manually + draw.ellipse() + .map_material(|mut mat| { + mat.color = BLUE.into(); + mat + }) + .x(200.0); +} diff --git a/examples/draw/draw_fragment_shader.rs b/examples/draw/draw_fragment_shader.rs index 543b8766e..09568b870 100644 --- a/examples/draw/draw_fragment_shader.rs +++ b/examples/draw/draw_fragment_shader.rs @@ -1,7 +1,5 @@ use nannou::prelude::*; -struct Model {} - fn main() { nannou::app(model) .simple_window(view) @@ -11,6 +9,8 @@ fn main() { .run() } +struct Model {} + fn model(app: &App) -> Model { Model {} } diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 78982b291..0b28310c2 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -9,6 +9,7 @@ //! - [**LoopMode**](./enum.LoopMode.html) - describes the behaviour of the application event loop. use std::any::Any; use std::cell::RefCell; +use std::hash::Hash; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -283,6 +284,15 @@ where self } + pub fn init_custom_material(mut self) -> Self + where + T: Material + Default, + T::Data: PartialEq + Eq + Hash + Clone, + { + self.app.add_plugins(NannouMaterialPlugin::::default()); + 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 { diff --git a/nannou/src/prelude.rs b/nannou/src/prelude.rs index 2687672f6..df0d19656 100644 --- a/nannou/src/prelude.rs +++ b/nannou/src/prelude.rs @@ -5,6 +5,8 @@ pub use crate::io::{load_from_json, load_from_toml, safe_file_save, save_to_json pub use crate::time::DurationF64; pub use bevy::ecs as bevy_ecs; pub use bevy::reflect as bevy_reflect; +pub use bevy::render as bevy_render; +pub use bevy::asset as bevy_asset; pub use bevy_nannou::prelude::*; pub use nannou_core::prelude::*; #[cfg(feature = "egui")]