diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 07898068fcd24b..d41187d2c139a4 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -60,15 +60,22 @@ impl Plugin for WireframePlugin { } } -/// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled -#[derive(Component, Debug, Clone, Default, ExtractComponent, Reflect)] +/// Overrides the global [`WireframeConfig`] for a single mesh. +#[derive(Component, Debug, Clone, Default, ExtractComponent, Reflect, Eq, PartialEq)] #[reflect(Component, Default)] -pub struct Wireframe; +pub enum Wireframe { + /// Always render the wireframe for this entity, regardless of global config. + #[default] + AlwaysRender, + /// Never render the wireframe for this entity, regardless of global config. + NeverRender, +} #[derive(Resource, Debug, Clone, Default, ExtractResource, Reflect)] #[reflect(Resource)] pub struct WireframeConfig { - /// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered. + /// Whether to show wireframes for all meshes. + /// Can be overridden for individual meshes by adding a [`Wireframe`] component. pub global: bool, } @@ -116,10 +123,7 @@ fn queue_wireframes( mut pipelines: ResMut>, pipeline_cache: Res, msaa: Res, - mut material_meshes: ParamSet<( - Query<(Entity, &Handle, &MeshUniform)>, - Query<(Entity, &Handle, &MeshUniform), With>, - )>, + material_meshes: Query<(Entity, &Handle, &MeshUniform, Option<&Wireframe>)>, mut views: Query<(&ExtractedView, &VisibleEntities, &mut RenderPhase)>, ) { let draw_custom = opaque_3d_draw_functions.read().id::(); @@ -129,7 +133,7 @@ fn queue_wireframes( let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); let add_render_phase = - |(entity, mesh_handle, mesh_uniform): (Entity, &Handle, &MeshUniform)| { + |(entity, mesh_handle, mesh_uniform, _): (Entity, &Handle, &MeshUniform, _)| { if let Some(mesh) = render_meshes.get(mesh_handle) { let key = view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology); @@ -155,21 +159,15 @@ fn queue_wireframes( } }; - if wireframe_config.global { - let query = material_meshes.p0(); - visible_entities - .entities - .iter() - .filter_map(|visible_entity| query.get(*visible_entity).ok()) - .for_each(add_render_phase); - } else { - let query = material_meshes.p1(); - visible_entities - .entities - .iter() - .filter_map(|visible_entity| query.get(*visible_entity).ok()) - .for_each(add_render_phase); - } + visible_entities + .entities + .iter() + .filter_map(|visible_entity| material_meshes.get(*visible_entity).ok()) + .filter(|(.., wireframe_override)| { + (wireframe_config.global || *wireframe_override == Some(&Wireframe::AlwaysRender)) + && *wireframe_override != Some(&Wireframe::NeverRender) + }) + .for_each(add_render_phase); } } diff --git a/examples/3d/wireframe.rs b/examples/3d/wireframe.rs index 277ab902a19103..9768cd53842bc5 100644 --- a/examples/3d/wireframe.rs +++ b/examples/3d/wireframe.rs @@ -17,36 +17,54 @@ fn main() { }), WireframePlugin, )) + .insert_resource(WireframeToggleTimer(Timer::from_seconds( + 1.0, + TimerMode::Repeating, + ))) .add_systems(Startup, setup) + .add_systems(Update, toggle_global_wireframe_setting) .run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, - mut wireframe_config: ResMut, mut meshes: ResMut>, mut materials: ResMut>, ) { - // To draw the wireframe on all entities, set this to 'true' - wireframe_config.global = false; // plane commands.spawn(PbrBundle { - mesh: meshes.add(shape::Plane::from_size(5.0).into()), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + mesh: meshes.add(Mesh::from(shape::Plane::from_size(5.0))), + material: materials.add(Color::rgb(0.3, 0.3, 0.5).into()), + ..default() + }); + + // Red cube: Never renders a wireframe + commands + .spawn(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), + material: materials.add(Color::rgb(0.8, 0.1, 0.1).into()), + transform: Transform::from_xyz(-1.0, 0.5, -1.0), + ..default() + }) + .insert(Wireframe::NeverRender); + // Orange cube: Follows global wireframe setting + commands.spawn(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), + material: materials.add(Color::rgb(0.8, 0.8, 0.1).into()), + transform: Transform::from_xyz(0.0, 0.5, 0.0), ..default() }); - // cube - commands.spawn(( - PbrBundle { + // Green cube: Always renders a wireframe + commands + .spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), - material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), - transform: Transform::from_xyz(0.0, 0.5, 0.0), + material: materials.add(Color::rgb(0.1, 0.8, 0.1).into()), + transform: Transform::from_xyz(1.0, 0.5, 1.0), ..default() - }, - // This enables wireframe drawing on this entity - Wireframe, - )); + }) + .insert(Wireframe::AlwaysRender); + // light commands.spawn(PointLightBundle { transform: Transform::from_xyz(4.0, 8.0, 4.0), @@ -58,3 +76,22 @@ fn setup( ..default() }); } + +/// This timer is used to periodically toggle the wireframe rendering. +#[derive(Resource)] +struct WireframeToggleTimer(Timer); + +/// Periodically turns the global wireframe setting on and off, to show the differences between +/// [`Wireframe::AlwaysRender`], [`Wireframe::NeverRender`], and no override. +fn toggle_global_wireframe_setting( + time: Res