Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding global wireframe setting. #7328

Merged
merged 1 commit into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 33 additions & 30 deletions crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bevy_render::{
};
use bevy_render::{Extract, ExtractSchedule, Render};
use bevy_utils::tracing::error;
use bevy_utils::EntityHashSet;
use bevy_utils::EntityHashMap;

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

Expand Down Expand Up @@ -62,27 +62,38 @@ impl Plugin for WireframePlugin {
}
}

/// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled
#[derive(Component, Debug, Clone, Default, Reflect)]
/// Overrides the global [`WireframeConfig`] for a single mesh.
#[derive(Component, Debug, Clone, Default, 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,
}

#[derive(Resource, Default, Deref, DerefMut)]
pub struct Wireframes(EntityHashSet<Entity>);
pub struct Wireframes(EntityHashMap<Entity, Wireframe>);

fn extract_wireframes(
mut wireframes: ResMut<Wireframes>,
query: Extract<Query<Entity, With<Wireframe>>>,
query: Extract<Query<(Entity, &Wireframe)>>,
) {
wireframes.clear();
wireframes.extend(&query);
wireframes.extend(
query
.iter()
.map(|(entity, wireframe)| (entity, wireframe.clone())),
);
}

#[derive(Resource, Clone)]
Expand Down Expand Up @@ -170,31 +181,23 @@ fn queue_wireframes(
});
};

if wireframe_config.global {
visible_entities
.entities
.iter()
.filter_map(|visible_entity| {
visible_entities
.entities
.iter()
.filter_map(|visible_entity| {
let wireframe_override = wireframes.get(visible_entity);

if (wireframe_config.global || wireframe_override == Some(&Wireframe::AlwaysRender))
&& wireframe_override != Some(&Wireframe::NeverRender)
{
render_mesh_instances
.get(visible_entity)
.map(|mesh_instance| (*visible_entity, mesh_instance))
})
.for_each(add_render_phase);
} else {
visible_entities
.entities
.iter()
.filter_map(|visible_entity| {
if wireframes.contains(visible_entity) {
render_mesh_instances
.get(visible_entity)
.map(|mesh_instance| (*visible_entity, mesh_instance))
} else {
None
}
})
.for_each(add_render_phase);
}
} else {
None
}
})
.for_each(add_render_phase);
}
}

Expand Down
65 changes: 51 additions & 14 deletions examples/3d/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,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<WireframeConfig>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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),
Expand All @@ -59,3 +77,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<Time>,
mut timer: ResMut<WireframeToggleTimer>,
mut wireframe_config: ResMut<WireframeConfig>,
) {
if timer.0.tick(time.delta()).just_finished() {
// The global wireframe config enables drawing of wireframes on every mesh, except those with
// `WireframeOverride::NeverRender`. Meshes with `WireframeOverride::AlwaysRender` will
// always have a wireframe, regardless of the global configuration.
wireframe_config.global = !wireframe_config.global;
}
}