← Back to project technical overview

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

ProblemRoot causeFix
Scene too bright at night, no night moodNo night darkening on the scene PPVNegative AutoExposureBias offset
Character emissive patterns overexposed at nightA fixed hundreds-fold multiplier at the end of material Emissive, constant through day and nightMaterial × EffectBrightness scalar (Lerp to 0.03 at night / 1.0 by day)
Skill VFX as bright as daytime at nightSome Niagara materials were not wired to MPC EmissiveScaleBatch-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.

TimeDaylightFactorExposure DimFactor (=1−factor)Skill EmissiveScaleCharacter EffectBrightness
09:00–18:151 (full bright)0 (unchanged)1.01.0
18:15–19:301→0.7620→0.2381→0.7621→0.762
19:30–21:300.762→00.238→10.762→00.762→0
21:30–06:150 (fully dark)1 (max)0.0000240.03
06:15–08:000→0.5381→0.4620.000024→0.5380.03→0.538
08:00–09:000.538→10.462→00.538→10.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)