This commit is contained in:
Jérôme Bousquié
2026-09-21 10:07:32 +02:00
parent 4bfd712496
commit 5ae978da23
49 changed files with 1640 additions and 611 deletions
+25 -25
View File
@@ -1,21 +1,21 @@
//! Test dédié aux **lumières spot** (Étape 13, Phase 4.2).
//! Test dedicated to **spot lights** (Step 13, Phase 4.2).
//!
//! Dans cet exemple, **seule** une lumière spot est allumée (la directionnelle par défaut est
//! retirée via `clear_lights()`) et l'ambiant est volontairement **très bas**. Le cube apparaît
//! donc quasiment noir sauf là où le cône de la spot l'atteint : on voit clairement
//! In this example, **only** a spot light is on (the default directional light is
//! removed via `clear_lights()`) and the ambient is deliberately **very low**. The cube therefore
//! appears nearly black except where the spot's cone reaches it: you clearly see
//!
//! 1. un **faisceau orienté** (pas un halo omni comme la lumière ponctuelle),
//! 2. un **bord lissé** (pénombre) à la limite du cône,
//! 3. l'éclairage qui **suit le cube** quand il tourne (le cône est fixe dans l'espace monde).
//! 1. a **directed beam** (not an omni halo like the point light),
//! 2. a **smoothed edge** (penumbra) at the cone's limit,
//! 3. the lighting that **follows the cube** as it rotates (the cone is fixed in world space).
//!
//! Lance avec : `cargo run -p wsg-lib --example spot_test`
//! Run with: `cargo run -p wsg-lib --example spot_test`
use glam::{Quat, Vec3};
use wsg_lib::AppHandler;
use wsg_lib::app::AppBuilder;
use wsg_lib::math::cube;
use wsg_lib::utils::WsgError;
/// Handler de test : cube qui tourne lentement sur deux axes, éclairé **uniquement** par une spot.
/// Test handler: cube rotating slowly on two axes, lit **only** by a spot.
struct SpotTest {
angle_x: f32,
angle_y: f32,
@@ -32,32 +32,32 @@ impl AppHandler for SpotTest {
.unwrap();
app.scene.add_entity("cube", "cube_mesh").unwrap();
// On retire la directionnelle par défaut pour isoler la spot.
// Remove the default directional light to isolate the spot.
app.scene.clear_lights();
// Ambiant quasi nul : le cube est noir hors du faisceau, le cône saute aux yeux.
// Near-zero ambient: the cube is black outside the beam, the cone stands out.
app.scene.set_ambient([0.03, 0.03, 0.03]);
// La spot est au-dessus/derrière-caméra, pointée vers l'origine (le cube).
// Position monde (0, 2, 3), axe du cône vers (0,0,0).
// The spot is above/behind the camera, aimed at the origin (the cube).
// World position (0, 2, 3), cone axis toward (0,0,0).
let spot_pos = Vec3::new(0.0, 2.0, 3.0);
let spot_dir = (Vec3::ZERO - spot_pos).normalize(); // pointe vers le cube
let spot_dir = (Vec3::ZERO - spot_pos).normalize(); // points at the cube
app.scene
.add_spot_light(
spot_pos,
spot_dir,
[1.0, 0.9, 0.6], // teinte chaude
2.0, // intensité
10.0, // rayon d'atténuation (large, le cube est à ~3.6)
0.45, // demi-angle (~26°) — assez large pour couvrir le cube
[1.0, 0.9, 0.6], // warm tint
2.0, // intensity
10.0, // attenuation radius (wide, the cube is at ~3.6)
0.45, // half-angle (~26°) — wide enough to cover the cube
)
.unwrap();
}
fn update(&mut self, app: &mut wsg_lib::App) {
// Rotation lente sur deux axes (X et Y) : le cône est fixe dans l'espace monde,
// on voit donc une région fixe du cube rester éclairée pendant que le cube tourne.
// Les deux axes permettent de voir l'effet du faisceau sur les 6 faces sans
// orientation privilégiée (la rotation Y seule laisserait les faces +Y/-Y fixes).
// Slow rotation on two axes (X and Y): the cone is fixed in world space,
// so a fixed region of the cube stays lit while the cube rotates.
// The two axes let you see the beam's effect on the 6 faces without
// a favored orientation (a Y rotation alone would leave the +Y/-Y faces fixed).
self.angle_x += 0.007;
self.angle_y += 0.011;
let base = *app
@@ -65,9 +65,9 @@ impl AppHandler for SpotTest {
.entity_transform("cube")
.expect("cube entity present");
let mut transform = base;
// Composition Y * X : l'axe X tourne dans le repère déjà orienté en Y,
// ce qui donne un mouvement de précession (tous les sommets passent devant
// le cône à tour de rôle).
// Y * X composition: the X axis rotates in the frame already oriented by Y,
// which gives a precession motion (all vertices pass in front of
// the cone in turn).
transform.rotation =
Quat::from_rotation_y(self.angle_y) * Quat::from_rotation_x(self.angle_x);
app.scene.set_entity_transform("cube", transform);