Skip to content

Commit ea78a22

Browse files
committed
Allow overriding global wireframe setting by adding a WireframeOverride component. (#7309)
1 parent 375af64 commit ea78a22

File tree

2 files changed

+84
-44
lines changed

2 files changed

+84
-44
lines changed

crates/bevy_pbr/src/wireframe.rs

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use bevy_render::{
2424
};
2525
use bevy_render::{Extract, ExtractSchedule, Render};
2626
use bevy_utils::tracing::error;
27-
use bevy_utils::EntityHashSet;
27+
use bevy_utils::EntityHashMap;
2828

2929
pub const WIREFRAME_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(192598014480025766);
3030

@@ -62,27 +62,38 @@ impl Plugin for WireframePlugin {
6262
}
6363
}
6464

65-
/// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled
66-
#[derive(Component, Debug, Clone, Default, Reflect)]
65+
/// Overrides the global [`WireframeConfig`] for a single mesh.
66+
#[derive(Component, Debug, Clone, Default, Reflect, Eq, PartialEq)]
6767
#[reflect(Component, Default)]
68-
pub struct Wireframe;
68+
pub enum Wireframe {
69+
/// Always render the wireframe for this entity, regardless of global config.
70+
#[default]
71+
AlwaysRender,
72+
/// Never render the wireframe for this entity, regardless of global config.
73+
NeverRender,
74+
}
6975

7076
#[derive(Resource, Debug, Clone, Default, ExtractResource, Reflect)]
7177
#[reflect(Resource)]
7278
pub struct WireframeConfig {
73-
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [`Wireframe`] component will be rendered.
79+
/// Whether to show wireframes for all meshes.
80+
/// Can be overridden for individual meshes by adding a [`Wireframe`] component.
7481
pub global: bool,
7582
}
7683

7784
#[derive(Resource, Default, Deref, DerefMut)]
78-
pub struct Wireframes(EntityHashSet<Entity>);
85+
pub struct Wireframes(EntityHashMap<Entity, Wireframe>);
7986

8087
fn extract_wireframes(
8188
mut wireframes: ResMut<Wireframes>,
82-
query: Extract<Query<Entity, With<Wireframe>>>,
89+
query: Extract<Query<(Entity, &Wireframe)>>,
8390
) {
8491
wireframes.clear();
85-
wireframes.extend(&query);
92+
wireframes.extend(
93+
query
94+
.iter()
95+
.map(|(entity, wireframe)| (entity, wireframe.clone())),
96+
);
8697
}
8798

8899
#[derive(Resource, Clone)]
@@ -170,31 +181,23 @@ fn queue_wireframes(
170181
});
171182
};
172183

173-
if wireframe_config.global {
174-
visible_entities
175-
.entities
176-
.iter()
177-
.filter_map(|visible_entity| {
184+
visible_entities
185+
.entities
186+
.iter()
187+
.filter_map(|visible_entity| {
188+
let wireframe_override = wireframes.get(visible_entity);
189+
190+
if (wireframe_config.global || wireframe_override == Some(&Wireframe::AlwaysRender))
191+
&& wireframe_override != Some(&Wireframe::NeverRender)
192+
{
178193
render_mesh_instances
179194
.get(visible_entity)
180195
.map(|mesh_instance| (*visible_entity, mesh_instance))
181-
})
182-
.for_each(add_render_phase);
183-
} else {
184-
visible_entities
185-
.entities
186-
.iter()
187-
.filter_map(|visible_entity| {
188-
if wireframes.contains(visible_entity) {
189-
render_mesh_instances
190-
.get(visible_entity)
191-
.map(|mesh_instance| (*visible_entity, mesh_instance))
192-
} else {
193-
None
194-
}
195-
})
196-
.for_each(add_render_phase);
197-
}
196+
} else {
197+
None
198+
}
199+
})
200+
.for_each(add_render_phase);
198201
}
199202
}
200203

examples/3d/wireframe.rs

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,54 @@ fn main() {
1818
}),
1919
WireframePlugin,
2020
))
21+
.insert_resource(WireframeToggleTimer(Timer::from_seconds(
22+
1.0,
23+
TimerMode::Repeating,
24+
)))
2125
.add_systems(Startup, setup)
26+
.add_systems(Update, toggle_global_wireframe_setting)
2227
.run();
2328
}
2429

2530
/// set up a simple 3D scene
2631
fn setup(
2732
mut commands: Commands,
28-
mut wireframe_config: ResMut<WireframeConfig>,
2933
mut meshes: ResMut<Assets<Mesh>>,
3034
mut materials: ResMut<Assets<StandardMaterial>>,
3135
) {
32-
// To draw the wireframe on all entities, set this to 'true'
33-
wireframe_config.global = false;
3436
// plane
3537
commands.spawn(PbrBundle {
36-
mesh: meshes.add(shape::Plane::from_size(5.0).into()),
37-
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
38+
mesh: meshes.add(Mesh::from(shape::Plane::from_size(5.0))),
39+
material: materials.add(Color::rgb(0.3, 0.3, 0.5).into()),
40+
..default()
41+
});
42+
43+
// Red cube: Never renders a wireframe
44+
commands
45+
.spawn(PbrBundle {
46+
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
47+
material: materials.add(Color::rgb(0.8, 0.1, 0.1).into()),
48+
transform: Transform::from_xyz(-1.0, 0.5, -1.0),
49+
..default()
50+
})
51+
.insert(Wireframe::NeverRender);
52+
// Orange cube: Follows global wireframe setting
53+
commands.spawn(PbrBundle {
54+
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
55+
material: materials.add(Color::rgb(0.8, 0.8, 0.1).into()),
56+
transform: Transform::from_xyz(0.0, 0.5, 0.0),
3857
..default()
3958
});
40-
// cube
41-
commands.spawn((
42-
PbrBundle {
59+
// Green cube: Always renders a wireframe
60+
commands
61+
.spawn(PbrBundle {
4362
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
44-
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
45-
transform: Transform::from_xyz(0.0, 0.5, 0.0),
63+
material: materials.add(Color::rgb(0.1, 0.8, 0.1).into()),
64+
transform: Transform::from_xyz(1.0, 0.5, 1.0),
4665
..default()
47-
},
48-
// This enables wireframe drawing on this entity
49-
Wireframe,
50-
));
66+
})
67+
.insert(Wireframe::AlwaysRender);
68+
5169
// light
5270
commands.spawn(PointLightBundle {
5371
transform: Transform::from_xyz(4.0, 8.0, 4.0),
@@ -59,3 +77,22 @@ fn setup(
5977
..default()
6078
});
6179
}
80+
81+
/// This timer is used to periodically toggle the wireframe rendering.
82+
#[derive(Resource)]
83+
struct WireframeToggleTimer(Timer);
84+
85+
/// Periodically turns the global wireframe setting on and off, to show the differences between
86+
/// [`Wireframe::AlwaysRender`], [`Wireframe::NeverRender`], and no override.
87+
fn toggle_global_wireframe_setting(
88+
time: Res<Time>,
89+
mut timer: ResMut<WireframeToggleTimer>,
90+
mut wireframe_config: ResMut<WireframeConfig>,
91+
) {
92+
if timer.0.tick(time.delta()).just_finished() {
93+
// The global wireframe config enables drawing of wireframes on every mesh, except those with
94+
// `WireframeOverride::NeverRender`. Meshes with `WireframeOverride::AlwaysRender` will
95+
// always have a wireframe, regardless of the global configuration.
96+
wireframe_config.global = !wireframe_config.global;
97+
}
98+
}

0 commit comments

Comments
 (0)