mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Add basic light gizmos (#12228)
# Objective - Part of #9400. - Add light gizmos for `SpotLight`, `PointLight` and `DirectionalLight`. ## Solution - Add a `ShowLightGizmo` and its related gizmo group and plugin, that shows a gizmo for all lights of an entities when inserted on it. Light display can also be toggled globally through the gizmo config in the same way it can already be done for `Aabb`s. - Add distinct segment setters for height and base one `Cone3dBuilder`. This allow having a properly rounded base without too much edges along the height. The doc comments explain how to ensure height and base connect when setting different values. Gizmo for the three light types without radius with the depth bias set to -1: ![without-radius](https://github.com/bevyengine/bevy/assets/18357657/699d0154-f367-4727-9b09-8b458d96a0e2) With Radius: ![with-radius](https://github.com/bevyengine/bevy/assets/18357657/f3af003e-dbba-427a-a305-c5cc1676e340) Possible future improvements: - Add a billboarded sprite with a distinct sprite for each light type. - Display the intensity of the light somehow (no idea how to represent that apart from some text). --- ## Changelog ### Added - The new `ShowLightGizmo`, part of the `LightGizmoPlugin` and configurable globally with `LightGizmoConfigGroup`, allows drawing gizmo for `PointLight`, `SpotLight` and `DirectionalLight`. The gizmos color behavior can be controlled with the `LightGizmoColor` member of `ShowLightGizmo` and `LightGizmoConfigGroup`. - The cone gizmo builder (`Cone3dBuilder`) now allows setting a differing number of segments for the base and height. --------- Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
This commit is contained in:
parent
6032978eba
commit
de0ed293fa
6 changed files with 563 additions and 9 deletions
11
Cargo.toml
11
Cargo.toml
|
@ -2680,6 +2680,17 @@ description = "A scene showcasing 3D gizmos"
|
|||
category = "Gizmos"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "light_gizmos"
|
||||
path = "examples/gizmos/light_gizmos.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.light_gizmos]
|
||||
name = "Light Gizmos"
|
||||
description = "A scene showcasing light gizmos"
|
||||
category = "Gizmos"
|
||||
wasm = true
|
||||
|
||||
[profile.wasm-release]
|
||||
inherits = "release"
|
||||
opt-level = "z"
|
||||
|
|
|
@ -32,6 +32,7 @@ pub mod circles;
|
|||
pub mod config;
|
||||
pub mod gizmos;
|
||||
pub mod grid;
|
||||
pub mod light;
|
||||
pub mod primitives;
|
||||
|
||||
#[cfg(feature = "bevy_sprite")]
|
||||
|
@ -46,6 +47,7 @@ pub mod prelude {
|
|||
aabb::{AabbGizmoConfigGroup, ShowAabbGizmo},
|
||||
config::{DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore},
|
||||
gizmos::Gizmos,
|
||||
light::{LightGizmoColor, LightGizmoConfigGroup, ShowLightGizmo},
|
||||
primitives::{dim2::GizmoPrimitive2d, dim3::GizmoPrimitive3d},
|
||||
AppGizmoBuilder,
|
||||
};
|
||||
|
@ -85,6 +87,7 @@ use config::{
|
|||
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoMeshConfig,
|
||||
};
|
||||
use gizmos::GizmoStorage;
|
||||
use light::LightGizmoPlugin;
|
||||
use std::{any::TypeId, mem};
|
||||
|
||||
const LINE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(7414812689238026784);
|
||||
|
@ -110,7 +113,8 @@ impl Plugin for GizmoPlugin {
|
|||
.init_resource::<LineGizmoHandles>()
|
||||
// We insert the Resource GizmoConfigStore into the world implicitly here if it does not exist.
|
||||
.init_gizmo_group::<DefaultGizmoConfigGroup>()
|
||||
.add_plugins(AabbGizmoPlugin);
|
||||
.add_plugins(AabbGizmoPlugin)
|
||||
.add_plugins(LightGizmoPlugin);
|
||||
|
||||
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
|
||||
return;
|
||||
|
|
324
crates/bevy_gizmos/src/light.rs
Normal file
324
crates/bevy_gizmos/src/light.rs
Normal file
|
@ -0,0 +1,324 @@
|
|||
//! A module adding debug visualization of [`PointLight`]s, [`SpotLight`]s and [`DirectionalLight`]s.
|
||||
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use crate::{self as bevy_gizmos, primitives::dim3::GizmoPrimitive3d};
|
||||
|
||||
use bevy_app::{Plugin, PostUpdate};
|
||||
use bevy_color::{
|
||||
palettes::basic::{BLUE, GREEN, RED},
|
||||
Color, Oklcha,
|
||||
};
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
query::Without,
|
||||
reflect::ReflectComponent,
|
||||
schedule::IntoSystemConfigs,
|
||||
system::{Query, Res},
|
||||
};
|
||||
use bevy_math::{
|
||||
primitives::{Cone, Sphere},
|
||||
Quat, Vec3,
|
||||
};
|
||||
use bevy_pbr::{DirectionalLight, PointLight, SpotLight};
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_transform::{components::GlobalTransform, TransformSystem};
|
||||
|
||||
use crate::{
|
||||
config::{GizmoConfigGroup, GizmoConfigStore},
|
||||
gizmos::Gizmos,
|
||||
AppGizmoBuilder,
|
||||
};
|
||||
|
||||
/// Draws a standard sphere for the radius and an axis sphere for the range.
|
||||
fn point_light_gizmo(
|
||||
transform: &GlobalTransform,
|
||||
point_light: &PointLight,
|
||||
color: Color,
|
||||
gizmos: &mut Gizmos<LightGizmoConfigGroup>,
|
||||
) {
|
||||
let position = transform.translation();
|
||||
gizmos
|
||||
.primitive_3d(
|
||||
Sphere {
|
||||
radius: point_light.radius,
|
||||
},
|
||||
position,
|
||||
Quat::IDENTITY,
|
||||
color,
|
||||
)
|
||||
.segments(16);
|
||||
gizmos
|
||||
.sphere(position, Quat::IDENTITY, point_light.range, color)
|
||||
.circle_segments(32);
|
||||
}
|
||||
|
||||
/// Draws a sphere for the radius, two cones for the inner and outer angles, plus two 3d arcs crossing the
|
||||
/// farthest point of effect of the spot light along its direction.
|
||||
fn spot_light_gizmo(
|
||||
transform: &GlobalTransform,
|
||||
spot_light: &SpotLight,
|
||||
color: Color,
|
||||
gizmos: &mut Gizmos<LightGizmoConfigGroup>,
|
||||
) {
|
||||
let (_, rotation, translation) = transform.to_scale_rotation_translation();
|
||||
gizmos
|
||||
.primitive_3d(
|
||||
Sphere {
|
||||
radius: spot_light.radius,
|
||||
},
|
||||
translation,
|
||||
Quat::IDENTITY,
|
||||
color,
|
||||
)
|
||||
.segments(16);
|
||||
|
||||
// Offset the tip of the cone to the light position.
|
||||
for angle in [spot_light.inner_angle, spot_light.outer_angle] {
|
||||
let height = spot_light.range * angle.cos();
|
||||
let position = translation + rotation * Vec3::NEG_Z * height / 2.0;
|
||||
gizmos
|
||||
.primitive_3d(
|
||||
Cone {
|
||||
radius: spot_light.range * angle.sin(),
|
||||
height,
|
||||
},
|
||||
position,
|
||||
rotation * Quat::from_rotation_x(PI / 2.0),
|
||||
color,
|
||||
)
|
||||
.height_segments(4)
|
||||
.base_segments(32);
|
||||
}
|
||||
|
||||
for arc_rotation in [
|
||||
Quat::from_rotation_y(PI / 2.0 - spot_light.outer_angle),
|
||||
Quat::from_euler(
|
||||
bevy_math::EulerRot::XZY,
|
||||
0.0,
|
||||
PI / 2.0,
|
||||
PI / 2.0 - spot_light.outer_angle,
|
||||
),
|
||||
] {
|
||||
gizmos
|
||||
.arc_3d(
|
||||
2.0 * spot_light.outer_angle,
|
||||
spot_light.range,
|
||||
translation,
|
||||
rotation * arc_rotation,
|
||||
color,
|
||||
)
|
||||
.segments(16);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws an arrow alongside the directional light direction.
|
||||
fn directional_light_gizmo(
|
||||
transform: &GlobalTransform,
|
||||
color: Color,
|
||||
gizmos: &mut Gizmos<LightGizmoConfigGroup>,
|
||||
) {
|
||||
let (_, rotation, translation) = transform.to_scale_rotation_translation();
|
||||
gizmos
|
||||
.arrow(translation, translation + rotation * Vec3::NEG_Z, color)
|
||||
.with_tip_length(0.3);
|
||||
}
|
||||
|
||||
/// A [`Plugin`] that provides visualization of [`PointLight`]s, [`SpotLight`]s
|
||||
/// and [`DirectionalLight`]s for debugging.
|
||||
pub struct LightGizmoPlugin;
|
||||
|
||||
impl Plugin for LightGizmoPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.register_type::<LightGizmoConfigGroup>()
|
||||
.init_gizmo_group::<LightGizmoConfigGroup>()
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
draw_lights,
|
||||
draw_all_lights.run_if(|config: Res<GizmoConfigStore>| {
|
||||
config.config::<LightGizmoConfigGroup>().1.draw_all
|
||||
}),
|
||||
)
|
||||
.after(TransformSystem::TransformPropagate),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures how a color is attributed to a light gizmo.
|
||||
#[derive(Debug, Clone, Copy, Default, Reflect)]
|
||||
pub enum LightGizmoColor {
|
||||
/// User-specified color.
|
||||
Manual(Color),
|
||||
/// Random color derived from the light's [`Entity`].
|
||||
Varied,
|
||||
/// Take the color of the represented light.
|
||||
#[default]
|
||||
MatchLightColor,
|
||||
/// Take the color provided by [`LightGizmoConfigGroup`] depending on the light kind.
|
||||
ByLightType,
|
||||
}
|
||||
|
||||
/// The [`GizmoConfigGroup`] used to configure the visualization of lights.
|
||||
#[derive(Clone, Reflect, GizmoConfigGroup)]
|
||||
pub struct LightGizmoConfigGroup {
|
||||
/// Draw a gizmo for all lights if true.
|
||||
///
|
||||
/// Defaults to `false`.
|
||||
pub draw_all: bool,
|
||||
/// Default color strategy for all light gizmos.
|
||||
///
|
||||
/// Defaults to [`LightGizmoColor::MatchLightColor`].
|
||||
pub color: LightGizmoColor,
|
||||
/// [`Color`] to use for drawing a [`PointLight`] gizmo when [`LightGizmoColor::ByLightType`] is used.
|
||||
///
|
||||
/// Defaults to [`RED`].
|
||||
pub point_light_color: Color,
|
||||
/// [`Color`] to use for drawing a [`SpotLight`] gizmo when [`LightGizmoColor::ByLightType`] is used.
|
||||
///
|
||||
/// Defaults to [`GREEN`].
|
||||
pub spot_light_color: Color,
|
||||
/// [`Color`] to use for drawing a [`DirectionalLight`] gizmo when [`LightGizmoColor::ByLightType`] is used.
|
||||
///
|
||||
/// Defaults to [`BLUE`].
|
||||
pub directional_light_color: Color,
|
||||
}
|
||||
|
||||
impl Default for LightGizmoConfigGroup {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
draw_all: false,
|
||||
color: LightGizmoColor::MatchLightColor,
|
||||
point_light_color: RED.into(),
|
||||
spot_light_color: GREEN.into(),
|
||||
directional_light_color: BLUE.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add this [`Component`] to an entity to draw any of its lights components
|
||||
/// ([`PointLight`], [`SpotLight`] and [`DirectionalLight`]).
|
||||
#[derive(Component, Reflect, Default, Debug)]
|
||||
#[reflect(Component, Default)]
|
||||
pub struct ShowLightGizmo {
|
||||
/// Default color strategy for this light gizmo. if [`None`], use the one provided by [`LightGizmoConfigGroup`].
|
||||
///
|
||||
/// Defaults to [`None`].
|
||||
pub color: Option<LightGizmoColor>,
|
||||
}
|
||||
|
||||
fn draw_lights(
|
||||
point_query: Query<(Entity, &PointLight, &GlobalTransform, &ShowLightGizmo)>,
|
||||
spot_query: Query<(Entity, &SpotLight, &GlobalTransform, &ShowLightGizmo)>,
|
||||
directional_query: Query<(Entity, &DirectionalLight, &GlobalTransform, &ShowLightGizmo)>,
|
||||
mut gizmos: Gizmos<LightGizmoConfigGroup>,
|
||||
) {
|
||||
let color = |entity: Entity, gizmo_color: Option<LightGizmoColor>, light_color, type_color| {
|
||||
match gizmo_color.unwrap_or(gizmos.config_ext.color) {
|
||||
LightGizmoColor::Manual(color) => color,
|
||||
LightGizmoColor::Varied => Oklcha::sequential_dispersed(entity.index()).into(),
|
||||
LightGizmoColor::MatchLightColor => light_color,
|
||||
LightGizmoColor::ByLightType => type_color,
|
||||
}
|
||||
};
|
||||
for (entity, light, transform, light_gizmo) in &point_query {
|
||||
let color = color(
|
||||
entity,
|
||||
light_gizmo.color,
|
||||
light.color,
|
||||
gizmos.config_ext.point_light_color,
|
||||
);
|
||||
point_light_gizmo(transform, light, color, &mut gizmos);
|
||||
}
|
||||
for (entity, light, transform, light_gizmo) in &spot_query {
|
||||
let color = color(
|
||||
entity,
|
||||
light_gizmo.color,
|
||||
light.color,
|
||||
gizmos.config_ext.spot_light_color,
|
||||
);
|
||||
spot_light_gizmo(transform, light, color, &mut gizmos);
|
||||
}
|
||||
for (entity, light, transform, light_gizmo) in &directional_query {
|
||||
let color = color(
|
||||
entity,
|
||||
light_gizmo.color,
|
||||
light.color,
|
||||
gizmos.config_ext.directional_light_color,
|
||||
);
|
||||
directional_light_gizmo(transform, color, &mut gizmos);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_all_lights(
|
||||
point_query: Query<(Entity, &PointLight, &GlobalTransform), Without<ShowLightGizmo>>,
|
||||
spot_query: Query<(Entity, &SpotLight, &GlobalTransform), Without<ShowLightGizmo>>,
|
||||
directional_query: Query<
|
||||
(Entity, &DirectionalLight, &GlobalTransform),
|
||||
Without<ShowLightGizmo>,
|
||||
>,
|
||||
mut gizmos: Gizmos<LightGizmoConfigGroup>,
|
||||
) {
|
||||
match gizmos.config_ext.color {
|
||||
LightGizmoColor::Manual(color) => {
|
||||
for (_, light, transform) in &point_query {
|
||||
point_light_gizmo(transform, light, color, &mut gizmos);
|
||||
}
|
||||
for (_, light, transform) in &spot_query {
|
||||
spot_light_gizmo(transform, light, color, &mut gizmos);
|
||||
}
|
||||
for (_, _, transform) in &directional_query {
|
||||
directional_light_gizmo(transform, color, &mut gizmos);
|
||||
}
|
||||
}
|
||||
LightGizmoColor::Varied => {
|
||||
let color = |entity: Entity| Oklcha::sequential_dispersed(entity.index()).into();
|
||||
for (entity, light, transform) in &point_query {
|
||||
point_light_gizmo(transform, light, color(entity), &mut gizmos);
|
||||
}
|
||||
for (entity, light, transform) in &spot_query {
|
||||
spot_light_gizmo(transform, light, color(entity), &mut gizmos);
|
||||
}
|
||||
for (entity, _, transform) in &directional_query {
|
||||
directional_light_gizmo(transform, color(entity), &mut gizmos);
|
||||
}
|
||||
}
|
||||
LightGizmoColor::MatchLightColor => {
|
||||
for (_, light, transform) in &point_query {
|
||||
point_light_gizmo(transform, light, light.color, &mut gizmos);
|
||||
}
|
||||
for (_, light, transform) in &spot_query {
|
||||
spot_light_gizmo(transform, light, light.color, &mut gizmos);
|
||||
}
|
||||
for (_, light, transform) in &directional_query {
|
||||
directional_light_gizmo(transform, light.color, &mut gizmos);
|
||||
}
|
||||
}
|
||||
LightGizmoColor::ByLightType => {
|
||||
for (_, light, transform) in &point_query {
|
||||
point_light_gizmo(
|
||||
transform,
|
||||
light,
|
||||
gizmos.config_ext.point_light_color,
|
||||
&mut gizmos,
|
||||
);
|
||||
}
|
||||
for (_, light, transform) in &spot_query {
|
||||
spot_light_gizmo(
|
||||
transform,
|
||||
light,
|
||||
gizmos.config_ext.spot_light_color,
|
||||
&mut gizmos,
|
||||
);
|
||||
}
|
||||
for (_, _, transform) in &directional_query {
|
||||
directional_light_gizmo(
|
||||
transform,
|
||||
gizmos.config_ext.directional_light_color,
|
||||
&mut gizmos,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -609,14 +609,36 @@ pub struct Cone3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
|
|||
// Color of the cone
|
||||
color: Color,
|
||||
|
||||
// Number of segments used to approximate the cone geometry
|
||||
segments: usize,
|
||||
// Number of segments used to approximate the cone base geometry
|
||||
base_segments: usize,
|
||||
|
||||
// Number of segments used to approximate the cone height geometry
|
||||
height_segments: usize,
|
||||
}
|
||||
|
||||
impl<T: GizmoConfigGroup> Cone3dBuilder<'_, '_, '_, T> {
|
||||
/// Set the number of segments used to approximate the cone geometry.
|
||||
/// Set the number of segments used to approximate the cone geometry for its base and height.
|
||||
pub fn segments(mut self, segments: usize) -> Self {
|
||||
self.segments = segments;
|
||||
self.base_segments = segments;
|
||||
self.height_segments = segments;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the number of segments to approximate the height of the cone geometry.
|
||||
///
|
||||
/// `segments` should be a multiple of the value passed to [`Self::height_segments`]
|
||||
/// for the height to connect properly with the base.
|
||||
pub fn base_segments(mut self, segments: usize) -> Self {
|
||||
self.base_segments = segments;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the number of segments to approximate the height of the cone geometry.
|
||||
///
|
||||
/// `segments` should be a divisor of the value passed to [`Self::base_segments`]
|
||||
/// for the height to connect properly with the base.
|
||||
pub fn height_segments(mut self, segments: usize) -> Self {
|
||||
self.height_segments = segments;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +660,8 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Cone> for Gizmos<'w, 's, T> {
|
|||
position,
|
||||
rotation,
|
||||
color,
|
||||
segments: DEFAULT_NUMBER_SEGMENTS,
|
||||
base_segments: DEFAULT_NUMBER_SEGMENTS,
|
||||
height_segments: DEFAULT_NUMBER_SEGMENTS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -656,7 +679,8 @@ impl<T: GizmoConfigGroup> Drop for Cone3dBuilder<'_, '_, '_, T> {
|
|||
position,
|
||||
rotation,
|
||||
color,
|
||||
segments,
|
||||
base_segments,
|
||||
height_segments,
|
||||
} = self;
|
||||
|
||||
let half_height = *height * 0.5;
|
||||
|
@ -665,7 +689,7 @@ impl<T: GizmoConfigGroup> Drop for Cone3dBuilder<'_, '_, '_, T> {
|
|||
draw_circle_3d(
|
||||
gizmos,
|
||||
*radius,
|
||||
*segments,
|
||||
*base_segments,
|
||||
*rotation,
|
||||
*position - *rotation * Vec3::Y * half_height,
|
||||
*color,
|
||||
|
@ -673,7 +697,7 @@ impl<T: GizmoConfigGroup> Drop for Cone3dBuilder<'_, '_, '_, T> {
|
|||
|
||||
// connect the base circle with the tip of the cone
|
||||
let end = Vec3::Y * half_height;
|
||||
circle_coordinates(*radius, *segments)
|
||||
circle_coordinates(*radius, *height_segments)
|
||||
.map(|p| Vec3::new(p.x, -half_height, p.y))
|
||||
.map(move |p| [p, end])
|
||||
.map(|ps| ps.map(rotate_then_translate_3d(*rotation, *position)))
|
||||
|
|
|
@ -266,6 +266,7 @@ Example | Description
|
|||
--- | ---
|
||||
[2D Gizmos](../examples/gizmos/2d_gizmos.rs) | A scene showcasing 2D gizmos
|
||||
[3D Gizmos](../examples/gizmos/3d_gizmos.rs) | A scene showcasing 3D gizmos
|
||||
[Light Gizmos](../examples/gizmos/light_gizmos.rs) | A scene showcasing light gizmos
|
||||
|
||||
## Input
|
||||
|
||||
|
|
190
examples/gizmos/light_gizmos.rs
Normal file
190
examples/gizmos/light_gizmos.rs
Normal file
|
@ -0,0 +1,190 @@
|
|||
//! This example demonstrates how to visualize lights properties through the gizmo API.
|
||||
|
||||
use std::f32::consts::{FRAC_PI_2, PI};
|
||||
|
||||
use bevy::{
|
||||
color::palettes::css::{DARK_CYAN, GOLD, GRAY, PURPLE},
|
||||
gizmos::light::{LightGizmoColor, LightGizmoConfigGroup},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, rotate_camera)
|
||||
.add_systems(Update, update_config)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct GizmoColorText;
|
||||
|
||||
fn gizmo_color_text(config: &LightGizmoConfigGroup) -> String {
|
||||
match config.color {
|
||||
LightGizmoColor::Manual(color) => format!("Manual {}", Srgba::from(color).to_hex()),
|
||||
LightGizmoColor::Varied => "Random from entity".to_owned(),
|
||||
LightGizmoColor::MatchLightColor => "Match light color".to_owned(),
|
||||
LightGizmoColor::ByLightType => {
|
||||
format!(
|
||||
"Point {}, Spot {}, Directional {}",
|
||||
Srgba::from(config.point_light_color).to_hex(),
|
||||
Srgba::from(config.spot_light_color).to_hex(),
|
||||
Srgba::from(config.directional_light_color).to_hex()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut config_store: ResMut<GizmoConfigStore>,
|
||||
) {
|
||||
// Circular base.
|
||||
commands.spawn(PbrBundle {
|
||||
mesh: meshes.add(Circle::new(4.0)),
|
||||
material: materials.add(Color::WHITE),
|
||||
transform: Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Cubes.
|
||||
{
|
||||
let mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
|
||||
let material = materials.add(Color::srgb_u8(124, 144, 255));
|
||||
for x in [-2.0, 0.0, 2.0] {
|
||||
commands.spawn(PbrBundle {
|
||||
mesh: mesh.clone(),
|
||||
material: material.clone(),
|
||||
transform: Transform::from_xyz(x, 0.5, 0.0),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Lights.
|
||||
{
|
||||
commands.spawn(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
shadows_enabled: true,
|
||||
range: 2.0,
|
||||
color: DARK_CYAN.into(),
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(0.0, 1.5, 0.0),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(SpotLightBundle {
|
||||
spot_light: SpotLight {
|
||||
shadows_enabled: true,
|
||||
range: 3.5,
|
||||
color: PURPLE.into(),
|
||||
outer_angle: PI / 4.0,
|
||||
inner_angle: PI / 4.0 * 0.8,
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(4.0, 2.0, 0.0).looking_at(Vec3::X * 1.5, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(DirectionalLightBundle {
|
||||
directional_light: DirectionalLight {
|
||||
color: GOLD.into(),
|
||||
illuminance: DirectionalLight::default().illuminance * 0.05,
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(-4.0, 2.0, 0.0).looking_at(Vec3::NEG_X * 1.5, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
// Camera.
|
||||
commands.spawn(Camera3dBundle {
|
||||
transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Example instructions and gizmo config.
|
||||
{
|
||||
let text_style = TextStyle {
|
||||
font_size: 20.0,
|
||||
..default()
|
||||
};
|
||||
commands.spawn(
|
||||
TextBundle::from_section(
|
||||
"Press 'D' to toggle drawing gizmos on top of everything else in the scene\n\
|
||||
Hold 'Left' or 'Right' to change the line width of the gizmos\n\
|
||||
Press 'A' to toggle drawing of the light gizmos\n\
|
||||
Press 'C' to cycle between the light gizmos coloring modes",
|
||||
text_style.clone(),
|
||||
)
|
||||
.with_style(Style {
|
||||
position_type: PositionType::Absolute,
|
||||
top: Val::Px(12.0),
|
||||
left: Val::Px(12.0),
|
||||
..default()
|
||||
}),
|
||||
);
|
||||
|
||||
let (_, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
|
||||
light_config.draw_all = true;
|
||||
light_config.color = LightGizmoColor::MatchLightColor;
|
||||
|
||||
commands.spawn((
|
||||
TextBundle::from_sections([
|
||||
TextSection::new("Gizmo color mode: ", text_style.clone()),
|
||||
TextSection::new(gizmo_color_text(light_config), text_style),
|
||||
])
|
||||
.with_style(Style {
|
||||
position_type: PositionType::Absolute,
|
||||
bottom: Val::Px(12.0),
|
||||
left: Val::Px(12.0),
|
||||
..default()
|
||||
}),
|
||||
GizmoColorText,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn rotate_camera(mut query: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
|
||||
let mut transform = query.single_mut();
|
||||
|
||||
transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 2.));
|
||||
}
|
||||
|
||||
fn update_config(
|
||||
mut config_store: ResMut<GizmoConfigStore>,
|
||||
keyboard: Res<ButtonInput<KeyCode>>,
|
||||
time: Res<Time>,
|
||||
mut color_text_query: Query<&mut Text, With<GizmoColorText>>,
|
||||
) {
|
||||
if keyboard.just_pressed(KeyCode::KeyD) {
|
||||
for (_, config, _) in config_store.iter_mut() {
|
||||
config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
|
||||
}
|
||||
}
|
||||
|
||||
let (config, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
|
||||
if keyboard.pressed(KeyCode::ArrowRight) {
|
||||
config.line_width += 5. * time.delta_seconds();
|
||||
config.line_width = config.line_width.clamp(0., 50.);
|
||||
}
|
||||
if keyboard.pressed(KeyCode::ArrowLeft) {
|
||||
config.line_width -= 5. * time.delta_seconds();
|
||||
config.line_width = config.line_width.clamp(0., 50.);
|
||||
}
|
||||
if keyboard.just_pressed(KeyCode::KeyA) {
|
||||
config.enabled ^= true;
|
||||
}
|
||||
if keyboard.just_pressed(KeyCode::KeyC) {
|
||||
light_config.color = match light_config.color {
|
||||
LightGizmoColor::Manual(_) => LightGizmoColor::Varied,
|
||||
LightGizmoColor::Varied => LightGizmoColor::MatchLightColor,
|
||||
LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType,
|
||||
LightGizmoColor::ByLightType => LightGizmoColor::Manual(GRAY.into()),
|
||||
};
|
||||
color_text_query.single_mut().sections[1].value = gizmo_color_text(light_config);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue