35 lines
1.2 KiB
TypeScript
35 lines
1.2 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 for now; far only needs to exceed the fog distance. */
|
|
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, 100)
|
|
return Mat4.multiply(proj, view)
|
|
}
|
|
}
|