feat: 1995
This commit is contained in:
commit
fb89263930
69 changed files with 3359 additions and 0 deletions
72
engine/math/Mat4.ts
Normal file
72
engine/math/Mat4.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { Vec3 } from "./Vec3"
|
||||
|
||||
/** 4x4 matrix in column-major storage: index = col * 4 + row, matching OpenGL
|
||||
* conventions so the standard perspective/lookAt formulas apply directly. */
|
||||
export type Mat4 = Float32Array
|
||||
|
||||
export namespace Mat4 {
|
||||
/** Matrix product A * B (apply B first, then A). */
|
||||
export function multiply(a: Mat4, b: Mat4): Mat4 {
|
||||
const out = new Float32Array(16)
|
||||
for (let col = 0; col < 4; col++) {
|
||||
for (let row = 0; row < 4; row++) {
|
||||
let sum = 0
|
||||
for (let k = 0; k < 4; k++) {
|
||||
sum += a[k * 4 + row] * b[col * 4 + k]
|
||||
}
|
||||
out[col * 4 + row] = sum
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/** Right-handed perspective projection (camera looks down -Z). Maps the view
|
||||
* frustum to clip space; the -1 in row 3 copies -z into w, so the later
|
||||
* divide by w is what produces foreshortening. */
|
||||
export function perspective(fovY: number, aspect: number, near: number, far: number): Mat4 {
|
||||
const f = 1 / Math.tan(fovY / 2)
|
||||
const out = new Float32Array(16)
|
||||
out[0] = f / aspect
|
||||
out[5] = f
|
||||
out[10] = (far + near) / (near - far)
|
||||
out[11] = -1
|
||||
out[14] = (2 * far * near) / (near - far)
|
||||
return out
|
||||
}
|
||||
|
||||
/** View matrix looking from `eye` toward `center`, with `up` roughly up.
|
||||
* Builds an orthonormal camera basis (s = right, u = up, f = forward) and
|
||||
* packs it as the inverse camera transform. */
|
||||
export function lookAt(eye: Vec3, center: Vec3, up: Vec3): Mat4 {
|
||||
const f = Vec3.normalize(Vec3.sub(center, eye))
|
||||
const s = Vec3.normalize(Vec3.cross(f, up))
|
||||
const u = Vec3.cross(s, f)
|
||||
const out = new Float32Array(16)
|
||||
out[0] = s.x
|
||||
out[1] = u.x
|
||||
out[2] = -f.x
|
||||
out[4] = s.y
|
||||
out[5] = u.y
|
||||
out[6] = -f.y
|
||||
out[8] = s.z
|
||||
out[9] = u.z
|
||||
out[10] = -f.z
|
||||
out[12] = -Vec3.dot(s, eye)
|
||||
out[13] = -Vec3.dot(u, eye)
|
||||
out[14] = Vec3.dot(f, eye)
|
||||
out[15] = 1
|
||||
return out
|
||||
}
|
||||
|
||||
/** Transform a point, returning homogeneous coords. `w` is kept (not divided
|
||||
* out) because the rasterizer needs it for near-clipping and the perspective
|
||||
* divide/depth; for a perspective matrix w equals the view-space distance. */
|
||||
export function transform(m: Mat4, v: Vec3): { x: number; y: number; z: number; w: number } {
|
||||
return {
|
||||
x: m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12],
|
||||
y: m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13],
|
||||
z: m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14],
|
||||
w: m[3] * v.x + m[7] * v.y + m[11] * v.z + m[15],
|
||||
}
|
||||
}
|
||||
}
|
||||
2
engine/math/Vec2.ts
Normal file
2
engine/math/Vec2.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/** 2D vector, used for texture coordinates. */
|
||||
export type Vec2 = { x: number; y: number }
|
||||
38
engine/math/Vec3.ts
Normal file
38
engine/math/Vec3.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
export type Vec3 = { x: number; y: number; z: number }
|
||||
|
||||
/** Plain 3D vector math. Every operation returns a fresh object (no in-place
|
||||
* mutation) to keep call sites easy to reason about. */
|
||||
export namespace Vec3 {
|
||||
export function add(a: Vec3, b: Vec3): Vec3 {
|
||||
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }
|
||||
}
|
||||
|
||||
export function sub(a: Vec3, b: Vec3): Vec3 {
|
||||
return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }
|
||||
}
|
||||
|
||||
export function scale(v: Vec3, s: number): Vec3 {
|
||||
return { x: v.x * s, y: v.y * s, z: v.z * s }
|
||||
}
|
||||
|
||||
export function dot(a: Vec3, b: Vec3): number {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||
}
|
||||
|
||||
export function cross(a: Vec3, b: Vec3): Vec3 {
|
||||
return {
|
||||
x: a.y * b.z - a.z * b.y,
|
||||
y: a.z * b.x - a.x * b.z,
|
||||
z: a.x * b.y - a.y * b.x,
|
||||
}
|
||||
}
|
||||
|
||||
export function length(v: Vec3): number {
|
||||
return Math.sqrt(dot(v, v))
|
||||
}
|
||||
|
||||
export function normalize(v: Vec3): Vec3 {
|
||||
const len = length(v)
|
||||
return len === 0 ? v : scale(v, 1 / len)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue