UE4 big-level optimization and level streaming

Hi everyone.
I am working on some untitled game on UE4 and we are creating a world/map approximately 2x2km+ size and I have a few questions, just like you about your projects :wink: . So I created this topic for discussion “Level optimization”

I watched epic’s videos about level streaming, hlods, impostors, fortnite optimization, and so on. But, for me it’s just “we have such technologies, so try it yourself” and I tried.
So I have several solutions and want to share and discuss them with you (each line is my thoughts without practical use, only theory, because at the moment I am only studying cases for big-level optimizations and will practice in the near future):

  1. World Composition - good thing for creating big/huge levels, for others World composition is weak tool (it has weak points with streaming, it can stream level behind the character. As I understand it isn’t rendering, but it streaming in vram).
  2. Level Streaming Volumes - almost the same tool as World Composition but with customizable Volume shapes for activating streaming, and has the above problem with behind the character.
    2a. Currently I have almost created blueprint for Level Streaming levels which shown in frustum ±10 degrees. This is a simple method with simple math.
  3. LOD - probably everyone knows about it, but I will write: LOD - level of Details, load levels depending on the distance from the character
  4. HLOD - usually the same as LOD, the difference: LOD is one mesh/object with own textures, HLOD combines meshes/objects into one large object and creates an atlas to reduce drawcalls. In UE4 it is
    generated automatically. In my “ideal world” it must be created by human or half-automated. Yes - it cost a lot of time, but the result will be better than automatically. And we want to achieve the best result in game, am I right? :wink:
  5. Impostors - an old topic, but unfortunately it is often forgotten. Need additive sheet-texture, but fewer vertices, reduce drawcalls.

I going to try the following scheme:

  • game logic, collision for the whole world (because we can throw a grenade far and it is multiplayer game), sounds, general light in separated layers using 1. World composition
  • level streaming with 2a
  • lod0 for first zone (closest to the character camera)
  • lod1 for second zone
  • lod2 for third zone
  • hlod0 from lod2 objects + impostors for fourth zone (mainly to reduce drawcals because the atlas)
  • hlod1 from lod2 objects + impostors for fifth zone (To Infinity and Beyond!)

What do you think about this?
P.S.: if I make a mistake somewhere I will be glad to hear where I am mistaken

1 Like

Big thing to watch out for with UE and open world stuff is the time spent adding objects to the world. We expected our levels to be dominated by IO – ie, by getting stuff off disk and streaming it in. As it happened (UE 4.13) it was the lifecycle costs of the things coming into the world – making UObjects for them and adding them to the world, and even removing old ones from memory – that really killed us.

Have not run the same tests in current unreal but I’d expect that’s going to be the real driver, so do a bunch of testing with somewhat representative content early. It was an unpleasant surprise for us!

1 Like

Listen to Theodox. This is single handedly the most important test you can perform during open world engine evaluation.

I made my scheme for level streaming:
Yellow - StreamLevelIn, loading into memory, no rendering
Orange - StreamLevelOut, loading into memory, no rendering
Green - show level
Dark Green - hide level

This currently saves 20-50% of memory.

Can someone share a link to the explanation/training of the UE4 Session Frontend -> Profiler ?
Because I can’t find a good documentation, everywhere “there is profiler and it can give you different CPU/GPU stats”

I interested in that hell-shell, a lot of events but almost each event has CPU Stall - Wait for Event with “big ms numbers” and it is REDed and different other “magic for me” things (the picture just an example)

After long procrastination, debugging, updating algorithm I have a little update:
avr FPS +100%
avr RAM usage -60%
avr VRAM usage -30%

Amazing! I’m facing the same issue of many CPU stall when levels are streaming in, so could you give me a brief of how to find the real bottleneck? Thanks~

I don’t have a running unreal at home for the holidays, but I seem to remember that the magic words are “add to world” or some variant of that – it’s the UObject lifecycle management that is (or was, last time I looked) the real killer

CPU stall -> CPU is just waiting :wink: waiting for something… and it can be anything…
I looked through all the stats and in my case the bottleneck was Garbage Collector, so if your “game world” is less than 10x10 km and each object in the game isn’t unique I advise you to turn off GC:

  1. in project settings set +100500 sec for “Time Between Purging Pending Kill Objects” . It generate more minuses (game freezes) than pluses…
  2. set s.ForceGCAfterLevelStreamedOut 0
  3. set s.ContinuouslyIncrementalGCWhileLevelsPendingPurge 0

If a game session lasts more than 10 min you must create your own rules for Forcing GC to save memory

The second bottleneck was occlusion (stat initView). You should consider streaming as a tool for working with occlusion (because it is expensive for the CPU)
Next was - World Tick Time. Use as few ticks as possible, use more timers instead ticks :wink:
and next was - loading some c++ libraries during a game session, instead of preloaded it (in my case, the first grenade throw initiated the library loading … and the grenade throw could happen for example in the 4th minute of the gamesession)

And as mentioned @Theodox “add to world” is the hell of streaming :wink: (look for AddToWorld() )

P.S.: sorry if I forgot something, but this is a very big topic for discussion, where there are a lot of variables for making this or that decision. As I was asked at one of the interviews “what is better, large or small particles in the screen?” … there are a lot of unknowns to give the correct answer (but they didn’t like my reasoning with the arguments of the first and second cases, they expected a clear answer “big or small”)

thanks u so much! your advice inspired me a lot and i now know this is a complicated issue. i found my game has a mixing problem consist of big texture loading, gc hitch, and even navigation system bug. I am step by step fixing them now

i understand from you that you can stream levels that are in yellow area . and that look impressive and good for optimization . but the question is how can you do that in unreal engine .

when u say StreamLevelIn , you mean by level meshes and objects or sublevels or what