feat: culling

This commit is contained in:
Dan Finch 2026-08-04 15:05:02 +02:00
parent 680e08aadc
commit ef5029da1d
7 changed files with 309 additions and 103 deletions

View file

@ -58,8 +58,13 @@ export namespace Sky {
* Per pixel it reconstructs the view ray from the camera basis, shades a
* horizon->zenith gradient by the ray's elevation, brightens toward `sun` near
* `sunDir`, then lays crisp-edged cumulus over the top.
*
* `step` (>= 1) renders the sky at 1/step resolution: the expensive shading
* (the per-pixel cloud fbm dominates the frame) runs once per step x step
* block and is copied across it. The sky is low-frequency, so 2 is nearly free
* visually and quarters the cloud cost; 1 is full resolution.
*/
export function render(fb: Framebuffer, camera: Camera, sky: SkyConfig, time: number): void {
export function render(fb: Framebuffer, camera: Camera, sky: SkyConfig, time: number, step = 1): void {
const { width, height, color, depth } = fb
const forward = Camera.forward(camera)
const right = Vec3.normalize(Vec3.cross(forward, UP))
@ -70,10 +75,15 @@ export namespace Sky {
const cosSun = Math.cos(sky.sunSize)
const clouds = sky.clouds
const cloud: CloudSample = { cover: 0, shade: 1 }
for (let y = 0; y < height; y++) {
const ndcY = 1 - ((y + 0.5) / height) * 2
for (let x = 0; x < width; x++) {
const ndcX = ((x + 0.5) / width) * 2 - 1
const s = Math.max(1, step | 0)
for (let by = 0; by < height; by += s) {
// Shade at the block center, then flood the whole block with that color.
const sampleY = Math.min(height - 1, by + (s >> 1))
const ndcY = 1 - ((sampleY + 0.5) / height) * 2
const yEnd = Math.min(height, by + s)
for (let bx = 0; bx < width; bx += s) {
const sampleX = Math.min(width - 1, bx + (s >> 1))
const ndcX = ((sampleX + 0.5) / width) * 2 - 1
// View ray = forward + right*ndcX*tanX + up*ndcY*tanY, then normalized.
let dx = forward.x + right.x * ndcX * tanX + up.x * ndcY * tanY
let dy = forward.y + right.y * ndcX * tanX + up.y * ndcY * tanY
@ -100,9 +110,14 @@ export namespace Sky {
c = Color.lerp(c, Color.scale(clouds.color, cloud.shade), cloud.cover)
}
}
const i = y * width + x
color[i] = c
depth[i] = 0
const xEnd = Math.min(width, bx + s)
for (let y = by; y < yEnd; y++) {
const o = y * width
for (let x = bx; x < xEnd; x++) {
color[o + x] = c
depth[o + x] = 0
}
}
}
}
}