feat: culling
This commit is contained in:
parent
680e08aadc
commit
ef5029da1d
7 changed files with 309 additions and 103 deletions
66
engine/render/Frustum.ts
Normal file
66
engine/render/Frustum.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import type { Mat4 } from "../math/Mat4"
|
||||
|
||||
/** The six view-frustum planes packed as (a, b, c, d) each, normal pointing
|
||||
* inward: a point is inside a plane when a*x + b*y + c*z + d >= 0. */
|
||||
export type Frustum = Float32Array
|
||||
|
||||
export namespace Frustum {
|
||||
/** Extract the planes from a view-projection matrix (Gribb-Hartmann). Our Mat4
|
||||
* is column-major (`m[col*4 + row]`), so a clip-space row `i` gathers the
|
||||
* `i`-th entry of every column. Left/right/bottom/top/near/far are the row
|
||||
* sums/differences with the w-row. */
|
||||
export function fromViewProj(m: Mat4): Frustum {
|
||||
const rx = [m[0], m[1], m[2], m[3]]
|
||||
const ry = [m[4], m[5], m[6], m[7]]
|
||||
const rz = [m[8], m[9], m[10], m[11]]
|
||||
const rw = [m[12], m[13], m[14], m[15]]
|
||||
// Row i of the clip matrix = (rx[i], ry[i], rz[i], rw[i]).
|
||||
const row = (i: number): [number, number, number, number] => [rx[i], ry[i], rz[i], rw[i]]
|
||||
const [x0, y0, z0, w0] = row(0)
|
||||
const [x1, y1, z1, w1] = row(1)
|
||||
const [x2, y2, z2, w2] = row(2)
|
||||
const [x3, y3, z3, w3] = row(3)
|
||||
const f = new Float32Array(24)
|
||||
plane(f, 0, x3 + x0, y3 + y0, z3 + z0, w3 + w0) // left
|
||||
plane(f, 1, x3 - x0, y3 - y0, z3 - z0, w3 - w0) // right
|
||||
plane(f, 2, x3 + x1, y3 + y1, z3 + z1, w3 + w1) // bottom
|
||||
plane(f, 3, x3 - x1, y3 - y1, z3 - z1, w3 - w1) // top
|
||||
plane(f, 4, x3 + x2, y3 + y2, z3 + z2, w3 + w2) // near
|
||||
plane(f, 5, x3 - x2, y3 - y2, z3 - z2, w3 - w2) // far
|
||||
return f
|
||||
}
|
||||
|
||||
/** True if the axis-aligned box might be visible. Conservative: tests the box
|
||||
* corner farthest along each plane normal; the box is culled only if that
|
||||
* corner is still outside some plane, so nothing visible is ever dropped. */
|
||||
export function intersectsAabb(
|
||||
f: Frustum,
|
||||
minX: number,
|
||||
minY: number,
|
||||
minZ: number,
|
||||
maxX: number,
|
||||
maxY: number,
|
||||
maxZ: number,
|
||||
): boolean {
|
||||
for (let p = 0; p < 24; p += 4) {
|
||||
const a = f[p]
|
||||
const b = f[p + 1]
|
||||
const c = f[p + 2]
|
||||
const px = a >= 0 ? maxX : minX
|
||||
const py = b >= 0 ? maxY : minY
|
||||
const pz = c >= 0 ? maxZ : minZ
|
||||
if (a * px + b * py + c * pz + f[p + 3] < 0) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function plane(f: Frustum, i: number, a: number, b: number, c: number, d: number): void {
|
||||
const inv = 1 / Math.hypot(a, b, c)
|
||||
f[i * 4] = a * inv
|
||||
f[i * 4 + 1] = b * inv
|
||||
f[i * 4 + 2] = c * inv
|
||||
f[i * 4 + 3] = d * inv
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue