import { Vec3 } from "../../../engine/math/Vec3" import type { Mesh } from "../../../engine/scene/Mesh" import type { Tree, TreeSpecies } from "../Tree" import { blob, lerp, limb, TAU, rng } from "./treekit" // Oak: short tapered trunk, a couple of branches, a broad cluster of rounded canopy // blobs (bushy, wider than tall). Trunk = brown bark, foliage = oak leaf. export const oak: TreeSpecies = { kind: "oak", trunk: "bark", foliage: "leaf", build } function build(tree: Tree, trunk: Mesh, leaves: Mesh, lod: "full" | "impostor"): void { const base = tree.position const g = tree.growth const rand = rng(tree.seed) const h = lerp(0.8, 7, g) const rTrunk = lerp(0.04, 0.32, g) const forkY = base.y + h * 0.5 const canopyY = base.y + h * 0.72 const blobR = h * 0.3 if (lod === "impostor") { // One low-poly blob on a stubby trunk -- reads as an oak at distance. limb(trunk, base, { x: base.x, y: forkY, z: base.z }, rTrunk, rTrunk * 0.6, 3) blob(leaves, { x: base.x, y: canopyY, z: base.z }, blobR * 1.15, rand, 4, 2) return } limb(trunk, base, { x: base.x, y: forkY, z: base.z }, rTrunk, rTrunk * 0.6, 5) const spread = h * 0.32 // Central blob plus, as it grows, a couple offset ones -> broad bushy crown. const blobs = 1 + Math.round(g * 2) for (let i = 0; i < blobs; i++) { const angle = rand() * TAU const rad = i === 0 ? 0 : spread * (0.5 + rand() * 0.5) const center = { x: base.x + Math.cos(angle) * rad, y: canopyY + (rand() - 0.4) * spread, z: base.z + Math.sin(angle) * rad, } blob(leaves, center, blobR * (0.7 + rand() * 0.4), rand) } // Grown oaks throw out a few branches, each tipped with a leaf tuft. if (g > 0.55) { const branches = 2 + Math.round(rand()) for (let i = 0; i < branches; i++) { const angle = rand() * TAU const dir = Vec3.normalize({ x: Math.cos(angle), y: 1.2, z: Math.sin(angle) }) const start = { x: base.x, y: base.y + h * 0.42, z: base.z } const end = Vec3.add(start, Vec3.scale(dir, h * 0.3)) limb(trunk, start, end, rTrunk * 0.4, rTrunk * 0.2, 4) blob(leaves, end, blobR * 0.6, rand) } } }