meat/engine/scene/Camera.ts
2026-08-04 12:51:07 +02:00

36 lines
1.3 KiB
TypeScript

import { Mat4 } from "../math/Mat4"
import { Vec3 } from "../math/Vec3"
/** First-person camera. Orientation is Euler yaw/pitch (no roll), which is all
* an FPS needs and avoids gimbal bookkeeping. */
export type Camera = {
position: Vec3
/** Rotation around +Y, radians. 0 looks toward -Z; increasing turns right. */
yaw: number
/** Look up/down, radians. Positive looks up. Clamp near +-pi/2 to avoid flip. */
pitch: number
/** Vertical field of view, radians. */
fov: number
}
export namespace Camera {
/** Unit forward direction implied by yaw/pitch. */
export function forward(cam: Camera): Vec3 {
const cp = Math.cos(cam.pitch)
return {
x: cp * Math.sin(cam.yaw),
y: Math.sin(cam.pitch),
z: -cp * Math.cos(cam.yaw),
}
}
/** Combined projection * view matrix for the given viewport aspect ratio.
* Near/far are fixed; far only needs to exceed the fog distance, and is set
* wide enough to reach the outdoor world's distant peaks. */
export function viewProjection(cam: Camera, aspect: number): Mat4 {
const eye = cam.position
const view = Mat4.lookAt(eye, Vec3.add(eye, forward(cam)), { x: 0, y: 1, z: 0 })
const proj = Mat4.perspective(cam.fov, aspect, 0.05, 260)
return Mat4.multiply(proj, view)
}
}