feat: 1995
This commit is contained in:
commit
fb89263930
69 changed files with 3359 additions and 0 deletions
64
engine/render/Sky.ts
Normal file
64
engine/render/Sky.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { Color } from "./Color"
|
||||
import type { Framebuffer } from "./Framebuffer"
|
||||
import { Camera } from "../scene/Camera"
|
||||
import { Vec3 } from "../math/Vec3"
|
||||
|
||||
/** Procedural sky: a vertical gradient plus a sun disc. No texture needed. */
|
||||
export type SkyConfig = {
|
||||
zenith: Color
|
||||
horizon: Color
|
||||
sun: Color
|
||||
/** World-space direction toward the sun (need not be normalized). */
|
||||
sunDir: Vec3
|
||||
/** Angular radius of the sun's core, in radians. */
|
||||
sunSize: number
|
||||
}
|
||||
|
||||
const UP: Vec3 = { x: 0, y: 1, z: 0 }
|
||||
|
||||
export namespace Sky {
|
||||
/**
|
||||
* Fill the whole framebuffer with the sky and reset depth to 0. Run first each
|
||||
* frame in place of Framebuffer.clear; opaque geometry then overwrites the sky
|
||||
* wherever it is nearer.
|
||||
*
|
||||
* Per pixel it reconstructs the view ray from the camera basis, shades a
|
||||
* horizon->zenith gradient by the ray's elevation (so it pans with pitch and
|
||||
* yaw), and brightens toward `sun` where the ray points near `sunDir`.
|
||||
*/
|
||||
export function render(fb: Framebuffer, camera: Camera, sky: SkyConfig): void {
|
||||
const { width, height, color, depth } = fb
|
||||
const forward = Camera.forward(camera)
|
||||
const right = Vec3.normalize(Vec3.cross(forward, UP))
|
||||
const up = Vec3.cross(right, forward)
|
||||
const tanY = Math.tan(camera.fov / 2)
|
||||
const tanX = tanY * (width / height)
|
||||
const sun = Vec3.normalize(sky.sunDir)
|
||||
const cosSun = Math.cos(sky.sunSize)
|
||||
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
|
||||
// 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
|
||||
let dz = forward.z + right.z * ndcX * tanX + up.z * ndcY * tanY
|
||||
const inv = 1 / Math.hypot(dx, dy, dz)
|
||||
dx *= inv
|
||||
dy *= inv
|
||||
dz *= inv
|
||||
// dy is the ray elevation: 0 at the horizon, 1 straight up.
|
||||
const t = Math.max(0, Math.min(1, dy))
|
||||
let c = Color.lerp(sky.horizon, sky.zenith, t)
|
||||
const facing = dx * sun.x + dy * sun.y + dz * sun.z
|
||||
if (facing > cosSun) {
|
||||
const glow = Math.min(1, ((facing - cosSun) / (1 - cosSun)) * 1.5)
|
||||
c = Color.lerp(c, sky.sun, glow)
|
||||
}
|
||||
const i = y * width + x
|
||||
color[i] = c
|
||||
depth[i] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue