diff --git a/assets/shaders/dissolve.wgsl b/assets/shaders/dissolve.wgsl index e071e59..7028dca 100644 --- a/assets/shaders/dissolve.wgsl +++ b/assets/shaders/dissolve.wgsl @@ -70,7 +70,7 @@ fn fragment( var cutoff = dissolve.percentage; if n > cutoff { - out.color = vec4(0.0, 0.0, 0.0, cutoff); + // out.color = vec4(0.0, 1.0, 0.0, cutoff); discard; } diff --git a/examples/shaders.rs b/examples/shaders.rs index 0e857d4..209b506 100644 --- a/examples/shaders.rs +++ b/examples/shaders.rs @@ -13,6 +13,7 @@ fn main() { MaterialPlugin::::default(), )) .add_systems(Startup, setup) + .add_systems(Update, set_scene) .add_systems(Update, rotate) .add_systems(Update, toggle_material.run_if( |keys: Res>| -> bool { @@ -25,11 +26,11 @@ fn main() { .run(); } -fn setup(mut commands: Commands, assets: Res) { - commands.spawn(SceneBundle { - scene: assets.load("models/Martian Chess.glb#Scene0"), - ..default() - }); +#[derive(Component)] +struct Root; + +fn setup(mut commands: Commands) { + commands.spawn((SceneBundle { ..default() }, Root)); commands.spawn(PointLightBundle { point_light: PointLight { @@ -46,6 +47,15 @@ fn setup(mut commands: Commands, assets: Res) { }); } +fn set_scene( + mut events: Query<&mut Handle, (With, Added)>, + assets: Res, +) { + events.iter_mut().for_each(|mut scene| { + *scene = assets.load("models/Martian Chess.glb#Scene0"); + }); +} + #[derive(Asset, AsBindGroup, Reflect, Debug, Clone)] struct MatExt { #[uniform(100)] diff --git a/src/display3d.rs b/src/display3d.rs index 2b0e340..65e90a7 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -70,7 +70,7 @@ impl Plugin for Display3dPlugin { .or_else(any_component_added::) .or_else(on_event::>()), ), - setup_capture_piece.run_if(any_component_added::), + setup_capture_piece.run_if(any_component_changed::>), capture_piece.run_if(any_with_component::()), ), ) @@ -579,160 +579,160 @@ fn set_piece_texture( .get_handle::("display3d_models_assets_file") .unwrap(); if let Some(gltf) = gltfs.get(assets_handle) { - children.iter_descendants(entity).for_each(|child| { - if let Ok((n, mut m)) = models.get_mut(child) { - debug!("Setting piece texture for {:?}", child); - match (*piece, side, n.as_str()) { - (Piece::Queen, Side::A, "Queen.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_queen_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Queen texture") - .clone() - } - (Piece::Queen, Side::A, "Queen.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Dots texture") - .clone() - } - (Piece::Queen, Side::B, "Queen.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_queen_blue") - .unwrap() - .as_str(), - ) - .expect("Load Blue Queen texture") - .clone() - } - (Piece::Queen, Side::B, "Queen.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_blue") - .unwrap() - .as_str(), - ) - .expect("Load Red Dots texture") - .clone() - } - (Piece::Drone, Side::A, "Drone.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_drone_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Drone texture") - .clone() - } - (Piece::Drone, Side::A, "Drone.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Dots texture") - .clone() - } - (Piece::Drone, Side::B, "Drone.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_drone_blue") - .unwrap() - .as_str(), - ) - .expect("Load Blue Drone texture") - .clone() - } - (Piece::Drone, Side::B, "Drone.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_blue") - .unwrap() - .as_str(), - ) - .expect("Load Blue Dots texture") - .clone() - } - (Piece::Pawn, Side::A, "Pawn.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_pawn_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Pawn texture") - .clone() - } - (Piece::Pawn, Side::A, "Pawn.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_red") - .unwrap() - .as_str(), - ) - .expect("Load Red Dots texture") - .clone() - } - (Piece::Pawn, Side::B, "Pawn.0") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_pawn_blue") - .unwrap() - .as_str(), - ) - .expect("Load Blue Pawn texture") - .clone() - } - (Piece::Pawn, Side::B, "Pawn.1") => { - *m = gltf - .named_materials - .get( - tweak - .get::("display3d_models_materials_dots_blue") - .unwrap() - .as_str(), - ) - .expect("Load Blue Dots texture") - .clone() - } - _ => warn!("???"), + // Why can't we just models.iter_many_mut(...).for_each(...)?? + let mut stuff = models.iter_many_mut(children.iter_descendants(entity)); + while let Some((n, mut m)) = stuff.fetch_next() { + debug!("Setting piece texture for {:?}", n); + match (*piece, side, n.as_str()) { + (Piece::Queen, Side::A, "Queen.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_queen_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Queen texture") + .clone() + } + (Piece::Queen, Side::A, "Queen.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Dots texture") + .clone() + } + (Piece::Queen, Side::B, "Queen.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_queen_blue") + .unwrap() + .as_str(), + ) + .expect("Load Blue Queen texture") + .clone() } + (Piece::Queen, Side::B, "Queen.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_blue") + .unwrap() + .as_str(), + ) + .expect("Load Red Dots texture") + .clone() + } + (Piece::Drone, Side::A, "Drone.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_drone_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Drone texture") + .clone() + } + (Piece::Drone, Side::A, "Drone.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Dots texture") + .clone() + } + (Piece::Drone, Side::B, "Drone.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_drone_blue") + .unwrap() + .as_str(), + ) + .expect("Load Blue Drone texture") + .clone() + } + (Piece::Drone, Side::B, "Drone.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_blue") + .unwrap() + .as_str(), + ) + .expect("Load Blue Dots texture") + .clone() + } + (Piece::Pawn, Side::A, "Pawn.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_pawn_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Pawn texture") + .clone() + } + (Piece::Pawn, Side::A, "Pawn.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_red") + .unwrap() + .as_str(), + ) + .expect("Load Red Dots texture") + .clone() + } + (Piece::Pawn, Side::B, "Pawn.0") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_pawn_blue") + .unwrap() + .as_str(), + ) + .expect("Load Blue Pawn texture") + .clone() + } + (Piece::Pawn, Side::B, "Pawn.1") => { + *m = gltf + .named_materials + .get( + tweak + .get::("display3d_models_materials_dots_blue") + .unwrap() + .as_str(), + ) + .expect("Load Blue Dots texture") + .clone() + } + _ => warn!("???"), } - }); + } } - }) + }); } /// Select tiles and pieces in 3d @@ -1281,12 +1281,12 @@ struct Backup(T); /// Sets up all pieces to have an associated "dissolve" material ready for capture fn setup_capture_piece( + // All entities with materials are candidates for this procedure + events: Query<(Entity, &Handle), (Added>, Changed>)>, // Only process newly created pieces (we do not delete pieces at runtime) - events: Query>, + query: Query, Added)>, // Children of pieces are the actual meshes that need materials - children: Query<&Children>, - // All entities with materials are candidates for this procedure - query: Query<(Entity, &Handle)>, + parents: Query<&Parent>, // Used to create DissovleMaterial standard_materials: Res>, // Used to create Handle @@ -1296,39 +1296,41 @@ fn setup_capture_piece( // Cache dissolve textures that have already been created mut cache: Local, Handle>>, ) { - events.iter().for_each(|entity| { - query - .iter_many(children.iter_descendants(entity)) - .for_each(|(child, std_handle)| { - let dis_handle = match cache.get(std_handle) { - // We have not seen this material, so create a new dissolve material - None => { - // Extension we will add to existing gltf-sourced materials - let extension = DissolveExtension { percentage: 1.0 }; - // Base material we will extend for the duration of the dissolve effect - let mut base = standard_materials - .get(std_handle) - .expect("Resolve material data") - .clone(); - - base.opaque_render_method = OpaqueRendererMethod::Auto; - base.alpha_mode = AlphaMode::Mask(0.5); - - dissolve_materials.add(ExtendedMaterial { base, extension }) - }, - Some(dis_handle) => dis_handle.clone(), - }; + events + .iter() + // Only process if this is a child of a piece + .filter(|(child, _)| { + query.iter_many(parents.iter_ancestors(*child)).count() > 0 + }) + // Handle this entity (mesh) + .for_each(|(child, std_handle)| { + let dis_handle = match cache.get(std_handle) { + // We have not seen this material, so create a new dissolve material + None => { + // Extension we will add to existing gltf-sourced materials + let extension = DissolveExtension { percentage: 1.0 }; + // Base material we will extend for the duration of the dissolve effect + let mut base = standard_materials + .get(std_handle) + .expect("Resolve material data") + .clone(); + + base.opaque_render_method = OpaqueRendererMethod::Auto; + base.alpha_mode = AlphaMode::Mask(0.5); + + dissolve_materials.add(ExtendedMaterial { base, extension }) + }, + Some(dis_handle) => dis_handle.clone(), + }; - cache.insert(std_handle.clone(), dis_handle.clone()); + // Insert this handle into the cache (may be redundant) + cache.insert(std_handle.clone(), dis_handle.clone()); - commands - .entity(child) - .insert(dis_handle.clone()) - .insert(Backup(std_handle.clone())) - .remove::>(); - }) - } - ); + // Add the dissolve handle as a Backup(T) + commands + .entity(child) + .insert(Backup(dis_handle.clone())); + }); } /// When a piece is captured... @@ -1363,9 +1365,8 @@ fn capture_piece( *prog = 1.0; // store the kids we want to process - *kids = children - .iter_descendants(entity) - .filter_map(|e| object_standard_materials.get(e).ok()) + *kids = object_standard_materials + .iter_many(children.iter_descendants(entity)) .map(|(child, std_handle, Backup(dis_handle))| { // Swap standard and dissolve material commands @@ -1418,6 +1419,10 @@ fn capture_piece( "Play fade out animation {:?} {:?}", delta, dissolve_material.extension.percentage ); + + commands + .entity(_child) + .log_components(); } ); }