How Epic Games optimized Unreal Engine for Fortnite Battle Royale ?

Sagar
5 min readJul 14, 2018
FORTNITE BATTLE ROYALE

How big is Fortnite ?

40 million players a month! Over 4 million players at a time! And still growing!! Within less than 1 year from the release of Battle Royale, Fortnite has become one of the most played games of all time. How crazy is that! Epic games has certainly lived upto their name by creating a really EPIC GAME!

Curious to know how this was made possible, I decided to dive in and do some research.

Let’s find out!

Below are some of the advancements which EPIC had to make in order to optimize ue4 for Fortnite Battle Royale.

Significance manager:

Significance manager divides the players into different buckets priority wise and the feeds this priority to different game aspects. Visible players are set at higher priority. Players closer are higher priority players. This data is immensely useful to decide where to spend the computation power of the server where the game is running.

Different bucket sizes for different platforms. Console has more players in higher priority bucket, mobile has less.

Animation:

Fortnite has 1 character with 4 other meshes (head+body+bag+weapon). Each part has its own animation blueprint. The animations work by taking a base body animation and then combining it with component animations.

What didn’t help? → 100 players will have around 500 meshes and all the animation calculation needs to be done every frame, so one way was to use Skeletal mesh LODs, which significantly reduced the bone count, however it didn’t help in improving the game thread time, because the LODs are processed on a different worker thread. Epic had initially, in Unreal Tournament 3, merged different meshes. But in Fortnite, they wanted to keep things flexible. Also, merging would mean that every player has unique mesh, which in turn would increase the memory usage.

What worked? → The Unreal Engine animation system breaks into three major steps: Update(Gather information from game-state) → Evaluate(Heavy animation decompression, blending. This can happen off worker threads) -> Completion (send all data to render thread, update any attachments and fire any Anim-Notify events). The animation nodes were written in blueprints which took around 0.93 ms to process. So they moved it to C++ improving its performance to 0.19 ms!

Some optimization hacks that Epic used:

Fast Path for animations:

Fast path animation system, when enabled makes sure that any member variables used for running the animations are accessed internally rather than using blueprint calls. This is suitable to use when the variables are accessed directly without any modifications in the animation blueprint. A thunderbolt mark appears over such nodes. It can be enabled from the project settings.

No fast path(left) vs fast path(right)

Epic has disable tick for off screen meshes in Fortnite! Which means, What you don’t see on the screen is not animated at all. They have avoided animating weapons after a certain distance. On mobile however, only our own weapon is animated.

Static rendering mesh:

Rendering skeletal meshes as static. (Used for supply drops)

Update rate optimization (URO):

Running animation less than frame-rate. It comes with an inbuilt option of whether you want to interpolate between frames or not.

Some components in the game have physics driven animations. Initially Epic used AnimDynamics after which they switched into RigidBody anim node which is a single node with greater speed and better options. A whole other post can be made on creating and using Physics based animations using these nodes.

Animation Bounds Calculation:

Fortnite has all the trending dance moves, emotes and what not! This makes it difficult to keep a single bounding box for the Skeletal Mesh. Hence is calculated every frame. It is derived from PhysicAssets.

Animation notify

Footstep, sound, particle, weapon trails. Epic converted all the logic to C++.

Auto Manage Attachment

The logic behind this is to not do any work on things that haven’t moved. This feature is available for Particle Effects and Sounds. (4.19)

Generating overlap events:

Checking if something is overlapping is usually one of the slowest process in the game. Generate overlap events was switched off wherever it was not necessary. Another way to effectively manage overlap events was to know the attachment hierarchy of any object and avoid calling overlap events to it’s child attachments wherever unnecessary .

Moving Components:

Player has a capsule which acts as its collision. Instead of checking for collision every frame, the capsule teleports between transforms it gets from the server. This is used to make the game even lighter on mobile platform.

Spawning Objects:

C++ components are faster to spawn than BP. Used pooling for spawning walls, buildings, loots and other quick spawns.

Particle Pooling:

Used pooling for particles. The sets of these particles are kept in the level hidden and used as required.

Reducing the work done every frame:

Epic converted some of the HUDs from blueprints to C++. They added invalidation panels to widgets. Widgets with invalidation panels are not updated every frame.

‘Dumpticks enabled’ console command — lists out all tick functions currently scheduled every frame. This can help developers to spot things that happen every frame which might not be necessary.

Time of day system runs every tick. It collects material parameters and changes. Epic modified it to sends only one command regardless of parameters were changed which again saved some ms of time.

Reduced soundcue evaluation

Texture streaming:

Is made slower in level and faster in the menu, where the player changes skins.

Level Streaming:

Level streaming makes sure that only a part of map is loaded dynamically. This reduced memory usage, increases map variety, optimizes rendering and game-play. Level streaming works as follows: load data → i/o(worker thread)→ de-serialization( data to memory)(asynchronous loading thread) → post-load(cannot do this off game thread hence we time-slice adaptive timestep). Example: While skydiving, level needs more time to load and hence we give it 5ms for postload, and when walking we give it 3ms.

Overlap level loads:

The trick is to start the i/o for the next level while post loading a previous one. Saving a few more ms.

In short! Epic saved space and time wherever they could.

These were few of the Optimizations that EPIC GAMES made in order to run Fortnite battle royale at such a large scale. There is a lot more going on which I would soon be posting in upcoming articles. I hope you learned something new while reading this article!

Good day!

--

--