refactor examples

This commit is contained in:
Jérôme Bousquié
2026-09-25 10:19:24 +02:00
parent ab3f056dbb
commit 35aeb769a8
37 changed files with 3430 additions and 457 deletions
+217
View File
@@ -0,0 +1,217 @@
//! **Bloom** — demonstrates the bloom post-process with emissive materials.
//!
//! A glowing sphere (emissive intensity 2.0) produces a visible halo. The scene
//! also contains a lit ground plane and a cube for reference.
//!
//! ## Controls
//! | Key | Action |
//! |-----|--------|
//! | Drag (LMB) | Orbit camera |
//! | Wheel | Zoom |
//! | `R` | Reset camera |
//! | `+` / `-` | Bloom threshold up/down |
//! | `[` / `]` | Bloom intensity up/down |
//! | `I` / `O` | Bloom radius up/down |
//! | `E` | Exposure up (×1.3) |
//! | `Q` | Exposure down (÷1.3) |
//! | `0` | Reset exposure |
//!
//! ## Build & Run
//! ```sh
//! cargo run -p wsg-lib --example bloom
//! ```
use glam::{Quat, Vec3};
use winit::event::MouseButton;
use winit::keyboard::KeyCode;
use wsg_lib::app::AppBuilder;
use wsg_lib::camera::CameraController;
use wsg_lib::core::{BloomConfig, ToneMapper, Transform};
use wsg_lib::mesh::{cube, icosphere, plane};
use wsg_lib::AppHandler;
use wsg_lib::utils::WsgError;
struct BloomDemo {
camera: CameraController,
angle: f32,
/// Runtime bloom config (mirrors the App's internal state for display/adjustment).
bloom: BloomConfig,
}
impl AppHandler for BloomDemo {
fn setup(&mut self, app: &mut wsg_lib::App) {
app.scene
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
.unwrap();
// Ground plane.
app.scene
.create_mesh("ground_mesh", plane(8.0, 8.0, 1, 1), None)
.unwrap();
app.scene.add_entity("ground", "ground_mesh").unwrap();
// Cube (lit, non-emissive — reference).
app.scene
.create_mesh("cube_mesh", cube(0.7), None)
.unwrap();
let mut cube_tf = Transform::identity();
cube_tf.translation = Vec3::new(1.5, 0.35, 0.0);
app.scene
.add_entity_with_transform("cube_e", "cube_mesh", cube_tf)
.unwrap();
// Glowing sphere (emissive intensity 2.0 → HDR bloom).
app.scene
.add_material_shader("glow_mat", "standard")
.unwrap();
app.scene
.set_material_emissive("glow_mat", [1.0, 0.3, 0.05, 2.0])
.unwrap();
app.scene
.create_mesh("glow_mesh", icosphere(0.35, 3), Some("glow_mat"))
.unwrap();
let mut glow_tf = Transform::identity();
glow_tf.translation = Vec3::new(0.0, 0.5, 0.0);
app.scene
.add_entity_with_transform("glow_e", "glow_mesh", glow_tf)
.unwrap();
// Second glow (blue, higher intensity for more dramatic bloom).
app.scene
.add_material_shader("blue_glow_mat", "standard")
.unwrap();
app.scene
.set_material_emissive("blue_glow_mat", [0.2, 0.5, 1.0, 3.0])
.unwrap();
app.scene
.create_mesh("blue_glow_mesh", icosphere(0.25, 3), Some("blue_glow_mat"))
.unwrap();
let mut blue_tf = Transform::identity();
blue_tf.translation = Vec3::new(-1.5, 0.4, 0.0);
app.scene
.add_entity_with_transform("blue_glow_e", "blue_glow_mesh", blue_tf)
.unwrap();
// Directional light (warm, from above-right).
let light_dir = Vec3::new(1.0, 1.5, 0.8).normalize();
app.scene
.add_directional_light(light_dir, [1.0, 0.95, 0.88], 1.2)
.unwrap();
app.scene.set_ambient([0.12, 0.12, 0.15]);
// Camera.
self.camera.yaw = 0.4;
self.camera.pitch = 0.3;
self.camera.distance = 5.0;
self.camera.target = Vec3::new(0.0, 0.5, 0.0);
self.camera.apply_to(app.scene.camera_mut());
// Sync bloom config from the App.
if let Some(cfg) = app.bloom_config() {
self.bloom = cfg.clone();
}
}
fn update(&mut self, app: &mut wsg_lib::App) {
// Orbit camera.
let (dx, dy) = app.input.mouse_delta();
if app.input.mouse_button_held(MouseButton::Left) {
self.camera.orbit(dx, dy);
}
let (_, sy) = app.input.scroll_delta();
self.camera.zoom(sy);
if app.input.key_pressed(KeyCode::KeyR) {
self.camera.yaw = 0.4;
self.camera.pitch = 0.3;
self.camera.distance = 5.0;
}
self.camera.apply_to(app.scene.camera_mut());
// Bloom threshold (+/-).
if app.input.key_pressed(KeyCode::Equal) {
self.bloom.threshold += 0.1;
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom threshold = {:.2}", self.bloom.threshold);
}
if app.input.key_pressed(KeyCode::Minus) {
self.bloom.threshold = (self.bloom.threshold - 0.1).max(0.0);
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom threshold = {:.2}", self.bloom.threshold);
}
// Bloom intensity ([/]).
if app.input.key_pressed(KeyCode::BracketRight) {
self.bloom.intensity += 0.1;
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom intensity = {:.2}", self.bloom.intensity);
}
if app.input.key_pressed(KeyCode::BracketLeft) {
self.bloom.intensity = (self.bloom.intensity - 0.1).max(0.0);
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom intensity = {:.2}", self.bloom.intensity);
}
// Bloom radius (I/O).
if app.input.key_pressed(KeyCode::KeyI) {
self.bloom.radius += 0.5;
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom radius = {:.1}", self.bloom.radius);
}
if app.input.key_pressed(KeyCode::KeyO) {
self.bloom.radius = (self.bloom.radius - 0.5).max(0.5);
app.set_bloom_config(self.bloom.clone());
eprintln!("bloom radius = {:.1}", self.bloom.radius);
}
// Exposure (E/Q/0).
if app.input.key_pressed(KeyCode::KeyE) {
app.set_exposure(app.exposure() * 1.3);
eprintln!("exposure = {:.2}", app.exposure());
}
if app.input.key_pressed(KeyCode::KeyQ) {
app.set_exposure(app.exposure() / 1.3);
eprintln!("exposure = {:.2}", app.exposure());
}
if app.input.key_pressed(KeyCode::Digit0) {
app.set_exposure(1.0);
eprintln!("exposure reset to 1.0");
}
// Slow rotation of the glow spheres.
self.angle += 0.01;
let mut tf = *app
.scene
.entity_transform("glow_e")
.expect("glow entity present");
tf.rotation = Quat::from_rotation_y(self.angle);
app.scene.set_entity_transform("glow_e", tf);
let mut tf2 = *app
.scene
.entity_transform("blue_glow_e")
.expect("blue glow entity present");
tf2.rotation = Quat::from_rotation_y(-self.angle * 0.7);
app.scene.set_entity_transform("blue_glow_e", tf2);
}
fn render(&mut self, app: &mut wsg_lib::App, frame: &wsg_lib::core::Frame) {
app.render_scene(frame.view());
}
}
#[pollster::main]
async fn main() -> Result<(), WsgError> {
let app = AppBuilder::new()
.title("WSG Bloom")
.size(960, 640)
.with_hdr(ToneMapper::Aces)
.with_bloom(BloomConfig::default())
.build()
.await?;
app.run(BloomDemo {
camera: CameraController::default(),
angle: 0.0,
bloom: BloomConfig::default(),
})
}