réorg doc
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
//! **Emissive Materials** — demonstrates the emissive property of the standard material.
|
||||
//!
|
||||
//! Shows objects with varying emissive intensities. Without HDR, emissive values > 1.0
|
||||
//! are clamped to white (LDR). With HDR, they produce true "glow" that can feed the
|
||||
//! bloom post-process.
|
||||
//!
|
||||
//! The scene contains 5 spheres with increasing emissive intensity (0.0 → 4.0),
|
||||
//! arranged in a row. A lit cube serves as a non-emissive reference.
|
||||
//!
|
||||
//! ## Controls
|
||||
//! | Key | Action |
|
||||
//! |-----|--------|
|
||||
//! | Drag (LMB) | Orbit camera |
|
||||
//! | Wheel | Zoom |
|
||||
//! | `R` | Reset camera |
|
||||
//! | `E` | Exposure up (×1.3) |
|
||||
//! | `Q` | Exposure down (÷1.3) |
|
||||
//! | `0` | Reset exposure |
|
||||
//! | `C` | Cycle emissive intensity (re-applies to all glow spheres) |
|
||||
//!
|
||||
//! ## Build & Run
|
||||
//! ```sh
|
||||
//! cargo run -p wsg-lib --example emissive
|
||||
//! ```
|
||||
//!
|
||||
//! Run with `--features all-prims` if you don't have the default features.
|
||||
|
||||
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::{ToneMapper, Transform};
|
||||
use wsg_lib::mesh::{cube, icosphere, plane};
|
||||
use wsg_lib::AppHandler;
|
||||
use wsg_lib::utils::WsgError;
|
||||
|
||||
/// Emissive intensities for the 5 glow spheres (left to right).
|
||||
const INTENSITIES: [f32; 5] = [0.0, 0.5, 1.0, 2.0, 4.0];
|
||||
/// RGB colors for the 5 glow spheres (rainbow-ish).
|
||||
const COLORS: [[f32; 3]; 5] = [
|
||||
[0.5, 0.5, 0.5], // gray (no glow)
|
||||
[1.0, 0.3, 0.1], // orange
|
||||
[1.0, 0.8, 0.0], // yellow
|
||||
[0.2, 1.0, 0.4], // green
|
||||
[0.3, 0.5, 1.0], // blue
|
||||
];
|
||||
|
||||
struct EmissiveDemo {
|
||||
camera: CameraController,
|
||||
angle: f32,
|
||||
/// Which intensity preset to apply (0-4 maps to a multiplier).
|
||||
cycle_idx: usize,
|
||||
}
|
||||
|
||||
impl AppHandler for EmissiveDemo {
|
||||
fn setup(&mut self, app: &mut wsg_lib::App) {
|
||||
app.scene
|
||||
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
|
||||
.unwrap();
|
||||
|
||||
// Ground.
|
||||
app.scene
|
||||
.create_mesh("ground_mesh", plane(10.0, 10.0, 1, 1), None)
|
||||
.unwrap();
|
||||
app.scene.add_entity("ground", "ground_mesh").unwrap();
|
||||
|
||||
// Reference cube (non-emissive).
|
||||
app.scene
|
||||
.create_mesh("cube_mesh", cube(0.6), None)
|
||||
.unwrap();
|
||||
let mut cube_tf = Transform::identity();
|
||||
cube_tf.translation = Vec3::new(0.0, 0.3, 1.5);
|
||||
app.scene
|
||||
.add_entity_with_transform("cube_e", "cube_mesh", cube_tf)
|
||||
.unwrap();
|
||||
|
||||
// 5 glow spheres in a row.
|
||||
for i in 0..5 {
|
||||
let mat_id = format!("glow_mat_{}", i);
|
||||
let mesh_id = format!("glow_mesh_{}", i);
|
||||
let entity_id = format!("glow_e_{}", i);
|
||||
|
||||
app.scene.add_material_shader(&mat_id, "standard").unwrap();
|
||||
let c = COLORS[i];
|
||||
let intensity = INTENSITIES[i];
|
||||
app.scene
|
||||
.set_material_emissive(&mat_id, [c[0], c[1], c[2], intensity])
|
||||
.unwrap();
|
||||
|
||||
app.scene
|
||||
.create_mesh(&mesh_id, icosphere(0.3, 3), Some(&mat_id))
|
||||
.unwrap();
|
||||
|
||||
let x = (i as f32 - 2.0) * 0.9;
|
||||
let mut tf = Transform::identity();
|
||||
tf.translation = Vec3::new(x, 0.4, 0.0);
|
||||
app.scene
|
||||
.add_entity_with_transform(&entity_id, &mesh_id, tf)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Directional light.
|
||||
let light_dir = Vec3::new(0.5, 1.0, 0.5).normalize();
|
||||
app.scene
|
||||
.add_directional_light(light_dir, [1.0, 0.95, 0.88], 1.0)
|
||||
.unwrap();
|
||||
app.scene.set_ambient([0.15, 0.15, 0.18]);
|
||||
|
||||
// Camera.
|
||||
self.camera.yaw = 0.0;
|
||||
self.camera.pitch = 0.2;
|
||||
self.camera.distance = 5.5;
|
||||
self.camera.target = Vec3::new(0.0, 0.3, 0.0);
|
||||
self.camera.apply_to(app.scene.camera_mut());
|
||||
}
|
||||
|
||||
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.0;
|
||||
self.camera.pitch = 0.2;
|
||||
self.camera.distance = 5.5;
|
||||
}
|
||||
self.camera.apply_to(app.scene.camera_mut());
|
||||
|
||||
// Exposure.
|
||||
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");
|
||||
}
|
||||
|
||||
// C: cycle emissive intensity multiplier (1x → 2x → 0.5x → back).
|
||||
if app.input.key_pressed(KeyCode::KeyC) {
|
||||
self.cycle_idx = (self.cycle_idx + 1) % 3;
|
||||
let multiplier = match self.cycle_idx {
|
||||
0 => 1.0,
|
||||
1 => 2.0,
|
||||
_ => 0.5,
|
||||
};
|
||||
for i in 0..5 {
|
||||
let mat_id = format!("glow_mat_{}", i);
|
||||
let c = COLORS[i];
|
||||
let intensity = INTENSITIES[i] * multiplier;
|
||||
if let Ok(()) = app.scene.set_material_emissive(&mat_id, [c[0], c[1], c[2], intensity]) {
|
||||
eprintln!("emissive multiplier = {:.1}x", multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slow rotation.
|
||||
self.angle += 0.01;
|
||||
for i in 0..5 {
|
||||
let entity_id = format!("glow_e_{}", i);
|
||||
if let Some(base) = app.scene.entity_transform(&entity_id) {
|
||||
let mut tf = *base;
|
||||
tf.rotation = Quat::from_rotation_y(self.angle * (1.0 + i as f32 * 0.2));
|
||||
app.scene.set_entity_transform(&entity_id, tf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
// HDR enabled so emissive > 1.0 produces true glow (not clamped to white).
|
||||
let app = AppBuilder::new()
|
||||
.title("WSG Emissive")
|
||||
.size(960, 640)
|
||||
.with_hdr(ToneMapper::Aces)
|
||||
.build()
|
||||
.await?;
|
||||
app.run(EmissiveDemo {
|
||||
camera: CameraController::default(),
|
||||
angle: 0.0,
|
||||
cycle_idx: 0,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user