|
4 | 4 | //! regardless of which engine plugins are loaded. |
5 | 5 |
|
6 | 6 | use bevy::prelude::*; |
| 7 | +use bevy::camera::primitives::Aabb; |
7 | 8 | use bevy::pbr::Lightmap; |
8 | 9 | use bevy::light::{EnvironmentMapLight, IrradianceVolume, LightProbe, VolumetricFog, VolumetricLight}; |
9 | 10 | use egui_phosphor::regular; |
@@ -392,8 +393,12 @@ fn directional_light_entry() -> InspectorEntry { |
392 | 393 | icon: regular::SUN, |
393 | 394 | category: "lighting", |
394 | 395 | has_fn: |world, entity| world.get::<DirectionalLight>(entity).is_some(), |
395 | | - add_fn: None, |
396 | | - remove_fn: None, |
| 396 | + add_fn: Some(|world, entity| { |
| 397 | + world.entity_mut(entity).insert(DirectionalLight::default()); |
| 398 | + }), |
| 399 | + remove_fn: Some(|world, entity| { |
| 400 | + world.entity_mut(entity).remove::<DirectionalLight>(); |
| 401 | + }), |
397 | 402 | is_enabled_fn: None, |
398 | 403 | set_enabled_fn: None, |
399 | 404 | fields: vec![ |
@@ -462,8 +467,14 @@ fn point_light_entry() -> InspectorEntry { |
462 | 467 | icon: regular::LIGHTBULB, |
463 | 468 | category: "lighting", |
464 | 469 | has_fn: |world, entity| world.get::<PointLight>(entity).is_some(), |
465 | | - add_fn: None, |
466 | | - remove_fn: None, |
| 470 | + add_fn: Some(|world, entity| { |
| 471 | + spawn_light_child(world, entity, "Point Light", |child| { |
| 472 | + child.insert(PointLight::default()); |
| 473 | + }); |
| 474 | + }), |
| 475 | + remove_fn: Some(|world, entity| { |
| 476 | + world.entity_mut(entity).remove::<PointLight>(); |
| 477 | + }), |
467 | 478 | is_enabled_fn: None, |
468 | 479 | set_enabled_fn: None, |
469 | 480 | fields: vec![ |
@@ -552,8 +563,14 @@ fn spot_light_entry() -> InspectorEntry { |
552 | 563 | icon: regular::FLASHLIGHT, |
553 | 564 | category: "lighting", |
554 | 565 | has_fn: |world, entity| world.get::<SpotLight>(entity).is_some(), |
555 | | - add_fn: None, |
556 | | - remove_fn: None, |
| 566 | + add_fn: Some(|world, entity| { |
| 567 | + spawn_light_child(world, entity, "Spot Light", |child| { |
| 568 | + child.insert(SpotLight::default()); |
| 569 | + }); |
| 570 | + }), |
| 571 | + remove_fn: Some(|world, entity| { |
| 572 | + world.entity_mut(entity).remove::<SpotLight>(); |
| 573 | + }), |
557 | 574 | is_enabled_fn: None, |
558 | 575 | set_enabled_fn: None, |
559 | 576 | fields: vec![ |
@@ -1182,3 +1199,44 @@ fn volumetric_fog_entry() -> InspectorEntry { |
1182 | 1199 | custom_ui_fn: None, |
1183 | 1200 | } |
1184 | 1201 | } |
| 1202 | + |
| 1203 | +/// Add a positional light (PointLight/SpotLight) to an entity such that the |
| 1204 | +/// emitter sits at the visible center of the entity's geometry rather than |
| 1205 | +/// at its `Transform` origin. |
| 1206 | +/// |
| 1207 | +/// Many imported GLBs (sketchfab scenes especially) have meshes whose local |
| 1208 | +/// `Transform` is `(0,0,0)` with all the world position baked into the |
| 1209 | +/// vertex data. A `PointLight` attached directly reads the entity's |
| 1210 | +/// `GlobalTransform` — `(0,0,0)` — and emits from world origin, nowhere |
| 1211 | +/// near where the light bulb actually appears. |
| 1212 | +/// |
| 1213 | +/// To put the light where the artist expects, we spawn it on a CHILD |
| 1214 | +/// entity with `Transform.translation` set to the parent's local AABB |
| 1215 | +/// center. The child's `GlobalTransform` then composes into the AABB world |
| 1216 | +/// center, which is what the user clicked on. Light moves with the parent |
| 1217 | +/// when reparented or transformed, same as any normal child. |
| 1218 | +/// |
| 1219 | +/// If the entity has no `Aabb` (typical for empty entities the user |
| 1220 | +/// created themselves to hold a light), the child still gets created but |
| 1221 | +/// at the parent's origin — equivalent to attaching the light directly, |
| 1222 | +/// just one level of indirection. |
| 1223 | +fn spawn_light_child( |
| 1224 | + world: &mut World, |
| 1225 | + parent: Entity, |
| 1226 | + name: &str, |
| 1227 | + insert: impl FnOnce(&mut bevy::ecs::world::EntityWorldMut), |
| 1228 | +) { |
| 1229 | + let center = world |
| 1230 | + .get::<Aabb>(parent) |
| 1231 | + .map(|a| Vec3::from(a.center)) |
| 1232 | + .unwrap_or(Vec3::ZERO); |
| 1233 | + |
| 1234 | + let mut child_cmd = world.spawn(( |
| 1235 | + Name::new(name.to_string()), |
| 1236 | + Transform::from_translation(center), |
| 1237 | + Visibility::default(), |
| 1238 | + )); |
| 1239 | + insert(&mut child_cmd); |
| 1240 | + let child = child_cmd.id(); |
| 1241 | + world.entity_mut(parent).add_child(child); |
| 1242 | +} |
0 commit comments