correction orbital camera inputs
This commit is contained in:
@@ -2,6 +2,18 @@
|
||||
|
||||
> Étape 16 (Phase 5 — Documentation & Polish) **terminée** le 2026-07-19.
|
||||
>
|
||||
> **Tuning caméra 2026-07-19** — sur rétroaction utilisateur (caméra trop sensible, orbit permanent) :
|
||||
> (1) `CameraController` a gagné deux champs configurables `orbit_sensitivity`/`zoom_factor` (defaults : 0.01→0.005
|
||||
> rad/px, 0.9/tic) ; (2) `InputState` normalise `PixelDelta`/32 en unités « notch » (le Wayland renvoyait ~100 px/tic,
|
||||
> donc `0.9^100` → zoom au clamping en un geste) ; (3) le `demo` orbite désormais **sur clic gauche enfoncé** (arc-rotate
|
||||
> classique). Docs `camera-input.md`/`examples.md` mises à jour. 51 tests OK.
|
||||
>
|
||||
> **Bug fix 2026-07-19** — `InputState::begin_frame()` remettait à zéro `mouse_delta`/`scroll` AVANT que
|
||||
> `update()` ne les lise, alors que les événements winit (CursorMoved/MouseWheel) s'accumulent ENTRE deux
|
||||
> frames. Résultat : la caméra orbitale du `demo` ne bougeait jamais (souris/molette toujours (0,0) dans
|
||||
> `update`). Corrigé par rotation des accumulateurs (`frame_mouse_delta`/`frame_scroll` → queryables à
|
||||
> `begin_frame`), aligné sur le pattern clavier/boutons. Tests mis à jour (ordre réel winit) + 45/50 tests OK.
|
||||
>
|
||||
> Traduction anglaise de toute la documentation (hors `docs/tech/`, DRAFT/PLAN/ROADMAP) **terminée** le 2026-07-19 :
|
||||
> `docs/user/*`, `README.md`, READMEs de modules, doc/rustdoc de tous les `.rs` (src + examples + tests),
|
||||
> `Étape`→`Step` global. Vérifications : 50 tests OK, `cargo fmt` clean, aucun lien cassé, 0 accent restant hors zone franche.
|
||||
|
||||
@@ -49,6 +49,13 @@ ctrl.apply_to(app.scene.camera_mut()); // write the framing into the active cam
|
||||
`CameraController::from_camera(&cam)` rebuilds a controller from an existing camera
|
||||
(useful to start the orbit from a manual framing).
|
||||
|
||||
Two public fields tune the feel of the camera (defaults in parentheses):
|
||||
|
||||
| Field | Meaning | Default |
|
||||
|-------|---------|---------|
|
||||
| `orbit_sensitivity` | radians of yaw per pixel of mouse delta | `0.005` (~110° per full window width) |
|
||||
| `zoom_factor` | multiplicative distance change per wheel notch (`distance *= factor^scroll`) | `0.9` (10% per notch) |
|
||||
|
||||
The exact wiring snippet (orbit + zoom + reset + `1`/`2`/`3` presets, driven from
|
||||
`app.input`) is in [`demo.rs`](../../lib/examples/demo.rs), `update()` section.
|
||||
|
||||
@@ -64,7 +71,13 @@ every frame (`begin_frame`/`end_frame` around your `update`). Three semantics pe
|
||||
| **released** | `key_released(code)`, `mouse_button_released(btn)` | true **only** on the release frame |
|
||||
|
||||
Plus: `mouse_position() -> (f32, f32)`, `mouse_delta() -> (f32, f32)` (accumulated over the
|
||||
frame, reset between frames), `scroll_delta() -> (f32, f32)` (wheel).
|
||||
frame, reset between frames), `scroll_delta() -> (f32, f32)` (wheel, in **line/notch units** —
|
||||
`PixelDelta` events are normalized by /32 so one physical wheel notch ≈ 1.0 on every backend).
|
||||
|
||||
> **Button-gated orbit**: `mouse_delta()` returns movement *whenever* the mouse moves. For a
|
||||
> classic arc-rotate camera, apply it only while a button is held — that is what the `demo` does:
|
||||
> `if app.input.mouse_button_held(MouseButton::Left) { self.camera.orbit(dx, dy); }`.
|
||||
> Free-movement orbit (no button) is also possible, just drop the condition.
|
||||
|
||||
`KeyCode` values are winit's physical codes (`winit::keyboard::KeyCode`); mouse buttons are
|
||||
`winit::event::MouseButton`. The library does not re-export them: if your code mentions
|
||||
@@ -73,12 +86,15 @@ applications (like `simple`/`cube`) don't need winit: `app.input` remains usable
|
||||
`KeyCode` comparisons require the import.
|
||||
|
||||
```rust
|
||||
use winit::event::MouseButton;
|
||||
use winit::keyboard::KeyCode;
|
||||
|
||||
fn update(&mut self, app: &mut wsg_lib::App) {
|
||||
// Orbit + zoom driven by the mouse (excerpts from demo):
|
||||
// Orbit (left-drag gated) + zoom driven by the mouse (excerpts from demo):
|
||||
let (dx, dy) = app.input.mouse_delta();
|
||||
self.camera.orbit(dx, dy);
|
||||
if app.input.mouse_button_held(MouseButton::Left) {
|
||||
self.camera.orbit(dx, dy);
|
||||
}
|
||||
let (_, sy) = app.input.scroll_delta();
|
||||
self.camera.zoom(sy);
|
||||
|
||||
@@ -103,6 +119,7 @@ fn update(&mut self, app: &mut wsg_lib::App) {
|
||||
| FPS camera (WASD) | `key_held(KeyCode::KeyW)` in `update` → move `camera.position`/`target`; override `render()` if needed |
|
||||
| Changing the orbit target | `ctrl.target = subject_position;` (following an object) |
|
||||
| View presets | `key_pressed(Digit1/2/3)` → write yaw/pitch/distance (from the `demo`) |
|
||||
| Tuning the camera speed | `ctrl.orbit_sensitivity = 0.003;` (slower orbit), `ctrl.zoom_factor = 0.95;` (gentler zoom) |
|
||||
|
||||
## Links
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Seven examples live in [`lib/examples/`](../../lib/examples/) and all launch wit
|
||||
|---------|----------|---------------|--------------------|
|
||||
| `simple` | `cargo run -p wsg-lib --example simple` | The minimal declarative workflow: a two-tone 2D quad, **unlit**, rendered automatically. The "15 lines, no wgpu" model | [Quickstart](quickstart.md), [Materials](materials.md) (§ unlit) |
|
||||
| `cube` | `cargo run -p wsg-lib --example cube` | The 3D MVP: a textured (checkerboard) cube, lit (directional + point + spot), spinning | [Meshes](meshes.md), [Materials](materials.md), [Lights](lights.md) |
|
||||
| `demo` | `cargo run -p wsg-lib --example demo` | The full showcase: ground + 6 primitives, textures, 3 lights, **shadows**, **orbital camera** on keyboard/mouse (drag = orbit, wheel = zoom, `R` = reset, `1`/`2`/`3` = presets) | [All pages](README.md) |
|
||||
| `demo` | `cargo run -p wsg-lib --example demo` | The full showcase: ground + 6 primitives, textures, 3 lights, **shadows**, **orbital camera** on keyboard/mouse (left-drag = orbit, wheel = zoom, `R` = reset, `1`/`2`/`3` = presets) | [All pages](README.md) |
|
||||
| `shadow_test` | `cargo run -p wsg-lib --example shadow_test` | Isolated shadow mapping: a cube casts a PCF-softened shadow on the ground (`clear_lights` technique → caster at index 0) | [Shadows](shadows.md) |
|
||||
| `spot_test` | `cargo run -p wsg-lib --example spot_test` | Isolated spot (ambient nearly zero): the directed beam, the penumbra, the attenuation | [Lights](lights.md) |
|
||||
| `manual` | `cargo run -p wsg-lib --example manual` | The **advanced** workflow: `Context`/`Renderer`/`PipelineCache` driven by hand, without the `App` facade (winit 0.30 `ApplicationHandler`) | below |
|
||||
|
||||
Reference in New Issue
Block a user