article · 2026-04-03

Stealth Light Detection in UE5: Driving 'Hidden or Lit' from a Measured Light Level

Read a real 0-1 brightness at the player from the rendered scene, and let shadow, skylight and Lumen bounce decide whether the guards can see you.

Lumen Meter
Featured on Fab Lumen Meter Measure and analyse Lumen lighting in real time, in the editor.
$5.99 Get on Fab →
3
Brightness outputs (Raw, Normalised 0-1, Smoothed)
2
Capture modes (Directional, Omnidirectional)
5.99
Price (USD)

What a stealth visibility value actually needs

Every stealth game lives or dies on one question the player asks constantly: am I in shadow, or am I lit? Getting that answer to match what the screen shows is the hard part of stealth game light detection in Unreal Engine. The classic approach is to walk the lights near the player, check distance and cone angle for each, and sum up a 'how lit am I' score. It works in a flat test room and falls apart the moment real level lighting arrives.

The problem is that a per-light distance check does not know about the world between the light and the player. It cannot see that a crate is casting a shadow across the alcove, that the skylight is filling the room with ambient even though no point light is near, or that a bright wall is bouncing indirect light into a corner you assumed was dark. Your detection score says 'hidden' while the player is clearly standing in a pool of light, and trust in the mechanic evaporates.

What you actually want is a single number that says how bright this exact spot looks, with everything already folded in: direct lighting, shadows, the skylight, and global-illumination bounce. Feed that number through a threshold and you have a 'hidden or lit' value that agrees with the camera, because it was measured from the same rendered image the player sees.

That is the gap Lumen Meter fills. It is a drop-in Unreal Engine tool that measures local scene brightness by re-rendering the scene from its own position and reading back the average luminance, then reports it as a raw value and a dynamically calibrated 0-1 normalised value. Because it samples the rendered scene as a post-process, the reading already includes global, static and dynamic lighting, shadows, skylight and Lumen GI bounce. No per-light tracing, and nothing for you to keep in sync with the artists' lighting passes.

Reading a normalised 0-1 light level at the player

The unit of currency for stealth logic is the normalised brightness output. Lumen Meter exposes three readings you can pull at any time: Brightness Raw (the CPU-side average luminance), Brightness Normalised (a 0-1 value), and Brightness Smoothed (the same reading after temporal smoothing). For a hidden-or-lit check, Brightness Normalised is the one you want, because it maps cleanly onto a threshold between 0 and 1.

The normalisation is automatic. Lumen Meter uses dynamic calibration: it tracks the lowest and highest values it has seen and normalises the current reading against them, so you do not have to hand-author brightness bounds for every level. As the meter observes the darkest shadow and the brightest spotlight in an area, the 0-1 scale settles onto that level's real dynamic range. That matters for stealth, because 'lit' in a moody crypt is a very different absolute luminance from 'lit' on a floodlit rooftop, and a fixed threshold against raw luminance would never transfer between the two.

To read brightness at the player rather than at a fixed spot, attach the meter to a moving actor. Lumen Meter is a drop-in actor, BP_LumenMeter, that you can either place in the level or attach to an existing actor to read brightness as it moves. Parent it to your character (or a socket on the capsule) and it reports the local brightness wherever the player walks. Turn on Enable Realtime Capture with a Loop Duration to get continuous reads, or call it on demand if you only need a sample at specific gameplay moments such as a noise check or a guard's line-of-sight test.

There is a real authoring choice here between two capture modes. Directional mode takes a single fast 2D capture in one direction, which is the right default for a real-time game where you are sampling every frame or every few frames. Omnidirectional mode takes a cube capture averaged over its faces for the most accurate reading, at higher cost. For a player-attached stealth meter, start with Directional pointed the way the character faces or straight up, and reserve Omnidirectional for moments where accuracy genuinely matters more than frame budget.

