Builtin Library
README.md
decals
Registry of oriented box decal projectors. Each entry is an entity whose
Transform is an oriented projection box plus the material the projector
stamps. The @builtin::renderFeatures.decals render feature reads this registry
every frame, groups the projectors by the material they share and packs them
eight to a pass. Each pass reconstructs a covered pixel's world position from
scene depth, transforms it into each projector's box space, and shades it from
the material — projecting a textured material's texture (or a flat-colour
material's colour) onto every surface inside the box, fading on faces turned away
from the projection axis so the decal wraps the surfaces facing the projector.
A pass is enqueued per channel the material provides: base colour when the
material binds a base_color_texture or states a base_color its shader does not
declare, while that colour's alpha covers something; emissive when it binds an
emissive_texture or states a non-black emissive. A material that provides
neither stamps nothing and says so in the log.
The @builtin::components.DecalProjector component is the authoring front end;
it calls into this registry. Use the module directly for code-driven projectors.
A projector's entry lasts as long as its entity: when the entity is despawned,
whatever despawned it, its id leaves the registry.
Surface
| Function | Meaning |
|---|---|
set(e, opts) | Register entity e (ref or id) as a projector. opts = { material, opacity? }. Re-calling updates it. |
clear(e) | Stop projecting from e. |
clearAll() | Remove every projector. |
has(e) | Whether e is a registered projector. |
entries() | The live { [id] = { material, opacity } } registry (read by the feature). |
Example
local decals = require("@builtin::modules.decals")
local p = entity.spawn("splat")
p.localPosition = { 0, 3, 0 }
p.localScale = { 5, 5, 4 }
p.localRotation = { 0.70710678, 0, 0, 0.70710678 } -- project down
decals.set(p.id, { material = "@builtin::materials.decal_default", opacity = 1.0 })