From 161472209530b35c54afcafb21d7754ce75aad8c Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sat, 14 Feb 2026 01:31:23 -0800 Subject: [PATCH] Switch to Z-up coordinate system: WASD on XY ground plane, E/Q for vertical --- CLAUDE.md | 2 +- index.html | 6 +++--- src/camera.rs | 12 ++++++------ src/main.rs | 10 +++++----- src/mesh.rs | 12 ++++++------ src/scene.rs | 6 +++--- src/shader.wgsl | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f7f63dc..6ed9335 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,7 +41,7 @@ Single-crate Rust app (`wgpu-demo`) that runs both natively and in-browser via W - `scene.rs` — `SceneObject` placement with animated rotation. `build_scene()` generates all meshes and objects - `input.rs` — `HashSet` key tracking -**Movement model:** Axis-aligned (not camera-relative). W/S = Y, A/D = X, Q/E = Z. Mouse look controls yaw/pitch. +**Movement model:** Z-up coordinate system. Axis-aligned (not camera-relative). W/S = Y (forward/back), A/D = X (left/right), E/Q = Z (up/down). Mouse look controls yaw/pitch. **WASM-specific:** `web-time` replaces `std::time::Instant`. HUD overlays (help, coordinate bar) are HTML elements in `index.html`, manipulated via `web-sys` DOM calls from Rust. Pointer lock via winit's cursor grab API. diff --git a/index.html b/index.html index fba9996..1c5a131 100644 --- a/index.html +++ b/index.html @@ -130,7 +130,7 @@

Controls

- Up / Down (Y) + Forward / Back (Y) WS
@@ -138,8 +138,8 @@ AD
- Forward / Back (Z) - QE + Up / Down (Z) + EQ
Look diff --git a/src/camera.rs b/src/camera.rs index f579b96..a729716 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -25,29 +25,29 @@ impl Camera { } } - /// Forward direction on the XZ plane (for WASD movement) + /// Forward direction on the XY plane (for WASD movement) pub fn forward(&self) -> Vec3 { - Vec3::new(self.yaw.sin(), 0.0, -self.yaw.cos()).normalize() + Vec3::new(self.yaw.cos(), self.yaw.sin(), 0.0).normalize() } - /// Right direction on the XZ plane + /// Right direction on the XY plane pub fn right(&self) -> Vec3 { - Vec3::new(self.yaw.cos(), 0.0, self.yaw.sin()).normalize() + Vec3::new(self.yaw.sin(), -self.yaw.cos(), 0.0).normalize() } /// The actual look direction (including pitch) for the view matrix fn look_dir(&self) -> Vec3 { Vec3::new( + self.pitch.cos() * self.yaw.cos(), self.pitch.cos() * self.yaw.sin(), self.pitch.sin(), - -self.pitch.cos() * self.yaw.cos(), ) .normalize() } pub fn view_matrix(&self) -> Mat4 { let target = self.position + self.look_dir(); - Mat4::look_at_rh(self.position, target, Vec3::Y) + Mat4::look_at_rh(self.position, target, Vec3::Z) } pub fn projection_matrix(&self) -> Mat4 { diff --git a/src/main.rs b/src/main.rs index 9666f67..dcae57c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,8 +42,8 @@ impl App { let pos = Vec3::new(10.0, -10.0, 10.0); let to_origin = (Vec3::ZERO - pos).normalize(); let mut cam = Camera::new(pos, 1.0); - cam.yaw = to_origin.x.atan2(-to_origin.z); - cam.pitch = to_origin.y.asin(); + cam.yaw = to_origin.y.atan2(to_origin.x); + cam.pitch = to_origin.z.asin(); cam }, input: InputState::new(), @@ -69,12 +69,12 @@ impl App { if self.input.is_pressed(KeyCode::KeyD) { self.camera.position.x += speed; } - if self.input.is_pressed(KeyCode::KeyQ) { - self.camera.position.z -= speed; - } if self.input.is_pressed(KeyCode::KeyE) { self.camera.position.z += speed; } + if self.input.is_pressed(KeyCode::KeyQ) { + self.camera.position.z -= speed; + } } fn try_lock_cursor(&self, window: &Window) { diff --git a/src/mesh.rs b/src/mesh.rs index 27bc4ed..cccfcf3 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -214,10 +214,10 @@ impl Mesh { pub fn icosphere_with_spike(subdivisions: u32, color: [f32; 3], spike_color: [f32; 3]) -> Self { let mut mesh = Self::icosphere(subdivisions, color); - // Add a cone spike pointing in +Y direction + // Add a cone spike pointing in +Z direction let spike_base_radius = 0.3; - let spike_base_y = 0.9; - let spike_tip = Vec3::new(0.0, 1.8, 0.0); + let spike_base_z = 0.9; + let spike_tip = Vec3::new(0.0, 0.0, 1.8); let segments = 12; // Generate base ring points @@ -226,8 +226,8 @@ impl Mesh { let angle = (i as f32 / segments as f32) * std::f32::consts::TAU; Vec3::new( angle.cos() * spike_base_radius, - spike_base_y, angle.sin() * spike_base_radius, + spike_base_z, ) }) .collect(); @@ -255,8 +255,8 @@ impl Mesh { } // Base cap (so the spike isn't open at the bottom) - let base_center = Vec3::new(0.0, spike_base_y, 0.0); - let base_normal = Vec3::NEG_Y; + let base_center = Vec3::new(0.0, 0.0, spike_base_z); + let base_normal = Vec3::NEG_Z; for i in 0..segments { let a = base_points[(i + 1) % segments]; let b = base_points[i]; diff --git a/src/scene.rs b/src/scene.rs index 94bb1eb..d73ead7 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -80,7 +80,7 @@ pub fn build_scene() -> (Vec, Vec) { objects.push(SceneObject { mesh_index: spiked_ball_index, position: Vec3::ZERO, - rotation_axis: Vec3::new(0.3, 1.0, 0.1).normalize(), + rotation_axis: Vec3::new(0.3, 0.1, 1.0).normalize(), rotation_speed: 0.5, scale: 0.8, base_rotation: 0.0, @@ -93,8 +93,8 @@ pub fn build_scene() -> (Vec, Vec) { let position = Vec3::new( rng.gen_range(-spread..spread), - rng.gen_range(-spread * 0.5..spread * 0.5), rng.gen_range(-spread..spread), + rng.gen_range(-spread * 0.5..spread * 0.5), ); let rotation_axis = Vec3::new( @@ -102,7 +102,7 @@ pub fn build_scene() -> (Vec, Vec) { rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0), ) - .normalize_or(Vec3::Y); + .normalize_or(Vec3::Z); let rotation_speed = rng.gen_range(0.2..1.5) * if rng.gen_bool(0.5) { 1.0 } else { -1.0 }; let scale = rng.gen_range(0.5..2.5); diff --git a/src/shader.wgsl b/src/shader.wgsl index 3c4a5df..49f4726 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -42,7 +42,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { let normal = normalize(in.world_normal); // Simple directional light + ambient for a flat-shaded look - let light_dir = normalize(vec3(0.4, 1.0, 0.6)); + let light_dir = normalize(vec3(0.4, 0.6, 1.0)); let ambient = 0.15; let diffuse = max(dot(normal, light_dir), 0.0);