One detail worth respecting: the reading is exposure-independent by design. Lumen Meter forces auto-exposure to manual and disables the tonemapper, bloom, eye adaptation and volumetric fog while it samples, reading pre-tonemap linear luminance. That means your stealth value reflects the scene's actual lighting and does not drift just because the player's camera adapted from a dark room to a bright doorway. Your threshold stays meaningful.

Reacting to the Brightness Level Change event

You rarely want to poll a brightness value in Tick and run a threshold comparison every frame if you can avoid it. Lumen Meter fires a Brightness Level Change event when the reading changes, which gives you a clean place to hang your stealth state machine. Bind to it, compare the new normalised value against your hidden and lit thresholds, and only update visibility state when it actually crosses a boundary.

Here is a practical wiring for a hidden-or-lit gate.

1. Attach BP_LumenMeter to your player character, set Capture Mode to Directional, enable Realtime Capture, and pick a Loop Duration that suits your game's reaction time (a few times a second is usually plenty for stealth).

2. In your character or an AI-perception manager, bind to the meter's Brightness Level Change event so your code runs whenever the reading moves.

3. In the handler, read Brightness Normalised (or Brightness Smoothed if you want to ride out flicker) and compare it against two thresholds, for example below 0.3 is 'hidden' and above 0.5 is 'lit'. Using two values rather than one creates a hysteresis band so the player does not flip between states on the edge of a shadow.

4. When the value crosses into 'lit', open the door for detection: let nearby guards' sight checks succeed, raise the suspicion meter faster, or brighten a UI 'you are exposed' indicator. When it drops into 'hidden', clamp detection back down.

5. Feed the same normalised value into your existing AI sight model as a multiplier on perception range or detection speed, so being half-lit reads as partially visible rather than a hard binary.

Reach for Brightness Smoothed when you want the stealth state to feel deliberate rather than twitchy. It is the reading after temporal smoothing, so a candle flickering or a sweeping searchlight will not strobe the player in and out of cover. Use the unsmoothed Brightness Normalised when you want instant, honest feedback, such as a quick crouch into a doorway shadow.

Keeping the scale consistent across a level

Dynamic calibration is convenient, but it has a consequence for stealth: a meter calibrates against the range it personally has seen. If your player-attached meter has only ever been in a dim corridor, its 0-1 scale is calibrated to that corridor, and stepping into a brightly lit hall can read differently than you expect until the calibration catches up. For a single moving meter this usually settles quickly, but if you use several meters, or you want one stable definition of 'lit' across a whole area, you want them to agree.

Lumen Meter supports synchronisation for exactly this. Turn on Enable Synchronisation and meters can sync calibration across the map, or by distance, so they share one normalised scale across an area. The shipped sync uses BP_LumenMeterLock together with the DA_LumeMeterLock data asset, and exposes Sync Distance and Sync Lock controls. For stealth design, this means a guard-mounted meter and a player-mounted meter can be judged against the same 0-1 yardstick, so 'lit enough to be seen' means the same thing for everyone in the room.

If you are placing static probe meters around a level to author lighting to spec, the same synchronisation keeps their readings comparable, which is useful when you are tuning the dark routes a player is meant to be able to use. And because Lumen Meter works in-editor, the in-world TextRender readout shows the live light level without entering play, so you can see exactly how dark that intended shadow route really is while you are still building it.

Why a rendered-scene read beats per-light distance checks

The deciding advantage is correctness for free. Because Lumen Meter measures the rendered scene rather than reasoning about light sources, the reading is plugin- and technique-agnostic: it works with dynamic and static lighting regardless of how the scene was built, and it captures occlusion, skylight and indirect bounce automatically. A per-light approach has to re-implement all of that, badly, and you have to maintain it every time the lighting changes. With a measured read, when an artist moves a light or rebuilds the lighting, your stealth values track the new scene with no code change.

It also collapses a pile of special cases. Shadows from level geometry, a character standing in their own cast shadow, a dark room lit only by skylight, a corridor lit only by GI bounce off a bright floor: a distance-summing detector mishandles all of these, while a scene read just returns the brightness that is actually there. The technique is the same whether Lumen is on or off, because it is reading the final rendered luminance either way.

