Reflection Update in Fortnite

Hey folks,

Just wondering if Epic has talked anywhere about their strategy for updating reflections in Fortnite with their time of day changes?

This remains a stumbling block for me in my project for a number of reasons.

  • Updating the sky causes a fairly massive frame hitch.
  • I’m unable to use reflection captures in levels for local reflections because the base luminance varies substantially between day and night.
  • Because of this I use a global reflection that’s just captured from the sky, but elements like the Fog have a huge influence on the brightness and color of the reflections, and I can’t adjust them independently. This often results in objects feeling like they’re lit from below or from the sides primarily.
  • This could potentially be mitigated by manually setting the lower hemisphere color in the skylight, but this doesn’t seem possible at runtime.

Fortnite’s reflections look quite good under most conditions I’ve seen, and their scenes are quite varied, so I’m wondering how they’ve accomplished it. Do they have their own in-house solution? Is their ToD done only through postprocessing? Has the team talked about this publicly and if not would they be willing to? Does anyone else have solutions to some of these problems?

Thanks in advance,


At the recent GDC there was some talks about Fortnite’s visuals - lighting, imposters, visuals in general. And I did not notice that some of the speakers mentioned about reflection update (maybe I missed it). Also, I asked, if they made some significant changes in the rendering system exsclusively for Fortnite, and the answer was - No. The game uses nearly the same rendering system as ordinary ue4.
So, do you have some information that they update reflections? Or you just think they do it? Maybe, with stylized visuals it’s enough to do some HSV manipulations with already captured reflections… Anyway the question is interesting and it would be good to know if it’s possible

maybe this will help you but i noticed a checkbox in the skylight where you can only capture emissive light and not cause the hitches

@Yura_s thanks, that’s actually the talk that inspired me to create this thread!

@Amiot unfortunately I’m actually already using that but Recapture Sky still takes 1-2ms which is pretty massive when trying to stay within 16.67ms

The native sky capture forces a rebuild of a lot of things in the scene. The capture was never meant to be done at runtime, but if you can’t do your own sky capture system I believe a work around was using textures instead of a scene capture and jumping between those. I don’t remember if there’s a blend option though, but it might be another method to look into.

A solution I sometimes use for games with a variable time of day is to update the sky color tint over time with a color curve to fake it. It works well enough if you get the right settings, you generally can’t tell the difference between an actual recapture and that.

For our project that has day/night cycle we’v ended having commandlet that iterated over the whole cycle (24 steps - 1 for each hour) and rendered all reflection probes, the the commandlet then created textures from that data

UBoxReflectionCaptureComponent *Ref = <your reflection component>;
FReflectionCaptureData ReadbackCaptureData;
GetWorld()->Scene->GetReflectionCaptureData(Ref, ReadbackCaptureData);
if (ReadbackCaptureData.CubemapSize && ReadbackCaptureData.FullHDRCapturedData.Num())
    <create cubemap from ReadbackCaptureData.FullHDRCapturedData>

and then it changed all reflection captures to SpecifiedCubemap type, and set first of these captures as source (all this while building package).

Then at runtime when the time shifts we iterating over reflection captures, and change their textures (need to async upload them up front, need to watch out to not change all of them in a single frame, etc.) - but this basically allows us to avoid all the hitching. (We’v modified source code around reflection captures to allow easy and efficient upload of custom cubemaps at runtume, but this is not a big change).

Hope that helps.