"Projected decals conform to runtime model renderers"
▸ SYMPTOM
You need a paint/splat/impact system that works on procedurally built terrain (voxel chunks, runtime meshes) and wonder whether projected decals will actually conform to those surfaces, or if they only work on static scene geometry.
▸ CAUSE
Runtime chunk meshes are normal ModelRenderer components. The engine's Sandbox.Decal projects its box volume onto any ModelRenderer geometry within range — there is no distinction between editor-placed and runtime-built meshes. Decals project onto whatever surfaces fall inside the projection volume.
▸ FIX
Use Sandbox.Decal for paint/impact/splat systems on runtime terrain:
-
Orient the projection axis to the hit normal:
Rotation = Rotation.LookAt(hitNormal)— the decal's projection axis is local +X (theGetDecalVolumeputsDepthon X), so orienting +X to the trace normal makes the box straddle the surface. -
Tune Depth to control wrap reach — how far the projection box extends through the surface.
-
Set
AttenuationAngle(0 = paint all faces within the box, 1 = fade at grazing angles) to control how aggressively the decal wraps around corners and trunk faces. -
Persistence:
LifeTime = 0holds the decal persistent (no native fade).Transient = truehands eviction to the engine'sDecalGameSystem(maxdecals, default 1000, Protected). -
Custom cap: manage a ring buffer yourself for a game-dialable cap with fade-on-recycle, keeping the visual derivation a pure function of replicated inputs so peers running different caps render the same marks.
Note: a brush remesh rebuilds a chunk and drops its decals — this is acceptable (repainting terrain clears its paint).
▸ WHY IT WORKS
The decal system operates at the scene-object level — it projects onto any ModelRenderer's geometry that intersects its volume, frustum-culled per frame. Runtime-built meshes assigned to a ModelRenderer are indistinguishable from editor-placed ones in the rendering pipeline, so the projection "just works" without any special setup.
- Published