When exporting Unreal Engine spot lights from a level to USD, lights with identical EV intensity and source radius settings but different outer cone angles produce inconsistent intensity values in the exported USD file.
The root cause seems to be in UsdToUnreal::ConvertLuxShapingAPIIntensityAttr (and my other places where this similar conversion happens for spotlight), the light area in square meters is computed as:
float SolidAngle = 2.f * PI * (1.f - GetSpotLightCosHalfConeAngle(OuterConeAngle));
float AreaInSqMeters = FMath::Max(SolidAngle * FMath::Square(SourceRadius / 100.f), KINDA_SMALL_NUMBER);
It seems the FMath::Max(…, KINDA_SMALL_NUMBER) guard was intended to prevent division by zero. However, because KINDA_SMALL_NUMBER = 1e-4 and the clamp triggers when: SolidAngle × (R/100)² < 1e-4
For example for source radius 1 any cone angle below 32.77°, the area is hard-clamped to 1e-4 regardless of the actual solid angle, making all such lights produce identical — and incorrect — intensity values.
The fix we have internally so far:
Move the clamp inside the expression so it applies only to the radius term, not to the combined product:
// BEFORE
float AreaInSqMeters = FMath::Max(SolidAngle * FMath::Square(SourceRadius / 100.f), KINDA_SMALL_NUMBER);
// AFTER
float AreaInSqMeters = SolidAngle * FMath::Max(FMath::Square(SourceRadius / 100.f), KINDA_SMALL_NUMBER);
To be sincere I’m not convinced the actual formula actually represent what happens in engine, I could be wrong here but what I observe happening in engine is in order to preserve the same visual brightness of a light when it’s outer cone increases I also need to increase it’s lumens intensity. But when exporting those lights to USD the oppose of what is set in the engine happens where the intensity value grows bigger as we the outer cone decrease.
It would be great if someone could explain what is the logic behind this.