readmes
This commit is contained in:
@@ -1,28 +1,28 @@
|
|||||||
# WSG — WGPU Simple Graphics Library
|
# WSG — WGPU Simple Graphics Library
|
||||||
|
|
||||||
**WSG** (WGPU Simple Graphics) est une bibliothèque Rust qui wrap [wgpu](https://github.com/gfx-rs/wgpu) et [winit](https://crates.io/crates/winit) pour dessiner en 3D **sans toucher wgpu directement**.
|
**WSG** (WGPU Simple Graphics) is a Rust library that wraps [wgpu](https://github.com/gfx-rs/wgpu) and [winit](https://crates.io/crates/winit) to draw 3D **without touching wgpu directly**.
|
||||||
|
|
||||||
## Ce que vous obtenez
|
## What you get
|
||||||
|
|
||||||
- **Une fenêtre 3D en ~30 lignes** — pas de wgpu, pas de winit dans votre code
|
- **A 3D window in ~30 lines** — no wgpu, no winit in your code
|
||||||
- **Éclairage Phong** (directional, point, spot) + **ombres portées** (shadow mapping)
|
- **Phong lighting** (directional, point, spot) + **shadows** (shadow mapping)
|
||||||
- **HDR + Tone Mapping** (ACES Filmic / Reinhard) — opt-in, zéro coût si désactivé
|
- **HDR + Tone Mapping** (ACES Filmic / Reinhard) — opt-in, zero cost when disabled
|
||||||
- **Pipeline GPU-driven** — world matrices + frustum culling sur le GPU, indirect draws
|
- **GPU-driven pipeline** — world matrices + frustum culling on the GPU, indirect draws
|
||||||
- **LOD** (Level of Detail) — dégradation automatique de la géométrie selon la distance
|
- **LOD** (Level of Detail) — automatic geometry degradation based on distance
|
||||||
- **Primitives procédurales** — cube, sphère, cylindre, cône, tore, plan
|
- **Procedural primitives** — cube, sphere, cylinder, cone, torus, plane
|
||||||
- **Import de fichiers** — parser OBJ intégré (glTF en cours)
|
- **File import** — built-in OBJ parser (glTF in progress)
|
||||||
- **Caméra orbitale** + input unifié (clavier/souris)
|
- **Orbital camera** + unified input (keyboard/mouse)
|
||||||
- **LOD, culling, HDR, ombres** : tout est **opt-in** — ce que vous n'activez pas ne coûte rien
|
- **LOD, culling, HDR, shadows**: everything is **opt-in** — what you don't enable costs nothing
|
||||||
|
|
||||||
## Forces
|
## Strengths
|
||||||
|
|
||||||
| Force | Détail |
|
| Strength | Detail |
|
||||||
|-------|--------|
|
|----------|--------|
|
||||||
| **Zéro wgpu dans votre code** | L'API déclarative (`AppBuilder` + `AppHandler`) encapsule tout |
|
| **Zero wgpu in your code** | The declarative API (`AppBuilder` + `AppHandler`) encapsulates everything |
|
||||||
| **Opt-in = zéro coût** | Un effet non activé n'alloue rien, n'exécute rien |
|
| **Opt-in = zero cost** | A disabled effect allocates nothing, executes nothing |
|
||||||
| **Features Cargo** | Ne compilez que les primitives/import dont vous avez besoin |
|
| **Cargo features** | Only compile the primitives/importers you need |
|
||||||
| **Un seul shader** | Le `standard` shader (Phong) couvre 90 % des cas ; mode unlit pour la 2D |
|
| **One shader** | The `standard` shader (Phong) covers 90% of cases; unlit mode for 2D |
|
||||||
| **GPU-driven** | Le CPU envoie des transforms, le GPU fait le reste (matrices, culling, draws) |
|
| **GPU-driven** | CPU sends transforms, GPU does the rest (matrices, culling, draws) |
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
@@ -31,9 +31,9 @@ use wsg_lib::prelude::*;
|
|||||||
use wsg_lib::app::AppBuilder;
|
use wsg_lib::app::AppBuilder;
|
||||||
use wsg_lib::utils::WsgError;
|
use wsg_lib::utils::WsgError;
|
||||||
|
|
||||||
struct MaScene;
|
struct MyScene;
|
||||||
|
|
||||||
impl AppHandler for MaScene {
|
impl AppHandler for MyScene {
|
||||||
fn setup(&mut self, app: &mut wsg_lib::App) {
|
fn setup(&mut self, app: &mut wsg_lib::App) {
|
||||||
app.scene
|
app.scene
|
||||||
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
|
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
|
||||||
@@ -42,7 +42,7 @@ impl AppHandler for MaScene {
|
|||||||
.create_material("mat", "standard", None)
|
.create_material("mat", "standard", None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Un cube lit par Phong, posé au-dessus d'un plan
|
// A Phong-lit cube, sitting on a ground plane
|
||||||
app.scene
|
app.scene
|
||||||
.create_mesh("cube", cube(1.0), Some("mat"))
|
.create_mesh("cube", cube(1.0), Some("mat"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -61,10 +61,10 @@ impl AppHandler for MaScene {
|
|||||||
|
|
||||||
fn main() -> Result<(), WsgError> {
|
fn main() -> Result<(), WsgError> {
|
||||||
let mut app = AppBuilder::new()
|
let mut app = AppBuilder::new()
|
||||||
.title("Ma scène WSG")
|
.title("My WSG scene")
|
||||||
.with_hdr(ToneMapper::Aces) // optionnel : HDR + tone mapping
|
.with_hdr(ToneMapper::Aces) // optional: HDR + tone mapping
|
||||||
.build()?;
|
.build()?;
|
||||||
app.run(MaScene);
|
app.run(MyScene);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -76,81 +76,91 @@ pollster = { version = "1", features = ["macro"] }
|
|||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run --example demo # le showcase complet (6 primitives, 3 lumières, ombres, HDR)
|
cargo run --example demo # full showcase (6 primitives, 3 lights, shadows, HDR)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fonctionnalités
|
## Features
|
||||||
|
|
||||||
| Catégorie | Ce qui est disponible |
|
| Category | What's available |
|
||||||
|-----------|----------------------|
|
|----------|-----------------|
|
||||||
| **Géométrie** | 6 primitives procédurales + import OBJ + `Geometry` custom |
|
| **Geometry** | 6 procedural primitives + OBJ import + custom `Geometry` |
|
||||||
| **Rendu** | Phong (lit), unlit (2D flat), HDR + tone mapping (ACES/Reinhard) |
|
| **Rendering** | Phong (lit), unlit (2D flat), PBR metallic/roughness, HDR + tone mapping |
|
||||||
| **Lumières** | Directional, point, spot (8 max) + ambient |
|
| **Lights** | Directional, point, spot (8 max) + ambient |
|
||||||
| **Ombres** | Shadow mapping (directional/spot), slope-scaled bias, PCF |
|
| **Shadows** | Shadow mapping (directional/spot), slope-scaled bias, PCF |
|
||||||
| **LOD** | Décimation quadric auto, hystérésis, 1 buffer multi-niveaux |
|
| **LOD** | Auto quadric decimation, hysteresis, 1 buffer multi-level |
|
||||||
| **GPU-driven** | Compute pass (matrices + culling) → indirect draws |
|
| **GPU-driven** | Compute pass (matrices + culling) → indirect draws |
|
||||||
| **Caméra** | Orbitale (drag/zoom/reset) + presets (front/side/top) |
|
| **Post-process** | Bloom, Depth of Field, Fog (3 modes), MSAA 4× |
|
||||||
| **Input** | Clavier (pressed/held/released), souris (delta, scroll, boutons) |
|
| **Camera** | Orbital (drag/zoom/reset) + presets (front/side/top) |
|
||||||
| **Textures** | RGBA8 (de bytes, de fichier, placeholder blanc) |
|
| **Input** | Keyboard (pressed/held/released), mouse (delta, scroll, buttons) |
|
||||||
|
| **Textures** | RGBA8 (from bytes, from file, white placeholder) |
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
| Où | Quoi |
|
| Where | What |
|
||||||
|----|------|
|
|-------|------|
|
||||||
| [docs/user/](docs/user/README.md) | **Guide utilisateur** (EN) — comment utiliser l'API, pas à pas |
|
| [docs/user/](docs/user/README.md) | **User guide** — how to use the API, step by step |
|
||||||
| [docs/tech/](docs/tech/ARCHI_APP.md) | **Architecture interne** (FR) — décisions, specs, cibles |
|
| [docs/tech/](docs/tech/ARCHI_APP.md) | **Internal architecture** — decisions, specs, targets |
|
||||||
| [docs/ROADMAP.md](docs/ROADMAP.md) | Feuille de route (phases 1-5 ✅, phase 6 en cours) |
|
| [docs/ROADMAP.md](docs/ROADMAP.md) | Roadmap (phases 1-5 ✅, phase 6 in progress) |
|
||||||
| [docs/PLAN.md](docs/PLAN.md) | Livre de recette (historique des étapes) |
|
| [docs/PLAN.md](docs/PLAN.md) | Recipe book (step history) |
|
||||||
| `cargo doc -p wsg-lib --no-deps` | **Référence API** (rustdoc, 100 % couvert) |
|
| `cargo doc -p wsg-lib --no-deps` | **API reference** (rustdoc, 100% covered) |
|
||||||
|
|
||||||
## Exemples
|
## Examples
|
||||||
|
|
||||||
| Exemple | Ce qu'il montre |
|
| Example | What it shows |
|
||||||
|---------|----------------|
|
|---------|---------------|
|
||||||
| `demo` | Le showcase : 6 primitives, 3 lumières, ombres, HDR, LOD, caméra orbitale |
|
| `demo` | Full showcase: 6 primitives, 3 lights, shadows, HDR, LOD, orbital camera |
|
||||||
| `cube` | MVP 3D : un cube lit par Phong, texture checkerboard |
|
| `bloom` | HDR bloom post-process |
|
||||||
| `simple` | Minimal : un quad coloré en mode unlit (2D) |
|
| `hdr` | HDR + tone mapping (ACES/Reinhard) |
|
||||||
| `shadow_test` | Ombres portées isolées |
|
| `emissive` | Emissive materials + runtime exposure control |
|
||||||
| `spot_test` | Spotlight isolé |
|
| `shadow` | Shadow mapping in isolation |
|
||||||
| `import` | Import de fichier OBJ (feature `import-obj`) |
|
| `culling` | GPU-driven frustum culling (15×15 grid) |
|
||||||
| `manual` | Workflow low-level (Context/Renderer/PipelineCache, sans App) |
|
| `msaa` | 4× multisample anti-aliasing |
|
||||||
|
| `fog` | 3 fog modes (linear, exponential, exponential²) |
|
||||||
|
| `dof` | Depth of field with focus presets |
|
||||||
|
| `pbr` | PBR metallic/roughness + normal mapping |
|
||||||
|
| `import` | OBJ file import (feature `import-obj`) |
|
||||||
|
| `manual` | Low-level workflow (Context/Renderer/PipelineCache, no App) |
|
||||||
|
|
||||||
## Features Cargo
|
## Cargo Features
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# Default : toutes les primitives
|
# Default: all primitives
|
||||||
wsg-lib = { path = "../lib" }
|
wsg-lib = { path = "../lib" }
|
||||||
|
|
||||||
# Minimal : juste le cube
|
# Minimal: just the cube
|
||||||
wsg-lib = { path = "../lib", default-features = false, features = ["prim-cube"] }
|
wsg-lib = { path = "../lib", default-features = false, features = ["prim-cube"] }
|
||||||
|
|
||||||
# Avec import OBJ
|
# With OBJ import
|
||||||
wsg-lib = { path = "../lib", features = ["import-obj"] }
|
wsg-lib = { path = "../lib", features = ["import-obj"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
| Feature | Active |
|
| Feature | Enables |
|
||||||
|---------|--------|
|
|---------|---------|
|
||||||
| `prim-cube`, `prim-plane`, `prim-sphere`, `prim-cylinder`, `prim-cone`, `prim-torus` | Primitives |
|
| `prim-cube`, `prim-plane`, `prim-sphere`, `prim-cylinder`, `prim-cone`, `prim-torus` | Primitives |
|
||||||
| `all-prims` (default) | Les 6 primitives |
|
| `all-prims` (default) | All 6 primitives |
|
||||||
| `import-obj` | Parser Wavefront OBJ |
|
| `import-obj` | Wavefront OBJ parser |
|
||||||
| `import-gltf` | glTF (stub) |
|
| `import-gltf` | glTF (stub) |
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo build --workspace # tout
|
cargo build --workspace # everything
|
||||||
cargo test --workspace # 116 tests
|
cargo test --workspace # 127 tests
|
||||||
cargo check --all-targets # vérification rapide
|
cargo check --all-targets # quick check
|
||||||
cargo run -p wsg-lib --example demo # lancer le showcase
|
cargo run -p wsg-lib --example demo # run the showcase
|
||||||
```
|
```
|
||||||
|
|
||||||
## Projet
|
## Project
|
||||||
|
|
||||||
- **Langage** : Rust 2024
|
- **Language**: Rust 2024
|
||||||
- **Dépendances** : wgpu 30, winit 0.30, glam (math)
|
- **Dependencies**: wgpu 30, winit 0.30, glam (math)
|
||||||
- **Pas publié sur crates.io** (dépendance par path)
|
- **Not published on crates.io** (path dependency)
|
||||||
- **Status** : MVP complet (phases 1-5 ✅), post-MVP en cours (phase 6)
|
- **Status**: MVP complete (phases 1-5 ✅), post-MVP in progress (phase 6)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Documentation détaillée (architecture, status, API reference, workflow manuel) : [README_DETAILS.md](README_DETAILS.md)*
|
*Detailed documentation (architecture, status, API reference, manual workflow): [README_DETAILS.md](README_DETAILS.md)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> This project was heavily developed using OpenCode, Pi Code, and JCode AI agents running on local Qwen3-27b_Q4 and DeepSeek V4 Flash Q4 instances. The project organization and architecture are the author's own design.
|
||||||
|
|||||||
+53
-36
@@ -1,6 +1,6 @@
|
|||||||
# WSG — Documentation détaillée
|
# WSG — Detailed Documentation
|
||||||
|
|
||||||
> Contenu technique du README principal : status, architecture, API reference, workflows, roadmap.
|
> Technical content from the main README: status, architecture, API reference, workflows, roadmap.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -9,14 +9,19 @@
|
|||||||
| Manual workflow (`Context` + `Renderer` + `PipelineCache`) | ✅ Working (advanced — fine-grained control) |
|
| Manual workflow (`Context` + `Renderer` + `PipelineCache`) | ✅ Working (advanced — fine-grained control) |
|
||||||
| `App` / `AppBuilder` / `AppHandler` event-loop facade | ✅ Working — window, events, frame presentation, automatic scene rendering |
|
| `App` / `AppBuilder` / `AppHandler` event-loop facade | ✅ Working — window, events, frame presentation, automatic scene rendering |
|
||||||
| `Scene` resource/entity registry | ✅ Working — auto-rendered in one batched pass (`App::render_scene`) |
|
| `Scene` resource/entity registry | ✅ Working — auto-rendered in one batched pass (`App::render_scene`) |
|
||||||
| GPU-driven two-pass pipeline (Compute → indirect draw) | ✅ Working (Phase 3) — `render_scene` + shadow pass 100 % indirect; opt-in frustum culling |
|
| GPU-driven two-pass pipeline (Compute → indirect draw) | ✅ Working (Phase 3) — `render_scene` + shadow pass 100% indirect; opt-in frustum culling |
|
||||||
| 3D infrastructure (uniform bind groups, MVP + camera) | ✅ Working — per-frame camera + per-entity world matrices in shared uniforms |
|
| 3D infrastructure (uniform bind groups, MVP + camera) | ✅ Working — per-frame camera + per-entity world matrices in shared uniforms |
|
||||||
| Shadows (shadow mapping) | ✅ Working — directional/spot, slope-scaled bias, PCF 3×3 |
|
| Shadows (shadow mapping) | ✅ Working — directional/spot, slope-scaled bias, PCF 3×3 |
|
||||||
| HDR + Tone Mapping | ✅ Working (Étape 20) — offscreen Rgba16Float, ACES/Reinhard, opt-in |
|
| HDR + Tone Mapping | ✅ Working — offscreen Rgba16Float, ACES/Reinhard, opt-in |
|
||||||
| LOD (Level of Detail) | ✅ Working (Étape 19) — quadric decimation, hysteresis, multi-level buffer |
|
| LOD (Level of Detail) | ✅ Working — quadric decimation, hysteresis, multi-level buffer |
|
||||||
| Mesh module (primitives + import) | ✅ Working (Étape 21) — feature-gated primitives, OBJ parser |
|
| Mesh module (primitives + import) | ✅ Working — feature-gated primitives, OBJ parser |
|
||||||
|
| Bloom | ✅ Working — threshold + separable blur + composite, HDR required |
|
||||||
|
| Fog | ✅ Working — 3 modes (linear, exp, exp²), runtime switchable |
|
||||||
|
| MSAA | ✅ Working — 4× multisample, resolve pass |
|
||||||
|
| DoF | ✅ Working — CoC + disc blur, focus presets |
|
||||||
|
| PBR (metallic/roughness + normal maps) | ✅ Working — Cook-Torrance, GGX, IBL, derivative tangent |
|
||||||
|
|
||||||
Note: `standard_shader.wgsl` (Phong, with an explicit **unlit** mode) is the **single** shader the library ships. Flat 2D drawing is its unlit variant (`Renderer::set_unlit(true)`).
|
Note: `standard_shader.wgsl` (Phong + PBR, with an explicit **unlit** mode) is the **single** shader the library ships. Flat 2D drawing is its unlit variant (`Renderer::set_unlit(true)`).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -37,28 +42,31 @@ Spec: [docs/tech/ARCHI_CPU_GPU.md](docs/tech/ARCHI_CPU_GPU.md) · User guide: [d
|
|||||||
```
|
```
|
||||||
lib/src/
|
lib/src/
|
||||||
├── lib.rs # crate root, re-exports
|
├── lib.rs # crate root, re-exports
|
||||||
├── prelude.rs # glob re-exports (types quotidiens)
|
├── prelude.rs # glob re-exports
|
||||||
├── app.rs # App + AppBuilder
|
├── app.rs # App + AppBuilder
|
||||||
├── handler.rs # AppHandler trait
|
├── handler.rs # AppHandler trait
|
||||||
|
├── camera.rs # Camera, CameraController
|
||||||
|
├── input.rs # InputState
|
||||||
|
├── lights.rs # Lights, Light, LightType, directional_light, …
|
||||||
├── core/
|
├── core/
|
||||||
│ ├── context.rs # GPU lifecycle (Instance/Surface/Adapter/Device/Queue)
|
│ ├── context.rs # GPU lifecycle (Instance/Surface/Adapter/Device/Queue)
|
||||||
│ ├── renderer.rs # RenderPass execution, shadow pass, HDR/TM pass
|
│ ├── renderer.rs # RenderPass execution, shadow pass, HDR/TM pass
|
||||||
│ ├── frame.rs # Per-frame RAII (surface texture + view)
|
│ ├── frame.rs # Per-frame RAII (surface texture + view)
|
||||||
│ ├── input.rs # Unified keyboard/mouse state
|
|
||||||
│ ├── geometry.rs # Geometry (positions/normals/UVs/indices) + BBox
|
│ ├── geometry.rs # Geometry (positions/normals/UVs/indices) + BBox
|
||||||
│ ├── transform.rs # Transform (translation/rotation/scale)
|
│ ├── transform.rs # Transform (translation/rotation/scale)
|
||||||
│ ├── frustum.rs # Frustum (6 planes, sphere/box culling)
|
│ ├── frustum.rs # Frustum (6 planes, sphere/box culling)
|
||||||
│ ├── lod.rs # LOD decimation (quadric edge collapse)
|
│ ├── lod.rs # LOD decimation (quadric edge collapse)
|
||||||
│ ├── shadow.rs # ShadowConfig (map size, bias, PCF)
|
│ ├── shadow.rs # ShadowConfig (map size, bias, PCF)
|
||||||
│ └── hdr.rs # ToneMapper enum (Aces/Reinhard)
|
│ ├── hdr.rs # ToneMapper enum (Aces/Reinhard)
|
||||||
|
│ ├── bloom.rs # BloomConfig + BloomPipeline
|
||||||
|
│ ├── msaa.rs # MsaaConfig
|
||||||
|
│ ├── fog.rs # FogConfig + FogMode
|
||||||
|
│ └── dof.rs # DoFConfig + DoFPipeline
|
||||||
├── mesh/
|
├── mesh/
|
||||||
│ ├── mod.rs # Re-exports flat
|
│ ├── mod.rs # Re-exports flat
|
||||||
│ ├── primitives/ # 6 feature-gated generators
|
│ ├── primitives/ # 6 feature-gated generators
|
||||||
│ └── import/ # OBJ parser + glTF stub
|
│ └── import/ # OBJ parser + glTF stub
|
||||||
├── pipeline/ # PipelineCache (shader → RenderPipeline)
|
├── pipeline/ # PipelineCache (shader → RenderPipeline)
|
||||||
├── camera/ # Camera, CameraController
|
|
||||||
├── lights/ # Lights, Light, LightType, directional_light, …
|
|
||||||
├── input/ # InputState
|
|
||||||
├── resources/ # Mesh, Material, Texture, Uniform, Vertex
|
├── resources/ # Mesh, Material, Texture, Uniform, Vertex
|
||||||
├── scene/ # Scene (registry), Entity
|
├── scene/ # Scene (registry), Entity
|
||||||
└── utils/ # Conf constants, WsgError
|
└── utils/ # Conf constants, WsgError
|
||||||
@@ -72,9 +80,9 @@ lib/src/
|
|||||||
| AppHandler | Trait | `setup()` / `update()` / `render()` callbacks |
|
| AppHandler | Trait | `setup()` / `update()` / `render()` callbacks |
|
||||||
| Scene | Struct | Registry: shaders, materials, meshes, entities, lights, camera |
|
| Scene | Struct | Registry: shaders, materials, meshes, entities, lights, camera |
|
||||||
| Context | Struct | GPU hardware (Instance, Surface, Adapter, Device, Queue) |
|
| Context | Struct | GPU hardware (Instance, Surface, Adapter, Device, Queue) |
|
||||||
| Renderer | Struct | RenderPass execution (scene, shadow, HDR/TM) |
|
| Renderer | Struct | RenderPass execution (scene, shadow, HDR/TM, bloom, DoF) |
|
||||||
| PipelineCache | Struct | Shader → compiled RenderPipeline cache |
|
| PipelineCache | Struct | Shader → compiled RenderPipeline cache |
|
||||||
| Material | Struct | Shader ID + texture + pipeline |
|
| Material | Struct | Shader ID + texture + pipeline + PBR params |
|
||||||
| Geometry | Struct | CPU vertex data (positions/normals/UVs/colors/indices) |
|
| Geometry | Struct | CPU vertex data (positions/normals/UVs/colors/indices) |
|
||||||
| Mesh / Vertex | Struct | GPU geometry / interleaved upload tuple |
|
| Mesh / Vertex | Struct | GPU geometry / interleaved upload tuple |
|
||||||
| Frame | Struct | Per-frame RAII (surface texture + view) |
|
| Frame | Struct | Per-frame RAII (surface texture + view) |
|
||||||
@@ -85,6 +93,10 @@ lib/src/
|
|||||||
| Lights / Light | Struct | Light list (directional/point/spot, MAX=8) + ambient |
|
| Lights / Light | Struct | Light list (directional/point/spot, MAX=8) + ambient |
|
||||||
| ShadowConfig | Struct | Shadow map size, bias, PCF taps, scene radius |
|
| ShadowConfig | Struct | Shadow map size, bias, PCF taps, scene radius |
|
||||||
| ToneMapper | Enum | ACES Filmic / Reinhard |
|
| ToneMapper | Enum | ACES Filmic / Reinhard |
|
||||||
|
| BloomConfig | Struct | Threshold, intensity, H/V passes |
|
||||||
|
| MsaaConfig | Struct | Sample count (1 = disabled) |
|
||||||
|
| FogConfig | Struct | Mode, near/far, density, color |
|
||||||
|
| DoFConfig | Struct | Focus distance, aperture, max blur |
|
||||||
| BBox | Struct | Axis-aligned bounding box (min/max) |
|
| BBox | Struct | Axis-aligned bounding box (min/max) |
|
||||||
| Frustum | Struct | 6 planes, sphere/box culling |
|
| Frustum | Struct | 6 planes, sphere/box culling |
|
||||||
|
|
||||||
@@ -95,14 +107,14 @@ use wsg_lib::prelude::*;
|
|||||||
use wsg_lib::app::AppBuilder;
|
use wsg_lib::app::AppBuilder;
|
||||||
use wsg_lib::utils::WsgError;
|
use wsg_lib::utils::WsgError;
|
||||||
|
|
||||||
struct MaScene;
|
struct MyScene;
|
||||||
|
|
||||||
impl AppHandler for MaScene {
|
impl AppHandler for MyScene {
|
||||||
fn setup(&mut self, app: &mut wsg_lib::App) {
|
fn setup(&mut self, app: &mut wsg_lib::App) {
|
||||||
app.scene
|
app.scene
|
||||||
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
|
.register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
app.scene.create_material("mat", "standard", None).unwrap();
|
app.scene.add_material_shader("mat", "standard").unwrap();
|
||||||
app.scene.create_mesh("cube", cube(1.0), Some("mat")).unwrap();
|
app.scene.create_mesh("cube", cube(1.0), Some("mat")).unwrap();
|
||||||
app.scene.add_entity("my_cube", "cube").unwrap();
|
app.scene.add_entity("my_cube", "cube").unwrap();
|
||||||
}
|
}
|
||||||
@@ -112,9 +124,10 @@ impl AppHandler for MaScene {
|
|||||||
// render() default: app.render_scene(frame.view()) — auto-draws everything
|
// render() default: app.render_scene(frame.view()) — auto-draws everything
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), WsgError> {
|
#[pollster::main]
|
||||||
let app = AppBuilder::new().title("WSG").build()?;
|
async fn main() -> Result<(), WsgError> {
|
||||||
app.run(MaScene);
|
let app = AppBuilder::new().title("WSG").build().await?;
|
||||||
|
app.run(MyScene);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -167,15 +180,15 @@ fn main() {
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
| Feature | Default | Fournit |
|
| Feature | Default | Provides |
|
||||||
|---------|---------|---------|
|
|---------|---------|----------|
|
||||||
| `prim-cube` | ✅ | `cube(size)` |
|
| `prim-cube` | ✅ | `cube(size)` |
|
||||||
| `prim-plane` | ✅ | `plane(w, d, seg_x, seg_z)` |
|
| `prim-plane` | ✅ | `plane(w, d, seg_x, seg_z)` |
|
||||||
| `prim-sphere` | ✅ | `uv_sphere(…)`, `icosphere(…)` |
|
| `prim-sphere` | ✅ | `uv_sphere(…)`, `icosphere(…)` |
|
||||||
| `prim-cylinder` | ✅ | `cylinder(…)` |
|
| `prim-cylinder` | ✅ | `cylinder(…)` |
|
||||||
| `prim-cone` | ✅ | `cone(…)` |
|
| `prim-cone` | ✅ | `cone(…)` |
|
||||||
| `prim-torus` | ✅ | `torus(…)` |
|
| `prim-torus` | ✅ | `torus(…)` |
|
||||||
| `all-prims` | ✅ (default) | Les 6 primitives |
|
| `all-prims` | ✅ (default) | All 6 primitives |
|
||||||
| `import-obj` | ⬜ | `load_obj(path)`, `parse_obj(str)` |
|
| `import-obj` | ⬜ | `load_obj(path)`, `parse_obj(str)` |
|
||||||
| `import-gltf` | ⬜ | `load_gltf(path)` (stub) |
|
| `import-gltf` | ⬜ | `load_gltf(path)` (stub) |
|
||||||
|
|
||||||
@@ -185,6 +198,10 @@ fn main() {
|
|||||||
|---------|--------------|----------------|
|
|---------|--------------|----------------|
|
||||||
| Shadows | `scene.set_shadow_caster(Some(idx))` | No shadow map, no depth pass, no PCF |
|
| Shadows | `scene.set_shadow_caster(Some(idx))` | No shadow map, no depth pass, no PCF |
|
||||||
| HDR + TM | `AppBuilder::with_hdr(ToneMapper::Aces)` | No offscreen texture, no TM pass |
|
| HDR + TM | `AppBuilder::with_hdr(ToneMapper::Aces)` | No offscreen texture, no TM pass |
|
||||||
|
| Bloom | `AppBuilder::with_bloom(BloomConfig::…)` | No bloom textures, no passes |
|
||||||
|
| MSAA | `AppBuilder::with_msaa(MsaaConfig { sample_count: 4 })` | Single sample, no resolve |
|
||||||
|
| Fog | `AppBuilder::with_fog(FogConfig::…)` | No fog uniforms |
|
||||||
|
| DoF | `AppBuilder::with_dof(DoFConfig::…)` | No CoC/blur textures |
|
||||||
| GPU-driven culling | `AppBuilder::with_gpu_driven(true)` | No compute pipeline, no indirect buffers |
|
| GPU-driven culling | `AppBuilder::with_gpu_driven(true)` | No compute pipeline, no indirect buffers |
|
||||||
| LOD | `scene.create_mesh_with_lod(…, levels)` | Single-level mesh |
|
| LOD | `scene.create_mesh_with_lod(…, levels)` | Single-level mesh |
|
||||||
| Primitives | Cargo feature `prim-*` | Not compiled |
|
| Primitives | Cargo feature `prim-*` | Not compiled |
|
||||||
@@ -194,19 +211,19 @@ fn main() {
|
|||||||
|
|
||||||
| Phase | Status |
|
| Phase | Status |
|
||||||
|-------|--------|
|
|-------|--------|
|
||||||
| 1 — Fondations (window, render loop, Context) | ✅ |
|
| 1 — Foundations (window, render loop, Context) | ✅ |
|
||||||
| 2 — Infrastructure 3D (Geometry, Mesh, Material, Pipeline) | ✅ |
|
| 2 — 3D infrastructure (Geometry, Mesh, Material, Pipeline) | ✅ |
|
||||||
| 3 — GPU-driven (compute pass, indirect draws, culling) | ✅ |
|
| 3 — GPU-driven (compute pass, indirect draws, culling) | ✅ |
|
||||||
| 4 — Rendu avancé (shadows, HDR/TM, lights) | ✅ |
|
| 4 — Advanced rendering (shadows, HDR/TM, lights) | ✅ |
|
||||||
| 5 — Polissage (LOD, camera controller, input, demo) | ✅ |
|
| 5 — Polish (LOD, camera controller, input, demo) | ✅ |
|
||||||
| 6 — Post-MVP (bloom, PBR, cascaded shadows, SSAO, refactoring) | 🔄 |
|
| 6 — Post-MVP (bloom, PBR, fog, DoF, MSAA, cascaded shadows, SSAO) | 🔄 |
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
| Où | Quoi |
|
| Where | What |
|
||||||
|----|------|
|
|-------|------|
|
||||||
| [docs/user/](docs/user/README.md) | Guide utilisateur (EN) |
|
| [docs/user/](docs/user/README.md) | User guide |
|
||||||
| [docs/tech/](docs/tech/ARCHI_APP.md) | Architecture interne (FR) |
|
| [docs/tech/](docs/tech/ARCHI_APP.md) | Internal architecture |
|
||||||
| [docs/ROADMAP.md](docs/ROADMAP.md) | Feuille de route |
|
| [docs/ROADMAP.md](docs/ROADMAP.md) | Roadmap |
|
||||||
| [docs/PLAN.md](docs/PLAN.md) | Livre de recette (historique) |
|
| [docs/PLAN.md](docs/PLAN.md) | Recipe book (step history) |
|
||||||
| `cargo doc -p wsg-lib --no-deps` | Référence API (rustdoc) |
|
| `cargo doc -p wsg-lib --no-deps` | API reference (rustdoc) |
|
||||||
|
|||||||
+206
-207
@@ -1,341 +1,340 @@
|
|||||||
# Exemples WSG
|
# WSG Examples
|
||||||
|
|
||||||
Chaque exemple est autonome et illustre **un effet ou une fonctionnalité** spécifique
|
Each example is self-contained and demonstrates **one effect or feature** of the library. All use the declarative API (`AppBuilder` + `AppHandler`).
|
||||||
de la bibliothèque. Tous utilisent l'API déclarative (`AppBuilder` + `AppHandler`).
|
|
||||||
|
|
||||||
## Lancer un exemple
|
## Running an example
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example <nom>
|
cargo run -p wsg-lib --example <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
| Exemple | Effet démontré |
|
| Example | Effect demonstrated |
|
||||||
|---------|---------------|
|
|---------|-------------------|
|
||||||
| `demo` | Showcase complet (tous les effets combinés) |
|
| `demo` | Full showcase (all effects combined) |
|
||||||
| `bloom` | Post-process bloom (glow autour des zones brillantes) |
|
| `bloom` | Post-process bloom (glow around bright areas) |
|
||||||
| `hdr` | HDR + Tone Mapping (ACES) + contrôle d'exposition |
|
| `hdr` | HDR + Tone Mapping (ACES) + exposure control |
|
||||||
| `emissive` | Matériaux émissifs (intensités croissantes 0 → 4.0) |
|
| `emissive` | Emissive materials (increasing intensities 0 → 4.0) |
|
||||||
| `shadow` | Shadow mapping (ombre portée directionnelle) |
|
| `shadow` | Shadow mapping (directional shadow) |
|
||||||
| `culling` | Culling GPU-driven (grille 15×15, objets hors frustum ignorés) |
|
| `culling` | GPU-driven culling (15×15 grid, off-frustum objects skipped) |
|
||||||
| `msaa` | MSAA 4× (anti-aliasing multi-échantillons, arêtes lisses) |
|
| `msaa` | MSAA 4× (multisample anti-aliasing, smooth edges) |
|
||||||
| `fog` | Brouillard de distance (3 modes : linéaire, exp, exp²) |
|
| `fog` | Distance fog (3 modes: linear, exp, exp²) |
|
||||||
| `manual` | Workflow bas niveau (Context + Renderer + PipelineCache) |
|
| `dof` | Depth of Field (cinematic bokeh, focus presets) |
|
||||||
| `import` | Import de fichier OBJ (non graphique, stdout) |
|
| `pbr` | PBR metallic/roughness + normal mapping |
|
||||||
|
| `manual` | Low-level workflow (Context + Renderer + PipelineCache) |
|
||||||
|
| `import` | OBJ file import (non-graphical, stdout) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `demo` — Showcase complet
|
## `demo` — Full Showcase
|
||||||
|
|
||||||
Combine **tous** les effets : primitives LOD, textures procédurales, lumières
|
Combines **all** effects: LOD primitives, procedural textures, lights
|
||||||
(directional + point + spot), ombres, HDR/ACES, exposition, émissif, bloom, culling.
|
(directional + point + spot), shadows, HDR/ACES, exposure, emissive, bloom, culling.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example demo
|
cargo run -p wsg-lib --example demo
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `1` / `2` / `3` | Presets : face / côté / dessus |
|
| `1` / `2` / `3` | Presets: front / side / top |
|
||||||
| `+` / `-` | Exposition ×1.3 / ÷1.3 |
|
| `+` / `-` | Exposure ×1.3 / ÷1.3 |
|
||||||
| `0` | Reset exposition |
|
| `0` | Reset exposure |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `bloom` — Post-process Bloom
|
## `bloom` — Post-process Bloom
|
||||||
|
|
||||||
Deux sphères émissives (orange intensité 2.0, bleue intensité 3.0) produisent un
|
Two emissive spheres (orange intensity 2.0, blue intensity 3.0) produce a visible
|
||||||
halo visible. Le cube et le sol servent de référence (non-émissifs).
|
halo. The cube and floor serve as reference (non-emissive).
|
||||||
|
|
||||||
Le bloom est un pipeline 4 passes GPU : threshold → blur H → blur V → composite.
|
Bloom is a 4-pass GPU pipeline: threshold → blur H → blur V → composite.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example bloom
|
cargo run -p wsg-lib --example bloom
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `+` / `-` | **Bloom threshold** +0.1 / −0.1 |
|
| `+` / `-` | **Bloom threshold** +0.1 / −0.1 |
|
||||||
| `[` / `]` | **Bloom intensity** +0.1 / −0.1 |
|
| `[` / `]` | **Bloom intensity** +0.1 / −0.1 |
|
||||||
| `I` / `O` | **Bloom radius** +0.5 / −0.5 |
|
| `I` / `O` | **Bloom radius** +0.5 / −0.5 |
|
||||||
| `E` / `Q` | Exposition ×1.3 / ÷1.3 |
|
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||||
| `0` | Reset exposition |
|
| `0` | Reset exposure |
|
||||||
|
|
||||||
### Ce qu'on voit
|
### What to observe
|
||||||
|
|
||||||
- **threshold bas** (0.0) : tout l'image "bloom" (effet très diffus).
|
- **Low threshold** (0.0): the entire image "blooms" (very diffuse effect).
|
||||||
- **threshold élevé** (2.0+) : seules les sphères émissives brillantes produisent du glow.
|
- **High threshold** (2.0+): only the bright emissive spheres produce glow.
|
||||||
- **intensity 0.0** : pas de glow visible (même si le threshold extrait des pixels).
|
- **Intensity 0.0**: no visible glow (even though the threshold extracts pixels).
|
||||||
- **radius grand** (10+) : le glow s'étend sur une grande zone.
|
- **Large radius** (10+): the glow spreads over a large area.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `hdr` — HDR + Tone Mapping
|
## `hdr` — HDR + Tone Mapping
|
||||||
|
|
||||||
Démontre le rendu HDR avec la courbe ACES Filmic. Trois objets :
|
Demonstrates HDR rendering with the ACES Filmic curve. Three objects:
|
||||||
|
|
||||||
- **Cube** : éclairage normal (aucun émissif) — référence LDR.
|
- **Cube**: normal lighting (no emissive) — LDR reference.
|
||||||
- **Sphère brillante** (émissif 3.0) : sans HDR, elle serait clampée à blanc.
|
- **Bright sphere** (emissive 3.0): without HDR, it would be clamped to white.
|
||||||
Avec ACES, les highlights "roulent" doucement vers le blanc (rolloff).
|
With ACES, highlights "roll off" smoothly toward white.
|
||||||
- **Sphère sombre** (émissif 0.3) : reste sombre même à haute exposition.
|
- **Dark sphere** (emissive 0.3): stays dark even at high exposure.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example hdr
|
cargo run -p wsg-lib --example hdr
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `E` | **Exposition ×1.3** (plus clair) |
|
| `E` | **Exposure ×1.3** (brighter) |
|
||||||
| `Q` | **Exposition ÷1.3** (plus sombre) |
|
| `Q` | **Exposure ÷1.3** (darker) |
|
||||||
| `0` | Reset exposition à 1.0 |
|
| `0` | Reset exposure to 1.0 |
|
||||||
|
|
||||||
### Ce qu'on voit
|
### What to observe
|
||||||
|
|
||||||
- À exposition 1.0 : la sphère brillante est blanche mais avec des détails (rolloff ACES).
|
- At exposure 1.0: the bright sphere is white but with detail (ACES rolloff).
|
||||||
- À exposition haute (E×E×E) : la scène s'éclaircit, la sphère brillante reste blanche
|
- At high exposure (E×E×E): the scene brightens, the bright sphere stays white
|
||||||
(saturée), mais le cube gagne en détail.
|
(saturated), but the cube gains detail.
|
||||||
- À exposition basse (Q×Q) : tout s'assombrit, la sphère brillante devient orangée
|
- At low exposure (Q×Q): everything darkens, the bright sphere becomes orange
|
||||||
(les valeurs HDR > 1.0 sont compressées).
|
(HDR values > 1.0 are compressed).
|
||||||
|
|
||||||
> **Note** : le tone mapper est compilé dans le pipeline au build. Pour comparer
|
> **Note**: the tone mapper is compiled into the pipeline at build time. To compare
|
||||||
> ACES vs Reinhard, modifier `ToneMapper::Aces` → `ToneMapper::Reinhard` dans le source.
|
> ACES vs Reinhard, change `ToneMapper::Aces` → `ToneMapper::Reinhard` in the source.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `emissive` — Matériaux Émissifs
|
## `emissive` — Emissive Materials
|
||||||
|
|
||||||
Cinq sphères alignées avec des intensités émissives croissantes :
|
Five spheres in a row with increasing emissive intensities:
|
||||||
|
|
||||||
| Sphere | Couleur | Intensité | Effet |
|
| Sphere | Color | Intensity | Effect |
|
||||||
|--------|---------|-----------|-------|
|
|--------|-------|-----------|--------|
|
||||||
| 1 | Gris | 0.0 | Aucune glow (référence) |
|
| 1 | Gray | 0.0 | No glow (reference) |
|
||||||
| 2 | Orange | 0.5 | Légère lueur |
|
| 2 | Orange | 0.5 | Slight glow |
|
||||||
| 3 | Jaune | 1.0 | Lueur visible |
|
| 3 | Yellow | 1.0 | Visible glow |
|
||||||
| 4 | Vert | 2.0 | Glow HDR (au-delà de 1.0) |
|
| 4 | Green | 2.0 | HDR glow (beyond 1.0) |
|
||||||
| 5 | Bleu | 4.0 | Glow intense (saturation) |
|
| 5 | Blue | 4.0 | Intense glow (saturation) |
|
||||||
|
|
||||||
Avec HDR, les intensités > 1.0 produisent un vrai "glow" (les valeurs dépassent
|
With HDR, intensities > 1.0 produce a true "glow" (values exceed
|
||||||
[0,1] en espace linéaire). Sans HDR, elles seraient clampées à blanc.
|
[0,1] in linear space). Without HDR, they would be clamped to white.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example emissive
|
cargo run -p wsg-lib --example emissive
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `E` / `Q` | Exposition ×1.3 / ÷1.3 |
|
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||||
| `0` | Reset exposition |
|
| `0` | Reset exposure |
|
||||||
| `C` | **Cycler le multiplicateur d'émissif** (1× → 2× → 0.5× → ...) |
|
| `C` | **Cycle emissive multiplier** (1× → 2× → 0.5× → ...) |
|
||||||
|
|
||||||
### Ce qu'on voit
|
### What to observe
|
||||||
|
|
||||||
- La sphère 1 (intensité 0) est simplement éclairée par la lumière directionnelle.
|
- Sphere 1 (intensity 0) is simply lit by the directional light.
|
||||||
- Les sphères 2-5 brillent de leur propre lumière, indépendamment de l'éclairage.
|
- Spheres 2-5 glow with their own light, independent of scene lighting.
|
||||||
- `C` double ou réduit toutes les intensités en même temps (pour voir l'effet HDR).
|
- `C` doubles or halves all intensities simultaneously (to see the HDR effect).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `shadow` — Shadow Mapping
|
## `shadow` — Shadow Mapping
|
||||||
|
|
||||||
Quatre objets (cube, sphère, cône, cylindre) sur un sol, éclairés par une lumière
|
Four objects (cube, sphere, cone, cylinder) on a floor, lit by a directional light
|
||||||
directionnelle qui projette des ombres. La qualité des ombres est contrôlée par
|
that casts shadows. Shadow quality is controlled by `ShadowConfig` (map size, anti-acne bias).
|
||||||
`ShadowConfig` (taille de la shadow map, biais anti-acne).
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example shadow
|
cargo run -p wsg-lib --example shadow
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `1` | Vue de face |
|
| `1` | Front view |
|
||||||
| `2` | Vue de côté |
|
| `2` | Side view |
|
||||||
| `3` | **Vue de dessus** (voir la forme des ombres clairement) |
|
| `3` | **Top view** (see shadow shapes clearly) |
|
||||||
| `L` | Changer la direction de la lumière (3 presets) |
|
| `L` | Change light direction (3 presets) |
|
||||||
|
|
||||||
### Ce qu'on voit
|
### What to observe
|
||||||
|
|
||||||
- Le cube tourne lentement → son ombre bouge sur le sol.
|
- The cube rotates slowly → its shadow moves on the floor.
|
||||||
- La sphère a une transition ombre/lumière douce (terminateur lisse).
|
- The sphere has a smooth shadow/light transition (soft terminator).
|
||||||
- Le cône produit une ombre triangulaire distincte.
|
- The cone produces a distinct triangular shadow.
|
||||||
- En vue de dessus (`3`), on voit la forme exacte des ombres projetées.
|
- In top view (`3`), you see the exact shape of projected shadows.
|
||||||
- La taille de la shadow map (1024 par défaut) détermine la résolution :
|
- Shadow map size (1024 default) determines resolution:
|
||||||
modifier `SHADOW_MAP_SIZE` en haut du fichier pour tester 256 (pixelisé) ou 2048 (net).
|
modify `SHADOW_MAP_SIZE` at the top of the file to test 256 (pixelated) or 2048 (sharp).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `culling` — GPU Frustum Culling
|
## `culling` — GPU Frustum Culling
|
||||||
|
|
||||||
Une grille de **15×15 = 225 cubes** est placée sur un grand sol. Le culling
|
A grid of **15×15 = 225 cubes** is placed on a large floor. The GPU-driven culling
|
||||||
GPU-driven (compute shader) détermine quels cubes sont visibles dans le frustum
|
(compute shader) determines which cubes are visible in the camera frustum and zeros
|
||||||
de la caméra et zéro leurs draw args indirects — **zéro coût CPU**.
|
their indirect draw args — **zero CPU cost**.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example culling
|
cargo run -p wsg-lib --example culling
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra (regarder autour) |
|
| Drag (LMB) | Orbit camera (look around) |
|
||||||
| Molette | Zoom in/out |
|
| Wheel | Zoom in/out |
|
||||||
| `R` | Reset (vue de dessus) |
|
| `R` | Reset (top view) |
|
||||||
| `1` | Vue de face (les cubes derrière sont culled) |
|
| `1` | Front view (cubes behind are culled) |
|
||||||
| `2` | Vue de côté |
|
| `2` | Side view |
|
||||||
| `3` | **Vue de dessus** (voir toute la grille) |
|
| `3` | **Top view** (see the full grid) |
|
||||||
|
|
||||||
### Ce qu'on voit
|
### What to observe
|
||||||
|
|
||||||
- En vue de dessus (`3`) : toute la grille 20×20 est visible.
|
- In top view (`3`): the entire grid is visible.
|
||||||
- Orbiter à 90° : les cubes derrière la caméra **ne sont pas dessinés** (culled).
|
- Orbit to 90°: cubes behind the camera **are not drawn** (culled).
|
||||||
- Zoomer très près : seuls les cubes proches du plan de near sont rendus.
|
- Zoom very close: only cubes near the near plane are rendered.
|
||||||
- Les cubes tournent lentement (phases décalées) → le culling est dynamique
|
- Cubes rotate slowly (staggered phases) → culling is dynamic
|
||||||
(un cube peut entrer/sortir du frustum au cours d'une frame).
|
(a cube can enter/leave the frustum during a frame).
|
||||||
|
|
||||||
> **Note** : le culling est activé via `AppBuilder::with_culling(true)`. Le modifier
|
> **Note**: culling is enabled via `AppBuilder::with_culling(true)`. Changing
|
||||||
> à `false` dans le source désactive le culling (tous les 400 cubes sont toujours
|
> it to `false` in the source disables culling (all cubes are always drawn, even off-screen).
|
||||||
> dessinés, même hors écran).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `msaa` — MSAA 4× (Anti-aliasing)
|
## `msaa` — MSAA 4× (Anti-aliasing)
|
||||||
|
|
||||||
Démontre l'anti-aliasing multi-échantillons : les arêtes des objets (cube, sphère)
|
Demonstrates multisample anti-aliasing: object edges (cube, sphere)
|
||||||
sont lisses au lieu d'être "en escalier". La scène contient un cube (arêtes nettes),
|
are smooth instead of "stair-stepped". The scene contains a cube (sharp edges),
|
||||||
une sphère (silhouette courbe) et un petit cube près de la caméra (aliasing maximal).
|
a sphere (curved silhouette), and a small cube near the camera (maximum aliasing).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example msaa
|
cargo run -p wsg-lib --example msaa
|
||||||
```
|
```
|
||||||
|
|
||||||
### Touches
|
### Keys
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Glisser (LMB) | Orbiter la caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
| `M` | Afficher le nombre d'échantillons |
|
| `M` | Show sample count |
|
||||||
|
|
||||||
### Pour comparer avec/sans MSAA
|
### To compare with/without MSAA
|
||||||
|
|
||||||
Supprimer la ligne `.with_msaa(4)` dans le source et recompiler : la scène est
|
Remove the `.with_msaa(4)` line in the source and recompile: the scene is
|
||||||
identique, seules les arêtes diffèrent (escaler vs lisse).
|
identical, only the edges differ (stair-stepped vs smooth).
|
||||||
|
|
||||||
> **Note** : MSAA est un réglage de build-time (allocation de textures multi-échantillons).
|
> **Note**: MSAA is a build-time setting (multisample texture allocation).
|
||||||
> Il fonctionne indépendamment de HDR : avec HDR, la texture MSAA est `Rgba16Float`
|
> It works independently of HDR: with HDR, the MSAA texture is `Rgba16Float`
|
||||||
> et résout dans la texture HDR avant bloom/TM.
|
> and resolves into the HDR texture before bloom/TM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `fog` — Brouillard de distance
|
## `fog` — Distance Fog
|
||||||
|
|
||||||
Démontre les 3 modes de brouillard : **linéaire**, **exponentiel**, **exponentiel²**.
|
Demonstrates the 3 fog modes: **linear**, **exponential**, **exponential²**.
|
||||||
La scène contient une rangée de cubes qui s'éloignent et des sphères dispersées sur
|
The scene contains a row of cubes receding into the distance and scattered spheres
|
||||||
un grand plan au sol. Le brouillard fond les objets vers une couleur de fond,
|
on a large floor plane. Fog blends objects toward a background color,
|
||||||
créant l'illusion d'un monde infini.
|
creating the illusion of an infinite world.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example fog --features "all-prims"
|
cargo run -p wsg-lib --example fog --features "all-prims"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Touches** : `1` = linéaire, `2` = exp, `3` = exp², `4` = désactivé, `R` = reset.
|
**Keys**: `1` = linear, `2` = exp, `3` = exp², `4` = off, `R` = reset.
|
||||||
|
|
||||||
> Le brouillard est appliqué dans le shader fragment principal (après l'éclairage,
|
> Fog is applied in the main fragment shader (after lighting, before tone mapping).
|
||||||
> avant le tone mapping). Il utilise la distance euclidienne du fragment à la caméra.
|
> It uses the Euclidean distance from the fragment to the camera.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `dof` — Depth of Field (bokeh cinématique)
|
## `dof` — Depth of Field (cinematic bokeh)
|
||||||
|
|
||||||
Démontre le flou de profondeur de champ : un objet au centre reste net tandis que
|
Demonstrates depth of field blur: an object at the focus plane stays sharp while
|
||||||
le premier et arrière-plan se flouent selon leur distance au plan de mise au point.
|
foreground and background blur according to their distance from the focus plane.
|
||||||
Crée un effet d'attention naturelle (type cinématique).
|
Creates a natural attention effect (cinematic style).
|
||||||
|
|
||||||
La scène contient un cube de focus au centre, des sphères en premier plan (proches)
|
The scene contains 20 cubes in a row along Z (z=3 to z=-25.5) and 5 spheres to the
|
||||||
et des cubes en arrière-plan (loin), sur un plan au sol.
|
sides, on a floor plane. Focus presets at 3m / 8m / 15m.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example dof --features "all-prims"
|
cargo run -p wsg-lib --example dof --features "all-prims"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Touches** : `1` = cinématique, `2` = subtil, `3` = focus 2m, `4` = focus 10m, `5` = off, `R` = reset.
|
**Keys**: `1` = cinematic, `2` = subtle, `3` = focus 3m, `4` = focus 15m, `5` = off, `R` = reset.
|
||||||
|
|
||||||
> DoF opère en HDR linéaire (après bloom, avant tone mapping). Deux passes :
|
> DoF operates in linear HDR (after bloom, before tone mapping). Two passes:
|
||||||
> CoC (depth → rayon de flou par pixel) puis blur disque 12-taps à rayon variable.
|
> CoC (depth → per-pixel blur radius) then 12-tap disc blur with variable radius.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `manual` — Workflow bas niveau
|
## `pbr` — PBR Metallic/Roughness + Normal Mapping
|
||||||
|
|
||||||
Démontre l'API **sans** la façade `App` : utilisation directe de `Context`,
|
Demonstrates the Cook-Torrance PBR workflow: GGX distribution + Smith geometry +
|
||||||
`Renderer`, `PipelineCache`, `Mesh`, `Material`. Rend un quad coloré (unlit).
|
Schlick Fresnel + hemispheric IBL + normal mapping.
|
||||||
|
|
||||||
Utile pour comprendre ce que la façade `App` encapsule.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo run -p wsg-lib --example manual
|
|
||||||
```
|
|
||||||
|
|
||||||
Pas de touches — rendu statique (quad unlit, 4 couleurs).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## `import` — Import de fichier OBJ
|
|
||||||
|
|
||||||
Exemple **non graphique** : parse un fichier `.obj` et affiche les statistiques
|
|
||||||
(nombre de sommets, normales, UVs, indices, bounding box) sur stdout.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Avec un fichier :
|
|
||||||
cargo run -p wsg-lib --example import --features import-obj -- /path/to/model.obj
|
|
||||||
|
|
||||||
# Sans argument (triangle de démonstration) :
|
|
||||||
cargo run -p wsg-lib --example import --features import-obj
|
|
||||||
```
|
|
||||||
|
|
||||||
Pas de touches — s'exécute et quitte.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## `pbr` — PBR Metallic/Roughness + Normal Mapping (Étape 27)
|
|
||||||
|
|
||||||
Démonstration du workflow PBR Cook-Torrance : GGX distribution + Smith visibility +
|
|
||||||
Schlick Fresnel + IBL hémisphérique + normal mapping.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -p wsg-lib --example pbr
|
cargo run -p wsg-lib --example pbr
|
||||||
```
|
```
|
||||||
|
|
||||||
| Touche | Action |
|
| Key | Action |
|
||||||
|--------|--------|
|
|-----|--------|
|
||||||
| Drag (LMB) | Orbite caméra |
|
| Drag (LMB) | Orbit camera |
|
||||||
| Molette | Zoom |
|
| Wheel | Zoom |
|
||||||
| `R` | Reset caméra |
|
| `R` | Reset camera |
|
||||||
|
|
||||||
Scène : 6 matériaux PBR (métal miroir, plastique, rouillé, céramique, bump map, sol matte).
|
Scene: 6 PBR materials (mirror metal, smooth plastic, rusty metal, ceramic, bump map, matte floor).
|
||||||
Le cube avec normal map montre des bumps procéduraux (sin wave).
|
The bump-map cube shows procedural sin-wave surface detail.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `manual` — Low-level Workflow
|
||||||
|
|
||||||
|
Demonstrates the API **without** the `App` facade: direct use of `Context`,
|
||||||
|
`Renderer`, `PipelineCache`, `Mesh`, `Material`. Renders a colored quad (unlit).
|
||||||
|
|
||||||
|
Useful for understanding what the `App` facade encapsulates.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run -p wsg-lib --example manual
|
||||||
|
```
|
||||||
|
|
||||||
|
No keys — static render (unlit quad, 4 colors).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `import` — OBJ File Import
|
||||||
|
|
||||||
|
**Non-graphical** example: parses a `.obj` file and prints statistics
|
||||||
|
(vertex count, normals, UVs, indices, bounding box) to stdout.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# With a file:
|
||||||
|
cargo run -p wsg-lib --example import --features import-obj -- /path/to/model.obj
|
||||||
|
|
||||||
|
# Without argument (demo triangle):
|
||||||
|
cargo run -p wsg-lib --example import --features import-obj
|
||||||
|
```
|
||||||
|
|
||||||
|
No keys — runs and exits.
|
||||||
|
|||||||
Reference in New Issue
Block a user