Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitdf78e4f826

README.md

LensFx

The lens the scene is photographed through, and the film behind it. Add it to an entity and bright sources throw flare, the grime on the front element varies it, and the image carries grain.

local id = entity.spawn("lens").id
entity(id).component.add("LensFx", {
    flareIntensity = 1.0,
    grainIntensity = 0.03,
    dirtIntensity = 0.5,
})

Every field is live — editing one in the inspector changes the look on the next frame, and the values persist with the scene. Setting flareIntensity and grainIntensity both to 0 releases the passes while keeping the rest authored; removing the last one in the scene clears it.

fieldeffect
thresholdLuminance a pixel must reach to throw a flare, with a soft knee below it.
flareIntensityBrightness of the whole flare. 0 is off.
ghostCount / ghostSpacingHow many internal reflections are drawn, and their spacing along the optical axis.
haloWidth / haloIntensityRadius and brightness of the halo ring.
streakIntensity / streakLengthThe anamorphic streak along one axis.
chromaShiftChannel separation inside a ghost.
grainIntensity / grainSizeDepth of the grain, and the size of one grain in pixels.
grainResponseShape of the response to luminance. Higher narrows it toward the midtones.
dirtIntensity / dirtScaleHow much grime varies the flare, and how fine the smudges are.

The component ticks the clock the grain is drawn against, in both edit and play, so the grain is a fresh field every frame rather than a fixed screen pattern.

One lens photographs the whole scene, so one of these per scene is enough — the last one to push wins.

The work runs in lensOptics.renderFeature; the settings live in @builtin::systems.lensFx.lensFx, which is also how to drive them from a script.