refactor: move world concepts into engine
This commit is contained in:
parent
eeedcb8e48
commit
2d15c7ab8d
52 changed files with 3298 additions and 1558 deletions
123
engine/render/ChunkBuilder.ts
Normal file
123
engine/render/ChunkBuilder.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import { STRIDE, type Mesh } from "../scene/Mesh"
|
||||
import type { Chunk, Bounds3 } from "./Chunk"
|
||||
import type { DrawGroup, Material } from "./Material"
|
||||
|
||||
export type MeshBatch = {
|
||||
mesh: (material: Material) => Mesh
|
||||
use: (material: Material, mesh: Mesh) => void
|
||||
}
|
||||
|
||||
export type ChunkItem = {
|
||||
position: { x: number; z: number }
|
||||
bakeNear: (batch: MeshBatch) => void
|
||||
bakeFar?: (batch: MeshBatch) => void
|
||||
}
|
||||
|
||||
export type ChunkCell = {
|
||||
x0: number
|
||||
z0: number
|
||||
x1: number
|
||||
z1: number
|
||||
}
|
||||
|
||||
export type ChunkBuilder = {
|
||||
minX: number
|
||||
minZ: number
|
||||
maxX: number
|
||||
maxZ: number
|
||||
columns: number
|
||||
rows: number
|
||||
bakeCell: (near: MeshBatch, far: MeshBatch, cell: ChunkCell) => void
|
||||
}
|
||||
|
||||
export namespace ChunkBuilder {
|
||||
export function build(config: ChunkBuilder, items: ChunkItem[]): Chunk[] {
|
||||
const width = (config.maxX - config.minX) / config.columns
|
||||
const depth = (config.maxZ - config.minZ) / config.rows
|
||||
const chunks: Chunk[] = []
|
||||
for (let column = 0; column < config.columns; column++) {
|
||||
const x0 = config.minX + column * width
|
||||
const x1 = x0 + width
|
||||
for (let row = 0; row < config.rows; row++) {
|
||||
const z0 = config.minZ + row * depth
|
||||
const z1 = z0 + depth
|
||||
const nearMeshes = new Map<Material, Mesh>()
|
||||
const farMeshes = new Map<Material, Mesh>()
|
||||
const near = batch(nearMeshes)
|
||||
const far = batch(farMeshes)
|
||||
config.bakeCell(near, far, { x0, z0, x1, z1 })
|
||||
for (const item of items) {
|
||||
if (inCell(item.position, x0, z0, x1, z1)) {
|
||||
item.bakeNear(near)
|
||||
item.bakeFar?.(far)
|
||||
}
|
||||
}
|
||||
const nearGroups = groups(nearMeshes)
|
||||
const farGroups = groups(farMeshes)
|
||||
const box = bounds([...nearMeshes.values(), ...farMeshes.values()])
|
||||
if (box !== null) {
|
||||
chunks.push({ ...box, near: nearGroups, far: farGroups })
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
function batch(meshes: Map<Material, Mesh>): MeshBatch {
|
||||
return {
|
||||
mesh(material) {
|
||||
let mesh = meshes.get(material)
|
||||
if (mesh === undefined) {
|
||||
mesh = { verts: [], indices: [] }
|
||||
meshes.set(material, mesh)
|
||||
}
|
||||
return mesh
|
||||
},
|
||||
use(material, mesh) {
|
||||
meshes.set(material, mesh)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function groups(meshes: Map<Material, Mesh>): DrawGroup[] {
|
||||
const result: DrawGroup[] = []
|
||||
for (const [material, mesh] of meshes) {
|
||||
if (mesh.indices.length > 0) {
|
||||
result.push({ mesh, material })
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function inCell(
|
||||
position: { x: number; z: number },
|
||||
x0: number,
|
||||
z0: number,
|
||||
x1: number,
|
||||
z1: number,
|
||||
): boolean {
|
||||
return (
|
||||
position.x >= x0 && position.x < x1 && position.z >= z0 && position.z < z1
|
||||
)
|
||||
}
|
||||
|
||||
function bounds(meshes: Mesh[]): Bounds3 | null {
|
||||
let minX = Infinity
|
||||
let minY = Infinity
|
||||
let minZ = Infinity
|
||||
let maxX = -Infinity
|
||||
let maxY = -Infinity
|
||||
let maxZ = -Infinity
|
||||
for (const mesh of meshes) {
|
||||
for (let i = 0; i < mesh.verts.length; i += STRIDE) {
|
||||
minX = Math.min(minX, mesh.verts[i])
|
||||
minY = Math.min(minY, mesh.verts[i + 1])
|
||||
minZ = Math.min(minZ, mesh.verts[i + 2])
|
||||
maxX = Math.max(maxX, mesh.verts[i])
|
||||
maxY = Math.max(maxY, mesh.verts[i + 1])
|
||||
maxZ = Math.max(maxZ, mesh.verts[i + 2])
|
||||
}
|
||||
}
|
||||
return maxX < minX ? null : { minX, minY, minZ, maxX, maxY, maxZ }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue