feat: threads
This commit is contained in:
parent
6fb46573da
commit
46e7070b6b
18 changed files with 878 additions and 125 deletions
|
|
@ -40,13 +40,13 @@ export namespace Framebuffer {
|
|||
* 15-bit output. Skipped entirely when it would be a no-op (full depth, no
|
||||
* dither).
|
||||
*/
|
||||
export function quantize(fb: Framebuffer, config: RenderConfig): void {
|
||||
export function quantize(fb: Framebuffer, config: RenderConfig, y0 = 0, y1 = fb.height): void {
|
||||
const levels = (1 << config.colorDepth) - 1
|
||||
if (levels >= 255 && config.dither === 0) {
|
||||
return
|
||||
}
|
||||
const { width, height, color } = fb
|
||||
for (let y = 0; y < height; y++) {
|
||||
const { width, color } = fb
|
||||
for (let y = y0; y < y1; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
// Per-pixel threshold from the tiled Bayer matrix, centered on 0 and
|
||||
// scaled by strength, nudges each channel before it snaps to a level.
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ export namespace Rasterizer {
|
|||
viewProj: Mat4,
|
||||
config: RenderConfig,
|
||||
cull = false,
|
||||
clipY0 = 0,
|
||||
clipY1 = 1 << 30,
|
||||
): void {
|
||||
const { verts, indices } = mesh
|
||||
const flat = config.lighting === "flat"
|
||||
|
|
@ -65,7 +67,7 @@ export namespace Rasterizer {
|
|||
// Near-clipping can turn one triangle into a quad; fan it back to tris.
|
||||
const n = clipNear(3)
|
||||
for (let k = 1; k + 1 < n; k++) {
|
||||
fillTriangle(fb, 0, k, k + 1, shade, texture, config, cull)
|
||||
fillTriangle(fb, 0, k, k + 1, shade, texture, config, cull, clipY0, clipY1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,6 +169,8 @@ export namespace Rasterizer {
|
|||
texture: Texture,
|
||||
config: RenderConfig,
|
||||
cull: boolean,
|
||||
clipY0: number,
|
||||
clipY1: number,
|
||||
): void {
|
||||
const oa = ia * CLIP
|
||||
const ob = ib * CLIP
|
||||
|
|
@ -210,8 +214,10 @@ export namespace Rasterizer {
|
|||
const vC = dst[oc + 4]
|
||||
const minX = Math.max(0, Math.floor(Math.min(sxA, sxB, sxC)))
|
||||
const maxX = Math.min(width - 1, Math.ceil(Math.max(sxA, sxB, sxC)))
|
||||
const minY = Math.max(0, Math.floor(Math.min(syA, syB, syC)))
|
||||
const maxY = Math.min(height - 1, Math.ceil(Math.max(syA, syB, syC)))
|
||||
// Clamp to the caller's Y-band (default full frame) so worker threads can
|
||||
// each fill a disjoint slice of rows without ever touching the same pixel.
|
||||
const minY = Math.max(0, clipY0, Math.floor(Math.min(syA, syB, syC)))
|
||||
const maxY = Math.min(height - 1, clipY1 - 1, Math.ceil(Math.max(syA, syB, syC)))
|
||||
// Edge deltas for the three barycentric edge functions (b->c, c->a, a->b).
|
||||
const dx0 = sxC - sxB
|
||||
const dy0 = syC - syB
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ export type RenderConfig = {
|
|||
* short draw distance and the shimmer of far geometry. It also colors pixels
|
||||
* no triangle covers, so the frame's clear color should match `fog.color`. */
|
||||
fog: Fog | null
|
||||
/** Beyond this distance (world units) trees + boulders draw as cheap low-poly
|
||||
* impostors instead of full geometry, cutting per-triangle work in dense
|
||||
* views. Kept inside `fog.far` so far detail is already fog-dimmed at the
|
||||
* switch; `Infinity` disables LOD. */
|
||||
lodDistance: number
|
||||
}
|
||||
|
||||
/** Ready-made looks. The demo binds keys 1/2/3 to these, sweeping resolution,
|
||||
|
|
@ -61,6 +66,7 @@ export namespace RenderConfig {
|
|||
textureFilter: "nearest",
|
||||
lighting: "flat",
|
||||
fog: { color: Color.rgb(150, 170, 200), near: 12, far: 200 },
|
||||
lodDistance: 60,
|
||||
}
|
||||
|
||||
export const ps1: RenderConfig = {
|
||||
|
|
@ -73,6 +79,7 @@ export namespace RenderConfig {
|
|||
textureFilter: "nearest",
|
||||
lighting: "flat",
|
||||
fog: { color: Color.rgb(150, 170, 200), near: 12, far: 200 },
|
||||
lodDistance: 60,
|
||||
}
|
||||
|
||||
export const soft: RenderConfig = {
|
||||
|
|
@ -85,6 +92,7 @@ export namespace RenderConfig {
|
|||
textureFilter: "nearest",
|
||||
lighting: "flat",
|
||||
fog: { color: Color.rgb(170, 190, 215), near: 16, far: 240 },
|
||||
lodDistance: 70,
|
||||
}
|
||||
|
||||
export const clean: RenderConfig = {
|
||||
|
|
@ -94,9 +102,9 @@ export namespace RenderConfig {
|
|||
colorDepth: 8,
|
||||
dither: 0,
|
||||
vertexSnap: 0,
|
||||
perspectiveCorrect: 1,
|
||||
textureFilter: "linear",
|
||||
lighting: "flat",
|
||||
fog: null,
|
||||
lodDistance: Infinity,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,8 +64,9 @@ export namespace Sky {
|
|||
* 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, step = 1): void {
|
||||
export function render(fb: Framebuffer, camera: Camera, sky: SkyConfig, time: number, step = 1, y0 = 0, y1 = -1): void {
|
||||
const { width, height, color, depth } = fb
|
||||
const bottom = y1 < 0 ? height : y1
|
||||
const forward = Camera.forward(camera)
|
||||
const right = Vec3.normalize(Vec3.cross(forward, UP))
|
||||
const up = Vec3.cross(right, forward)
|
||||
|
|
@ -76,11 +77,13 @@ export namespace Sky {
|
|||
const clouds = sky.clouds
|
||||
const cloud: CloudSample = { cover: 0, shade: 1 }
|
||||
const s = Math.max(1, step | 0)
|
||||
for (let by = 0; by < height; by += s) {
|
||||
// Band `y0`..`bottom` must be step-aligned (callers ensure it) so the block
|
||||
// grid stays global and neighboring bands don't seam.
|
||||
for (let by = y0; by < bottom; 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)
|
||||
const yEnd = Math.min(bottom, 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue