Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitd93fccdb21

README.md

mesher

Pure-function voxel mesher. Walks a grid via isSolid, getColor, and optional getMaterial callbacks and emits CPU-side mesh data (positions, indices, normals, uvs, colors, submeshes). Two CPU variants — buildSimple (one quad per visible face) and buildGreedy (merges adjacent faces of the same color and material) — plus a generic build that dispatches through a session-level backend selector (CPU or GPU).

Submesh index convention is 0-based: submeshes[i].indexStart is the offset into indices where material i's faces begin, counted from 0. This matches GPU draw-call conventions. Even a single-material mesh gets a submesh entry — callers never have to branch on its presence.

The GPU backend lives in the sibling gpu.module/. The selector defaults to "gpu" when the engine exposes compute + renderer.mesh.create, and "cpu" otherwise.

Exports

  • M.buildSimple(opts: BuildOpts) -> MeshDescriptor — one quad per visible face. CPU-only.
  • M.buildGreedy(opts: BuildOpts) -> MeshDescriptor — greedy face merging, per-material passes. CPU-only.
  • M.setBackend(name: BackendName) — set the session-default backend ("cpu" or "gpu"). Raises on unknown names.
  • M.getBackend() -> BackendName — read the current default. Resolves lazily on first call.
  • M.build(opts: BuildOpts) -> MeshDescriptor — dispatch through the active backend.

Types:

  • Vec3 = { x: number, y: number, z: number }
  • Submesh = { material: string, indexStart: number, indexCount: number }
  • MeshDescriptor = { positions, indices, normals, uvs, colors, submeshes, vertexCount, gpuBuffers?, aabb? }
  • BuildOpts = { size: Vec3, blockSize?: number, origin?: Vec3, isSolid, getColor, getMaterial? }
  • BackendName = "cpu" | "gpu"

Usage

local Mesher = require("@builtin::systems.voxelEngine.voxelEngine.mesher")

local desc = Mesher.buildGreedy({
    size      = { x = 32, y = 32, z = 32 },
    blockSize = 1.0,
    isSolid   = function(x, y, z) return ... end,
    getColor  = function(x, y, z) return r, g, b end,
})

-- Or via the backend selector:
Mesher.setBackend("gpu")
local desc = Mesher.build(opts)

Notes

  • CCW-front winding. Output is ready for renderer.mesh.create (CPU) or renderer.mesh.create (GPU).
  • An empty mesh (no visible faces) yields an empty submeshes array.
  • buildSimple / buildGreedy are direct CPU entry points — they bypass the backend selector. Use them when you need CPU-side vertex arrays even if the session default is GPU.
  • setBackend only affects build — explicit calls to buildSimple / buildGreedy always run CPU.