Switch to Z-up coordinate system: WASD on XY ground plane, E/Q for vertical
This commit is contained in:
@@ -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<KeyCode>` 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.
|
||||
|
||||
|
||||
+3
-3
@@ -130,7 +130,7 @@
|
||||
<div class="help-box">
|
||||
<h2>Controls</h2>
|
||||
<div class="help-row">
|
||||
<span class="help-action">Up / Down (Y)</span>
|
||||
<span class="help-action">Forward / Back (Y)</span>
|
||||
<span class="help-keys"><kbd>W</kbd><kbd>S</kbd></span>
|
||||
</div>
|
||||
<div class="help-row">
|
||||
@@ -138,8 +138,8 @@
|
||||
<span class="help-keys"><kbd>A</kbd><kbd>D</kbd></span>
|
||||
</div>
|
||||
<div class="help-row">
|
||||
<span class="help-action">Forward / Back (Z)</span>
|
||||
<span class="help-keys"><kbd>Q</kbd><kbd>E</kbd></span>
|
||||
<span class="help-action">Up / Down (Z)</span>
|
||||
<span class="help-keys"><kbd>E</kbd><kbd>Q</kbd></span>
|
||||
</div>
|
||||
<div class="help-row">
|
||||
<span class="help-action">Look</span>
|
||||
|
||||
+6
-6
@@ -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 {
|
||||
|
||||
+5
-5
@@ -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) {
|
||||
|
||||
+6
-6
@@ -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];
|
||||
|
||||
+3
-3
@@ -80,7 +80,7 @@ pub fn build_scene() -> (Vec<Mesh>, Vec<SceneObject>) {
|
||||
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<Mesh>, Vec<SceneObject>) {
|
||||
|
||||
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<Mesh>, Vec<SceneObject>) {
|
||||
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);
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
let normal = normalize(in.world_normal);
|
||||
|
||||
// Simple directional light + ambient for a flat-shaded look
|
||||
let light_dir = normalize(vec3<f32>(0.4, 1.0, 0.6));
|
||||
let light_dir = normalize(vec3<f32>(0.4, 0.6, 1.0));
|
||||
let ambient = 0.15;
|
||||
let diffuse = max(dot(normal, light_dir), 0.0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user