The honest trade-off is cost and render-path dependence. Lumen Meter samples by re-rendering the local scene with a SceneCaptureComponent, so each reading is a small extra capture, and because it reads the rendered output the value is tied to your render path. In practice you manage this the way you would any capture-based feature: use Directional mode for the per-frame player check, keep Loop Duration sane, and switch to Omnidirectional only where the extra accuracy earns its cost. For most stealth games, one player-attached Directional meter on a modest loop is all the mechanic needs.

If you want to confirm your stealth values match what the camera shows, it is worth observing the meter and the scene side by side rather than trusting numbers alone. Mythic Dev Assist, our agent-native editor bridge, can capture framed screenshots and read back live world state from outside the editor, which makes it straightforward to verify that 'hidden' really looks hidden and 'lit' really looks lit across your test spots before you ship the mechanic.

Getting started

Lumen Meter ships as a Blueprint-only Unreal Engine project (a 5.6 project) containing BP_LumenMeter, a demo map, the render targets and the post-process materials it uses. Open the shipped project to try it, or migrate the LumenMeter content into your own project to use it for real. Drag BP_LumenMeter into the level to test a fixed spot, or attach it to your character to read brightness as the player moves.

Because it is delivered as a Blueprint with no manual brightness bounds to set, it auto-configures and starts reading immediately, and you can open the Blueprint and extend it to fit your stealth system: add your own threshold variables, expose extra events, or route the normalised value straight into your AI perception component. Start with one player-attached Directional meter, bind the Brightness Level Change event, pick your hidden and lit thresholds, and you have a stealth visibility value that agrees with the screen.

Per-light distance checks vs a measured scene read

ConcernPer-light distance checkLumen Meter scene read
Shadows from geometryIgnored unless you add manual occlusion tracesIncluded automatically (samples the rendered scene)
Skylight / ambient fillNot representedIncluded in the reading
Lumen GI bounceNot representedIncluded in the reading
Static vs dynamic lightingHandled differently per light typeTechnique-agnostic; same read either way
Maintenance after a lighting changeRe-tune detector logicTracks the new scene with no code change
OutputA custom summed score you defineNormalised 0-1 value plus raw and smoothed

Why a rendered-scene brightness value is the more robust basis for stealth visibility.

FAQ

How do I tell if the player is in shadow in Unreal Engine for stealth?

Measure the local light level at the player rather than summing nearby lights. Attach Lumen Meter's BP_LumenMeter to your character; it re-renders the scene from that position and returns a normalised 0-1 brightness that already includes shadows, skylight and GI bounce. Compare that value against a threshold to decide hidden or lit.

What does the normalised 0-1 brightness value represent?

It is the current scene luminance at the meter, scaled against the lowest and highest values the meter has dynamically calibrated to for that area. That makes a single threshold meaningful across very different lighting, because 'lit' is relative to the level's own dark-to-bright range rather than an absolute luminance you would have to hand-tune.

Do I have to poll the value every frame?

No. Lumen Meter fires a Brightness Level Change event when the reading changes, so you can update your stealth state only when the value actually moves. Enable Realtime Capture with a Loop Duration for continuous reads, or call the meter on demand at specific gameplay moments.

Does it work with both Lumen and baked lighting?

Yes. Because the reading samples the rendered scene as a post-process, it is technique-agnostic: it captures global, static and dynamic lighting, shadows, skylight and Lumen GI bounce regardless of how the scene was built. The reading is render-path dependent, but the technique is the same whether Lumen is on or off.

Which capture mode should I use for a stealth game?

Start with Directional mode, a single fast 2D capture, for the per-frame player check in a real-time game. Reserve Omnidirectional mode, a cube capture averaged over its faces, for moments where accuracy matters more than frame budget.

Get it on Fab

Lumen Meter

Read local scene brightness so you can light to spec. An in-editor probe that measures and analyses Lumen lighting in real time — no more eyeballing exposure.

$5.99USD · one-time · free updates
Report a bug