Introduction
Tutorials for setting up physically based rendering (PBR) in Unreal Engine using real-world Lux and EV100 values are becoming common. However, once you implement physically correct lighting, you run into game design problems, like "fire effects becoming invisible during the day."
This article explains how to leverage the auto-exposure (Eye Adaptation) effect—like when emerging from a cave—to create a realistic, physically-based day/night cycle while ensuring that "symbolic" effects remain visible regardless of the ambient brightness.
Step 1: EV Value Calculation and Basic Auto Exposure Setup
First, let's set up our camera (PostProcessVolume) and ambient light (SkyLight) to handle a day/night cycle.
1. EV100 Calculation Formula
To perform physically based lighting, we first need to calculate the "correct exposure" (EV100) from the real-world "illuminance" (Lux).
The formula to find the EV100
required to properly expose an 18% middle-gray object based on the illuminance (Lux) hitting it is:
2. Calculate Day and Night EV Values
Let's use this formula to calculate the "limit" values for day and night.
-
Day (12:00 PM):
- Assume bright sunlight is 100,000 Lux.
- 15
- (We'll set it to 18 to give some margin for bright reflections, like snow.)
-
Night (12:00 AM):
- Consider moonlight (0.1 Lux) or starlight (0.001 Lux).
- -8.3
- (Therefore, we'll set the night limit to -8.)
3. Lock Auto Exposure Range to "Physical Limits"
Based on the values from Step 1.2, we'll define the camera's (eye's) adaptation limits in the PostProcessVolume
. Do not change these settings during gameplay.
-
Metering Mode
:Auto Exposure Histogram
(leave as auto) -
Min EV100
: -8.0 (The limit for capturing starlight) -
Max EV100
: 18.0 (The limit for sunlight, including margin)
By fixing this range, the camera will constantly try to auto-expose (Eye Adaptation) from the darkest places (deep caves) to the brightest (direct sunlight on snow).
(TIPS: In UE 5.3 and earlier, you had to enable Extend default Luminance range
in Project Settings
, but recent versions use this wide EV100 range by default.)
Step 2: Control Day/Night with DirectionalLight "Lux" and "Color"
We'll prepare two Curve
assets to control the DirectionalLight
(Sun/Moon).
-
C_DayNight_SunLux
(for Intensity) -
C_DayNight_LightColor
(for Light Color)
Use these curves to update the DirectionalLight
values on a Tick event. (For debugging, it's helpful to create a system where one day loops every 24 seconds by adding DeltaTime * 0.1
to the time.)
1. "Lux" Curve (Physical Light Intensity)
- Day (12:00): 100,000 Lux (Clear sky sun)
-
Night (0:00): 0.1 Lux (Moonlight)
2. "Color" Curve (Artistic Color)
-
Day (12:00):
(R:1.0, G:1.0, B:1.0)
(Pure white) -
Night (0:00):
(R:0.1, G:0.1, B:0.15)
(A faded dark gray, slightly blueish)
Why change the "Color" too?
Since our Min EV100
is set so low (-8.0
), the camera sees the dark night scene (0.1 Lux) as 'underexposed' and automatically boosts its sensitivity (EV value) to -8.0
to compensate.
The result is a bright, noisy image that looks like daytime, not the dark night scene we intended.
While the correct approach might be to control the PostProcessVolume
's Exposure Compensation
value (e.g., setting it to -5.0 at night), tuning that curve can be tedious.
So, for this simple example, we'll use a more direct method to create the "nighttime feel": intentionally setting the Light Color
to a "dark gray." Auto Exposure will still try to brighten the scene, but because the light source itself is a dark gray, the final image will be desaturated and have the intended "nighttime" atmosphere.
Step 3: Protecting "Symbolic Effects" from Exposure
Now for the main topic. Let's display a fire magic effect (material emissive brightness: 3000 cd/m²
) in this physically-based world.
At Night: The
EV100
is around-8.0
(settings for a bright picture), so the effect glows brilliantly.
At Day: The
EV100
is around18.0
(settings for a dark picture). Compared to the100,000 Lux
sunlight, the3000
brightness value is tiny, and the effect becomes almost invisible.
This is physically correct, but it will lead to a storm of complaints from players ("I can't see the hitbox!"). We can't use "it's physically correct!" as an excuse for symbolic, gameplay-critical effects.
[Solution] Cancel Exposure Compensation in the Material
Instead of making separate effects for day and night, we can solve this with a single material. Luckily, UE provides a node to get the current camera exposure compensation value.
- Open the material used by your effect.
- Add the
EyeAdaptationInverse
node.- This node returns a large value when the camera is trying to darken the scene (daytime) and a small value when it's trying to brighten it (nighttime).
-
Multiply
your originalEmissive Color
calculation by thisEyeAdaptationInverse
node.
(Note: If you are on an older version and can't find the EyeAdaptationInverse
node, you can get the exact same result by adding the *Exposure (Eye Adaptation)
** node and Divide
-ing your original Emissive Color by it.)*
Result
By applying this material, the effect will now maintain its intended perceived brightness regardless of the scene's exposure (day or night, inside a cave or out).
Summary
- EV100 Formula: Calculate day/night exposure limits (e.g., -8 and 18) based on .
- EV Min/Max (Range): Fix the
PostProcessVolume
's EV range to these limits (e.g., -8 to 18) for the entire game.- → This keeps "Eye Adaptation" (bright/dark adaptation) constantly working.
- SkyLight: Enable
Real Time Capture
.- → Allows it to automatically follow changes from the
DirectionalLight
.
- → Allows it to automatically follow changes from the
- DirectionalLight (Intensity & Color): Dynamically change using
Curve
assets.- → Use
Lux
for physical brightness andColor
(dark gray) for artistic "nighttime feel."
- → Use
- Symbolic VFX: In the material, Multiply the
Emissive Color
byEyeAdaptationInverse
.- → This cancels the exposure compensation, maintaining a consistent perceived brightness.
Using this method, you can balance physical accuracy with the "symbolic" readability required for games.
Top comments (0)