Three independent "day-night brightness controls" originally ran on different curves; when the night ambience was darkened, character and skill emissive still carried a hundreds-of-times daytime multiplier, blowing out. All three were unified on one shared curve, GetDaylightFactor, and each consumer takes what it needs.
— Origin of the V61 unified curve
1. Three Independent Problems → One Unified Solution
| Problem | Root cause | Fix |
|---|---|---|
| Scene too bright at night, no night mood | No night darkening on the scene PPV | Negative AutoExposureBias offset |
| Character emissive patterns overexposed at night | A fixed hundreds-fold multiplier at the end of material Emissive, constant through day and night | Material × EffectBrightness scalar (Lerp to 0.03 at night / 1.0 by day) |
| Skill VFX as bright as daytime at night | Some Niagara materials were not wired to MPC EmissiveScale | Batch-add Multiply × CollectionParameter(EmissiveScale) to 52 emissive materials |
2. The V61 Authoritative Curve (Shared by All Three Consumers)
The static function ATimeOfDayManager::GetDaylightFactor(float Hours) returns a factor from 0 (fully dark at night) to 1 (fully bright by day). The exposure/skill/character consumers each use either "1 − factor" or factor directly.
| Time | DaylightFactor | Exposure DimFactor (=1−factor) | Skill EmissiveScale | Character EffectBrightness |
|---|---|---|---|---|
| 09:00–18:15 | 1 (full bright) | 0 (unchanged) | 1.0 | 1.0 |
| 18:15–19:30 | 1→0.762 | 0→0.238 | 1→0.762 | 1→0.762 |
| 19:30–21:30 | 0.762→0 | 0.238→1 | 0.762→0 | 0.762→0 |
| 21:30–06:15 | 0 (fully dark) | 1 (max) | 0.000024 | 0.03 |
| 06:15–08:00 | 0→0.538 | 1→0.462 | 0.000024→0.538 | 0.03→0.538 |
| 08:00–09:00 | 0.538→1 | 0.462→0 | 0.538→1 | 0.538→1 |
Curve Parameters (Tunable Levers)
constexpr float NightDimMaxEV = 4.0f; // 夜晚最多压暗的 EV(±1 EV ≈ 亮度 ×2 或 ÷2)
constexpr float DawnStartH = 6.25f; // 06:15 开始恢复
constexpr float DawnAccelEndH = 8.0f; // 08:00 加速段起点
constexpr float DawnRestoreEndH = 9.0f; // 09:00 完全恢复
constexpr float DuskStartH = 18.25f; // 18:15 开始压暗
constexpr float DuskAccelEndH = 19.5f; // 19:30 加速段起点
constexpr float DuskEndH = 21.5f; // 21:30 全暗
constexpr float NightEndH = 6.25f; // 06:15 结束
constexpr float NightEffBright = 0.03f; // 角色发光夜晚值(角色材质 Multiply)
constexpr float NightEmissive = 0.000024f; // 技能特效 MPC 夜晚值
3. Exposure Darkening Implementation (AutoExposureBias)
Iron rule: the sign of UE's AutoExposureBias — positive = brighter, negative = darker (each ±1 EV ≈ brightness ×2 or ÷2). The V48 initial version had the comment wrong, saying "positive = darker"; following the comment made night brighter as exposure increased.
// TimeOfDayManager.cpp · ApplySunMoonIntensity() V61 块
// 缓存 PPV 的原始 EV 基值(避免每帧把上次写入值当基值导致漂移)
float CachedBaseBias = PPVCache.Get(PPV); // 首次读取 PPV->Settings.AutoExposureBias
const float DimFactor = 1.0f - GetDaylightFactor(CurrentHours);
const float Offset = NightDimMaxEV * DimFactor;
PPV->Settings.AutoExposureBias = CachedBaseBias - Offset; // 负方向 = 变暗 ✓
4. Character Material EffectBrightness Wiring
Each of the 6 emissive parent materials (M_角色_Emissive / M_角色_Body / M_角色_Clothes / M_角色_Fur / M_角色_Hair / M_角色_Ribbon) gets a new Multiply node chained into the new scalar parameter EffectBrightness (default=1) before the EmissiveColor output.
// TransformCharacter.cpp · UpdateEffectBrightness()
// 白天=1(保持原大乘数不变),夜晚=0.03(压暗到接近默认)
const float Target = FMath::Lerp(NightEffBright, 1.0f,
ATimeOfDayManager::GetDaylightFactor(GetCurrentGameHours()));
// 对每个骨骼/静态网格材质槽创建 MID 并设 EffectBrightness
for (auto& Slot : MeshComponent->GetMaterials()) {
UMaterialInstanceDynamic* MID = MeshComponent->CreateAndSetMaterialInstanceDynamicFromMaterial(i, Slot);
MID->SetScalarParameterValue(TEXT("EffectBrightness"), Target);
}
5. Skill VFX MPC EmissiveScale Wiring
For the 52 skill emissive materials, a Multiply × CollectionParameter(EmissiveScale) node is added at the end of the parent material chain, referencing the MPC /Game/TimeOfDay/MPC_GlobalEffectBrightness. TimeOfDayManager writes the MPC every frame, and the three day-night curves are driven uniformly.
6. Reuse Points (Future Bright/Dark Tuning)
- Night too bright → increase
NightDimMaxEV(e.g. 4→5); too dark → decrease (e.g. 4→3). - Darkening start/end times off → only the four floats
DuskStartH/DuskEndH/NightEndH/DawnRestoreEndHneed changing. - Character emissive overexposed at night → raise
NightEffBrightfrom 0.03 to 0.05. - Temporarily disable the whole darkening → set
NightDimMaxEVto 0, or assign 0 to the consumer'sDimFactor. - Add a new emissive parent material → remember to also insert "Multiply × EffectBrightness", or that material will not be controlled by day-night scaling.
- Sign iron rule restated → UE exposure bias negative = dark. Verify before copying any engine exposure comment; the V48 comment had the sign reversed.