To achieve and maintain 60 FPS in Unreal Engine 5, developers must configure project settings from the start by disabling UMG bindings, setting collision complexity to simple, and establishing device profiles with resolution scaling (rendering at 800-1080p and upscaling to 4K using TSR), then implement performance best practices including PCG for world building, Mass for large-scale operations, Nanite mesh LODs, and proper material optimization, while using Unreal Insights and automated testing to monitor and return to target frame rate throughout development.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
How to Start Your Project at 60 FPS and Keep It There | Unreal Fest Chicago 2026
Added:Welcome everybody. Or should I say a vast mateies and uh really quick before we get started, please remember to silence your phones. Don't worry about taking pictures of the slides. I'm going to have a QR code at the end which will take you to my link tree which will show you an Epic Developer community article where I wrote all this stuff down for you. So, uh, that out of the way, welcome everybody to a talk that I wanted to title the journey to 16 milliseconds begins with a single step colon. Hitting 60 frames per second with high quality visuals on Gen 9 hardware in Unreal Engine 5, and keeping it there.
But character limits foiled my ambition.
Uh, speaking of me, hi, my name is Matt Oel. I am a principal technical artist on the developer relations team at Epic Games. I have been doing technical art for most of the time that I've been in the games industry. And technical art, as we all know, has a very definition of what it means to which company, who does what kind of things. But throughout all of the technical art that I have done, I've always been doing performance. I've always cared a lot about performance.
And if we've spoken for more than about 30 seconds, you know, I care an awful lot about performance. And it turns out that a lot of people at Epic care about performance and there is always new technology and tools and features going into Unreal Engine 5 to support that.
And when we started there was a lot of unexplored territory of how do I do this? How do I make this run in Unreal Engine 5? What features should I be using? And over the last five or so years, we've been filling in the gaps on the map ourselves and with the help of a lot of our customers. So partly what I wanted to do today was highlight the work that my colleagues have done to make the Unreal Engine uh more performant and also give you a guide on starting, staying, and returning to 60 frames per second. And why specifically do we want to talk about 60 frames per second today? Well, a lot of our players really want that responsive feel in their games. And we know that the hardware is capable of running some really amazing stuff in only 16.66 milliseconds.
But we are not going to be talking about going higher than 60 frames per second today because it turns out going from 30 to 60 is about 14 15 milliseconds and then now we're down to 16.66 milliseconds and we want to go up to 120. Great. Do you want to do your game thread in 8.3 milliseconds? That's not what we're talking about today. So, um, we're not going to talk about going higher. It's a lot of effort. So today, like I said, I'm going to do a very, very brief history lesson because I'm going to get really nitty-gritty on what it looks like to build an Unreal Engine game for and at 60 frames per second.
We'll talk about how to monitor to make sure that your game is running at 60 frames per second and what you might need to do to return to 60 frames per second if you stray from the path. So, really quickly, history of Unreal Engine part five.
Um, not going to go too deep into this, but I did want to highlight a lot of the features, the projects, the improvements, and the resources that we've been developing over the lifetime of UE5. And you can see right around, you know, 5.3, Audi and I start doing a bunch of talks to like give people the information that we have learned about how to get things running in Unreal Engine 5 more performantly, things like that. And you can see also the features that we started to add and improve. You know, PSO pre-caching becomes a lot easier in 5.3. Um, we parallelized the render thread in 5.4, parallelized the RHI thread in 5.5. Uh, 56, we get um, fast geo and runtime cell transformers and all the stuff that we've done for Nanite Foliage, things like that. All to help you make big games running at 60 frames per second on Gen 9 hardware. Um, I there was a version of this talk where I went through every single version of the engine and we're just going to talk about 5.8 because I don't have a whole lot of time. So 5.8 8 I feel is the discerning person's Unreal Engine 5. I'm really happy with this release. Uh Megalytes and Iris are now production ready which is going to play into our performance. Um Fast Gio is uh beta. A lot of the a lot of stuff has been smoothed out with Fast Geo. Um we'll talk about that in a second. And the illumin lumen radiance field gather so like lumen light um for for some lower uh lower hardware. Really useful option there. Uh, dynamic res on PC is now an option, which I'm excited about. Uh, and then we've got a lot of shader reduction tools that are coming on in 5.8, as well as some experimental stuff that I'm really excited about, like mesh terrain and nite bindless shaders, as well as improvements to the procedural vegetation editor and world partition streaming insights. Oo.
Um, and we've come a long way on this journey of of learning about the performance of the Unreal Engine and all of our features, building the tools that you need, things like that. Um, and I just wanted to share a little bit with that little bit of that with y'all. So, let's take a lot of those learnings. And this is really everything that I have learned from talking to our customers, from building projects myself, from stuff that we've learned at Epic about how to really build these these huge scale games at 60 frames per second. Um, and this talk is assuming that you have already set up your Unreal Engine studio the epic way. Um, so we're going to tackle this in two stages. It's first day one, day zero really, right after you make the U project, there's some things I need you to do. And then over the course of pre-production and prototyping and things like that, things I want you to keep in mind, features that are in the engine that are going to support you in your ambitions of building these big games at these high frame rates. So, let's look at our very first change list, CL1, right? I made a new U project. I disabled some default plugins. I enabled some other plugins. I set some default project settings. And then I added two INI files to my config folder. Default editor settings.ini and default device profiles.ini. And then of course I tag it so that all this stuff shows up in Jira. And it was, you know, I got I got the change list reviewed, right?
So, uh, there are not a lot of project settings, project settings specifically in UE5 where I'm like, okay, you absolutely positively have to do this if you want to build a game with high frame rate that runs performantly. And there's it's really like three settings and a bonus. So, we all know UMG bindings, right? Where you could like every property in UMG, you could click it and then you could bind it to a function that would update that v variable, right?
Don't use those. Those are legacy. They are very slow. They're executed every frame. I can see them in your insights traces. Please don't use them. Uh and in fact, what's really cool is if you go into your project settings for the editor for editor utility widgets and for um game widgets, you can prevent them from showing up at all. So, you set uh the property binding rule to prevent and you never have to worry about somebody using UMG bindings in your project. The next one that I'm going to want you to set is the collision complexity. Please set this to use simple collision as complex collision as Ari and I like to talk about. I can see it in your chaos visual debugger. Um there's a lot of stuff that is using complex collision and the issue has been compounded by uh maybe some of you haven't been setting the number of lodgs in your nanite meshes and so your fallback meshes which are used for complex collision are also your 2 million triangle quixle mega scans rocks complex collision at 2 million triangles is very very expensive. Um so we can we can get ahead of that by just setting this default setting. Um, and then the other thing that I think would be really helpful is create an editor startup map that is nothing. So that when you open the editor, it's faster to get into the editor. And the faster it is for you to iterate, I think the better it's ultimately going to be for your project.
Um, and this is I think I'm going to get up on my soap box here and talk about defaults in the engine. Um, the engine is set up for people learning the learning to make games the first time. maybe saw a YouTube tutorial. They downloaded uh Epic Game. They downloaded Unreal from the Epic Games Launcher and they wanted to see this cool shader tutorial. And what I know is that all of my primitive components should have evaluate world position offset disabled.
But because that's something that I would have to change engine code to ensure is default, uh we're not going to set that because what I really don't want is is little Timmy uh learning Unreal for the first time to not know why his world position offset shader isn't working. Right? So there are a lot of defaults in the engine that are that make it easier to get things done. But when we're talking about big games running at 60 frames per second, we're going to turn a lot of the stuff off by default and make it opt in. like complex collision. We're going to opt into complex collision rather than opt out.
Um, I'm going to very briefly talk about frame pacing because you're all just going to stay in this room and go to Ari's talk afterward. So, frame pacing, there's a a console variable that is called uh r.gt sync type, the default value of zero. Um, that's kind of more or less what you want to use for PC.
There's some other stuff. Again, Ari's going to go into this. If we're looking at a mobile project, we're going to use R.GT sync type one. And for Gen 9 consoles, we're going to use R.GT sync type 2. And if you want to learn more about that, go to Ari's talk after this.
Uh, he goes into so much depth and I don't want to uh I don't want to rain on his parade. Other thing I'm going to do like, okay, right, I've made a U project. Uh, I've opened the editor the first time. Before I even get to restarting the editor for anything, I'm going to go in and turn off a bunch of plugins and I'm going to turn on some plugins. The two that I really want you to turn on now so that we can start using them later are data validation and the asset referencing restrictions plugin. Data validation gives you a bunch of tools for to write C++ or blueprint validators for literally everything in your project. And asset referencing restrictions means that uh effectively I can make sure that nobody references their developer content in the main world map, which is very helpful. Um you're also going to want to turn off some of these plugins that you might not need. So, for example, if I know which source control provider I'm going to use, I can turn off the source control provider plugins that I'm not using, right? It's I'm at a big studio, we only have one source control, I can turn the other ones off. Same thing with like source code editors. Um, you know, some other stuff that you're probably going to want to turn on is going to be like fast go, a lot of the uh procedural content generation framework stuff, geometry script, those are ones that I usually end up turning on all the time. Anyways, so I've I've changed some project settings. I have updated my my plugins. Am I running at 60 frames per second? Does anybody raise your hand if you think the first time you open a u a new project you're set up to run at 60 frames per second?
Nobody. You are all correct. So, does anybody know why?
No, it's these guys here. Let me zoom in on that. There we go. So, up in the viewport, there is this scalability menu. And you can see that all of the rendering features are set to epic by default.
And the epic scalability groups are your 30 frames pers quality mode. So when I'm looking at the editor right now, I am not looking at the game as it would be in 60 frames per second mode. I'm looking at it in quality mode. And so I need a I need a way to change this. And of course, anybody could just go in and click high, right? That's easy enough.
But because this is the first change list, nobody else has opened this project yet, I have some things I can do to make sure that all of my developers are going to be looking at the 60 frames per second version of the game. So that is where default editor settings ini comes into play. So what I'm going to do, I'm going to put this in my config folder and I have this little scalability group section and all of the the scalability groups are set to two, which is high. And now anytime anybody opens the editor in this project, by default, they're going to get 60 frames per second mode. And if anybody makes any changes to this or if you want to make sure that everybody's running at the correct version, the edits to this are saved in the engine saved config folder. So if you ever need to like reset anybody to default or like you know some software we just have to delete our user preps folder, that's what this is. So uh and this is all going to be in the EDC article at the end. Now, we got to make sure that the game is also doing that, right? And that's what device profiles are for.
This is mandatory if we are trying to run at 60 frames per second. And I love device profiles. They are they are hierarchical. So, I can set up a whole tree of device profiles. Um, every imaginable setting, texture log groups, every sear is something that you can change with a DevO profile and change it all at once. So, I know that like, okay, these are all the settings that I want to be set exactly if I'm running at 60 frames per second. And if you are somebody who has access to the NDA platform folders, we added suggested device profiles for those platforms running at 60 frames per second. So, if you have those that code in your your repo, you can find out what you know, Gen 9 60 frames per second should look like. So, definitely use that as a starting point. Um, one of the things that you are going to be setting in your DevOps profiles is your resolution scaling settings. And this this is the important one. So, what we learned on the Witcher 4 UE5 tech demo last year is to focus on rendering a lot of our resolution dependent features at a smaller dynamic primary resolution anywhere between about 800 and 1080. And then using um, and that's going to be with your R.namic res or R.creen screen percentage console variables and then we use TSR to secondary upscale or to upscale first to our secondary resolution of 1440. And the reason for this is that um we know that TSR can go up to 2x. So you can go from 1080 to 4K, but anything lower than about 1080 it you can start to see some some quality loss there. And so the thinking here is let's use um let's use TSR to go from maybe 800 up to 1440 uh with R.cary screen percentage.game viewport. And then finally we will do a spatial upscale to our final output resolution of 4K where we'll flip everything to the back buffer and render the UI at at the full frame size. And you can tweak the settings here with R.upscale.quality.
This is the slide you can take a picture of. If nothing else, when we are thinking about how do we run a 60 frames per second game in Unreal Engine 5, it is secondary upscaling. We focus on rendering fewer, higher quality pixels and then doing secondary upscaling to get us all the way up to 4K.
Okay, that's the show. Thanks everybody.
Really appreciate your time. No, we're not done. Um, so I'm going to put all of this in my default device profiles. INI.
So something it it might look something like this where uh I have my project. I have a 60 Hz project uh targeting the Windows platform_60.
And I'm going to go through and I'm going to have all of my scalability groups set to two uh for static resolution platforms. Uh messed that up a little bit. So r.se secondary screen percentage.game viewport equals 75 is how we go. 4K to 1440. And then R.creen percentage is for our static resolution platforms. And that's going to be, you know, right around the middle. It's like 900p basically. And then for dynamic res, I'm going to set my frame time budget to 16, maybe 16.66 if you're feeling fancy. Uh, and then the min and max screen percentage for dynamic resolution is going to be between 55 and 75. And that's my 800 to 1080 of 1440.
So this is the other one. Uh, and I'm going to put this in my config folder.
And then if I already know that I have a bunch of platforms I'm going to be supporting, I will put platform specific device profiles and I will set them up automatically from day one. Um, and this is really the the big thing for me is I I think trying to get trying to set all this stuff up when you're in the middle of production can be more of a challenge. And so I think if we do it on day one, we don't even have to think about it. We already know that the that all the console variables are where we want them to be to run at 60 frames per second. Uh there are there are the tricky thing with device profiles is you do have to set them. The engine does not have something that goes ah you have a 60 frames per second device profile. I'm going to use that one whenever I boot up. You do have to have something that selects the device profile. And there's a few different options for this. Um there's an example device profile selector plugin. Um there are some examples in uh the platform engine INI folders and if you want to get really advanced go look at ura settings local that's got a lot of logic for setting devost profiles and there's also uh devost profile selection module and preview device profile selection module that you set in your uh default engine or no your default devost profiles ini.
So, I'm going to make sure that I have something set up that knows, okay, if I'm booting up on this platform, I need to use the 60 frames per second DevOps profile. And that's great. So, now that I've done all of that, I'm going to submit. Great. Ship it. We're done. No, we're not done. Uh because now we have to actually build our game for 60 frames per second. Um, so let's talk about that, right? We're we're in pre-prototype, we're prototype, we're pre-production, and we got to figure out what kind of game we're building, right?
What features do we want to make use of?
What's our platform range that we're targeting? We got to figure out what kind of game we're actually building and how to build it optimally.
And I say building optimally because it's about making sure that the hardware is doing the right work of spawning and loading and simulating, rendering, animating, and all that fun stuff. There are a lot of systems in the Unreal Engine to help with that, knowing the kind of game that we are building, right? And it means I'm going to start talking about a lot of best practices.
Asterisk, >> not allies will qualify. No purchase necessary. Void word prohibited. Context matters. You got to make the game that makes sense to you. I'm making some assumptions about the kind of game that you're trying to make and presenting information most relevant to that kind of assumption. If you don't feel like it applies to you, feel free to ignore it.
I'm not your mom.
>> This section is also meant to bring awareness to a lot of the features of the engine. Um whether for why you might use them to build a game. Right there.
there is a pretty sharp cut off between I can just do it with blueprint and oh I should really be using mass for this right um and the other way to look at this section is like if you asked me here's how I'm going to do it so when I'm building a large scale open world game targeting gen 9 consoles and high quality visuals at 60 frames per second one of the biggest decisions I'm going to make is how I populate and build and stream my world right so world building this is I lump this category of like PCG, world partition, HL lods, and we're also going to talk about our async timing budgets because our goals here are one to improve iteration and construction times for our developers. I really think that this is a factor in building performant games. The faster I can iterate on my game, the more likely I am to be able to make the change that will bring me back to 60 frames per second. And with world building, we're really thinking about reducing the number of active actors, reducing the number of active components instances while still representing a large open world. And PCG is a really big part of this. And I'm going to be a bit of a a a knowledge dump here. So for me, PCG is about empowering artists to work faster and better while still being creative and expressive. Um, things like the level instance to PCG data asset workflow are really powerful for like the artist is in control. The artist is in the driver's seat of what is getting spawned. Um, PCG editor mode gives them a lot of control about where things are getting spawned. We can use the scriptable tools framework to do a lot more stuff. Give the artists a lot of control over how they're building out their world. Um, and 5.8 brings manual editing to PCG. So, if you have a graph and you run it and then you're like, "Oo, that tree needs to be a little to the left." We can now do that in 5.8, which I'm excited about. Um, I also think of PCG as a way to enforce building standards. So, if all of the stuff that's spawned into the world is constructed exactly the way that I want it, I know that my world is being built the way that I have set in my style guide, I don't have to stress out about that. Um, and of course, PCG is not just for geo things like VFX, gameplay objects, audio. We can spawn a lot of stuff with PCG, which improves our iteration times. Now, what I'm definitely going to do as I'm building my 60 frames per second large open world game on gen consoles with high quality visuals, I'm replacing landscape grass types. I'm not using them. I don't like them. They have a CPU cost associated with them. Um, I'm going to replace it with with partitioned hierarchically generated GPUon uh instances. It is a lot faster. Um, it's a it's faster to generate. There's no CPU overhead associated with it. I just like doing it better. Um when we are building our PCG graphs, we want to make sure that we are discarding points as quickly as possible. Uh we want to think about how graphs output data for other graphs. Um a big thing that I need everybody to know is that generate ondemand does not just mean when I click the generate button. It means whenever something needs to generate from that PCG graph. So sometimes you might put a perfectly reasonable uh blocking synchronous load into a blueprint call in your PCG data or in your PCG graphs because you expect that PCG graph to only run in the editor. But sometimes we need to run that we need to rerun that graph at runtime and you might miss this. So what you can do is mark those PCG components as editor only so that there's no way that they could possibly be run at runtime. Um, and then of course I'm going to use PCG builders to wrap all of my big PCG systems together. There was a really great talk uh from Chris Murphy and Adrien Logan at GDC. Uh, it will be in the links at the end of the show about like how to build largecale PCG interoperable systems. So definitely check that one out. Um, I'm going to be using world partition for for my world streaming. I really like using it. Now, a while ago, there was maybe some talk that the number of streaming grids was how you controlled like, oh, this is the high detail, the medium detail, the low detail. Um, I'm not a huge fan of that anymore. So, instead, for like a lot of the smaller detail stuff, I'm going to use that runtime hierarchical PCG generation. Um, the size of your streaming grid, the size of my streaming grid is going to be very project dependent. This is something that as I am working through pre-production, I'm going to be figuring this out. I'm not just going to rely on the default settings in the engine. I am going to use runtime cell transformers.
Uh these are great because they they take the stuff that is in a a world partition streaming cell and they transform it into a format that is more uh performant for runtime usage. So fast geo is beta in 5.8.
I don't always like saying epic says blah blah blah, but like use it please.
Um there's a lot of power there um to basically do what we think is happening in our brains. When I put a static mesh actor in the world and its mobility is static, I think it should be fairly cheap. But like that is an actor and a component that has to be spawned. And spawning actors and components takes time. So if I can make it not an actor and not a component, it'll be faster to stream in at runtime. Um, for PI startup, I think we actually have editor or world settings for this to slowly grow the streaming radius when I'm in uh, playin editor. So, it helps me get into playin editor faster. Uh, depending on the project, I might need to think about building a custom streaming hash.
So, I need, you know, if I have a world where I've got a bunch of tunnels and caves, right? I'm I'm super excited about mesh terrain. um I I might need to think about a different way to stream that than just the default um streaming hash set that came in 5.5.
Uh and of course I'm going to use data layers for a lot of state swapping.
There's a lot of really cool stuff in my colleague Jakong's presentation about persistence which unfortunately was at the same time as my pirate talk, but I've got some links of EDC articles that he wrote in the links at the end of the show. Um and of course level instances and packed editors. I really wanted to talk about these briefly in the context of building large open worlds because the the the s level instances get baked down into the streaming grid. But a packed level actor is an actor and actor bounds are what determines which streaming cell it's going to be put in.
So if I've got a really big packed level actor that covers two city blocks and my streaming grid is half a city block, now it's always going to be loaded in. So, I really have to think about the size of my um the size of the packed level actors that I'm going to have my artists working with, the size of those level instances, and how I'm going to use them. And then finally, I wanted to talk about the async streaming budgets. So, every frame, the engine is going to try to stream in more stuff as we're moving through the world, right? That's add to world. And by default, the budget for that is 5 milliseconds. And we can do a little bit of math, and we know that 5 milliseconds out of 16 is a lot. So, I might tune that down with a couple of different console variables to tune what kind of streaming I'm doing, how much of it per frame, things like that. So, I'm going to change those settings. There's a few different console variables there.
We'll talk about that at the end of the show. There's also project settings for that. Um, and again, anything that's a console variable can be part of a device profile, right? Um, I am going to use hlots, uh, partly because they are required for hardware ray trace lumen farfield. If you want to have loom stuff in your lumen scene beyond the default lumen streaming distance, I'm going to have to use H lods. Uh if I am using H lods, when I'm using H lods, I'm going to use the approximated mesh method. And importantly, I am going to check this checkbox called use render LOD meshes because what this does is use your fallback meshes. So my two million triangle quick mega scan rock I've set a bunch of LOD settings on it for its fallback and it's you know LD 8 fallback is like 10 triangles. Now that 10 triangle rock is part of the HLOD build and my computer doesn't run out of RAM whenever I'm trying to build my HOADs.
That check that checkbox. That's the one. Um I'm also going to create project specific HLO layers, right? Um I know that by default like you get an instance layer and a and a merge layer. Uh, I think what I'm going to do in production on my game is I'm going to evaluate whether or not I need an instance layer or fast geo is going to do most of the work for me and I can increase the size of my streaming grids so that I don't really have to manage like oh and then this is an instance and then this is a merged mesh, right? But I'm going to evaluate that and I'm going to think about customizing my HLO class. Maybe I want to have some functionality on my HLOD for like, oh, that building could be partially destroyed and I don't want to have to like bake a separate HLOD for it. I can make my own custom HLOD class.
I can make my own custom HLOD builder classes. There's a lot of really cool stuff and power within that that I I'm going to explore so that I could build my game as 60 frames high quality visuals on nextG hardware. Um, and of course I'm gonna b because I've set up my Unreal Engine Studio the epic way, uh, I'm going to run my HLOD builds every night after I run my PCG builds every night across a bunch of different agents so that I can I can amvertise that work. Um, how you build your gameplay of course has a huge impact, right? There's a whole thread called the game thread and that's what we're going to talk about here. Uh, and this is me very poorly playing Lyra. Um, so my goals with gameplay generally are building extensible systems that everybody can use that fit in my budget, right? Um, going to talk about this very very briefly. Um, ultimately this is up up to you, right? Um, some people can build an entire game without ever writing a line of C++. That's great.
Some people don't want to do that.
That's also totally fine. Um, but definitely profile it, right? Determine what the right balance is for your project. see if there's something that your engineers should be nativeizing for your designers because you've got a very expensive operation. Um, I'm not going to spend a whole lot of time on this.
There are a lot of really great resources on there about how to structure game code correctly, um, performantly, things like that. Um, really I I think for me it's a lot about teaching your designers a little bit of computer science and teaching your engineers a little bit of game design so that they all know what they're talking about together. Um, that's all I'm really going to say about that. There's not a lot of secrets there. uh how I might want to have my living world built and expressed is a major major part of performance in these large scale games, these large scale open world yada yada yada yada. Um and I call this living world because I have had to find a new word that encompasses um these kinds of features. So, my goals here are to scale the simulation of my living worlds from from maybe tens of actors to hundreds of actors to even thousands or tens of thousands of agents all running around and doing a lot of really cool stuff, right? Um, and I want to enable those agents that are populating my living world to have efficient activity and navigation throughout that world, right? So, um, state tree is going to be a really big part of how I'm building all of these systems. They are tickless as of 5.8.
This is really cool. It means your state tree components are not all ticking every frame. Um, so I'm gonna think about now as I'm starting my game in 5.8, I'm going to think about utilizing um async or event driven patterns so that the tree is only evaluating when state needs to change, right? Uh, and where possible. Oh, I do want to mention state tree is not just for NPCs. It can be used by a lot of different systems.
Uh, I have heard of somebody that used state tree to drive their UI transitions. Um, that was really cool.
Uh, but it pairs really nicely with the environmental query system, which is also not just for efficient navigation.
Um, it it helps my agents determine where they need to move in the world and how to navigate things like that. I do want to make use of things like linked assets and parallel state trees. Um, because these are designed to hold reusable behavior. Now, the recommendation that I got from my colleague who works with a lot of these systems is it is a good idea to be prototyping a lot of these state tree tasks in blueprint and then nativeizing them to C++ when you're getting pretty close to uh to finalizing those because we're going to be running these on a lot of um a lot of different actors. And finally, uh debugging for the state tree is now rolled into the animation rewind debugger. So keep an eye out for that.
If you had previously used the one that was just built into state tree, now it's in the just the generalized rewind debugger. I wanted to call that out while I was talking about it. Um, navigation is a really big part of this.
Uh, and static nav mesh can be an option and there has been some work in this area much like a lot of other systems on the rendering side of things. Uh, I'm going to go with dynamic. Uh, so dynamic nav invokers are kind of the way to go.
The basic idea is a nav invoker says, I would like some nav mesh, please. and we generate some nav mesh around that thing that has invoked the generation of nav mesh so that I don't have to hold 16 km by 16 km worth of nav mesh all at the same time. I can just say I just need nav mesh right now. The added bonus is when you blow something up in your world or you change a data layer. You don't have to rebuild all of the nav mesh in order to do that. Right? It's all just dynamic. Um and then I'll probably need some kind of hierarchical system. Maybe I build something with EQS to say, "Okay, I've got I've got an enemy over there and they need to come toward me, but I don't want them to also be doing nav invoke, so they're just going to start walking toward me. I'm going to have a system to help them do that." And then when they get close enough, now they're part of my nav mesh. Um, mass is a really big part of this. When I think about the like, hey, things that we wish we had done or things that I really want people to do when we're talking about tens of thousands of things happening in the world, NAS is the answer. Uh, so as a general, I'm I'm going to briefly blow through this. Uh, so mass is a lot of large scale operations. I have to do a lot of them all at once. And it's this operates on a strct of arrays. So rather than for each actor I need to update the transform, update the rotation and then figure out where they're going next.
What this what mass is basically doing at a very very high level is going I'm going to update all the transforms and then I'm going to update all the rotations and then I'm going to update the goal positions.
It's much more efficient uh computationally. Um, and the other reason that I really want you to be thinking about mass and how it fits into your large scale open world 60 frames per second game is it underpins instanced actors, which I think I'm going to be using instanced actors in my large scale game. Um, because it basically means that when um when a thing becomes relevant to gameplay, it is fully hydrated actor blah blah blah and then when it's not relevant, it is an instance static mesh. Uh, this is like disabling tick on your actors on steroids. Um, and J Kong has a bunch of, uh, bunch more information about this.
Uh, I realized that his EDC article is kind of kind of the first big one talking about it. So, definitely check that out at the end of the show. Um, like I said, his talk was this morning.
Sorry you missed it. And then after this, if you don't want to go to Ari's talk, uh, Jared is talking about basically how to get your brain to think about mass. And then Henry is going to talk about what we can do with mass in the context of crowds because crowds is usually where I see the mass thing become a really big issue. So, oh boy, I'm running short of time. So, I'm going to re briefly talk about animation. Um, in 5.8, I'm still using animation blueprint. Um, anything larger large scale or like, oh, I don't want to have an anp running this. I'm going to move to something that's mass-based crowds or or vertex animated textures. Um, generally I'm going to be profiling and nativizing complex processing in my animation blueprint. I'm going to be really careful about, hey, maybe don't update a bunch of attached components every frame. I always see that in insights traces. And I'm probably going to start off, and this is the big one, I'm going to start off using the anom budget allocator from the hop because if I realize I need to use it later, there's a bunch of reparing that gets really, really messy. So, I'm going to just use it out of the box. uh simulating your large open worlds is a really big factor of it too, right? Our destruction, how complex our collision is, our trace and object channels, things like that. Um I think actually this last one is probably the more important one is, you know, that list of world dynamic, world, static, pawn, vehicle, whatever. Um you can add to that those that's a project setting and I think you can add up to like 32. So if you have something that's like oh this is an interactable rather than doing like get all overlapping actors and then doing a cast to see or even doing an interface call you can say okay this is an interactable object and my volume can only overlap interactable objects which means I have fewer things to update overlaps on and then I know that I've already limited my scope of what I'm going to be overlapping. Um, I'm going to lean really heavily into that. And then if I'm doing a bunch of destructible stuff, I'm going to lean heavily on data flow for iteration.
Another great talk about that uh from GDC last year that's linked in the notes at the end of the show. Particle effects are another thing that has a really outsized impact on this. I just really briefly want to touch on systems as a service. So I talked about this in the um in the profiling with pirates talk.
Rather than having like Niagara system actor, Niagara system actor, Niagara system actor, Niagara system actor, I'm going to have a system where there's only one Niagara system and then I'm going to spawn a bunch of those different particles using Niagara data channels so that I only have one ticking Niagara system. Um, as I'm building everything out, I'm going to have effect types that's going to let me do a lot of really cool scalability stuff, right? So maybe I have more particles show up or they do more complex logic in my quality mode at 30 frames per second because I can spend more time on it. Um the other thing that I'm going to think about with Niagara is using lightweight emitters.
You know, if I've got a looping particle that doesn't have to really react to anything in the world, I can use lightweight emitters for things like that. And if you want to learn more about uh Chaos and um and Niagara, definitely check out Philip's talk tomorrow at 9:00 a.m. about how Fortnite built a lot of their living world creatures with Niagara. That is basically the Niagara data channel talk.
Uh and then Vincent tomorrow at 11:45 is talking about optimizing chaos. So there's a bunch of cool stuff in there.
Now we get to the meat of things.
Rendering. My favorite part. All right.
Going to have to rip through this. All right. Nanite. You have to set a number of LODs on your nanite meshes. Go into your static meshes. Set num loads. They really really really need you to do that so that it generates fallback meshes which are more efficient to ray trace against more efficient to uh complex collision and it means you have something when you need to deploy to non-anite platforms you have just please set a number of lods um and think about the rate tracing proxies so five I think 56 maybe 57 we added the ability to have a separate distinct uh ray tracing fallback or rateracing proxy so that I can tune how this is going to look right if you're using mega lights. Now, we're using ray tracing for our direct lighting. And those ray tracing proxies become really, really important. Um, in my materials, I'm going to set something like max displacement. So, if I have a WPO, I'm going to limit how far uh that WPO is going to move, which is going to help me improve my my cluster calling.
If I am using uh displacement and tessellation on my materials, you have to go into the material and enable the displacement fade checkbox. that I wish that was on by default. Uh for everybody in this room, go home, figure out all your tessellation materials, and just check that checkbox. And of course, I'm going to make sure that I have disabled distances set, both pixel programmable disabled distances and WPO disabled distances so that my programmable rasterization falls back falls back to fixed function at a distance. Um a really the really important thing with Nanite is reducing bin counts. And the way we'd reduce our bin counts is by architecting our materials. So the the shading bins is the number of unique material instances. So material instance constant, material instance dynamic. And the way that I can reduce the number of those in my project and the number of those in my scene is using custom primitive data and per instance custom data for changing, you know, I want to do a little bit of variety on this thing. I want to tweak the color on this thing. I'm going to use per instance data for that instead. And then if I want to change a global value, I'm going to use a material parameter collection rather than looping through and updating a bunch of material instance dynamics.
Um, this is a really big one. Usage flags is about generating a bunch of shaders. Uh, Jason and John are going to talk about this later, how they did this in Fortnite. 58 has per material instance usage flags. So if you have one of those, like, ooh, the landscape material was also used on a Niagara mesh particle. You all have this. I know you do. Um, you can now say, okay, this material instance is the one that's going to be used. and generate the permutations for the Niagara one. We're not going to have to generate a whole bunch of permutations. Now, this is a big one. Large world coordinate rendering. Um, we have all seen this in every material tutorial that has ever existed since like Zach Parish in UE3, right? World position subtracted from actor position gives me a vector that I can use with. Well, large world coordinate rendering means that that actually causes us some problems when we are evaluating our base path. So large world coordinate stuff means that we have to do a little bit of extra transform. The engine has to do some transform on that math. The math gets more expensive if we math it this way.
So instead I'm going to use camera relative stuff as much as humanly possible or periodic world space because anytime I introduce large world coordinate into my material math I'm it might be part of my performance problems. I am not suggesting that all of you have to go through and to audit your materials for this, right? It's about profiling.
So, if I profile and my base pass is really slow, I might look at my large world coordinate usage in my material.
But because we're talking about starting a project at 60 frames per second, I'm going to set this standard early so I don't have to worry about it later. Uh again, link in the show. Um one of our rendering engineers wrote an article that was basically like don't do this, do this instead, and you will find those patterns in your project. Only do it if your base pass is slow. Um substrate, oh god, I'm going slow. Uh substrate, this my tech artists are going to make a fixed material topology. Substrate slabs are not material layers. That's really important. um every BSDF and blending BSDFs can be very very expensive. I think generally for the purposes of a lot of people in this room, we're going to have one BSDF. We're going to have one substrate slab and then maybe as a treat, I will have an extra one for like clear coat or slightly different clear coat. Um and again, the artists are not the ones that are going to be making new slabs. Most of it is all going to funnel into one slab. uh lumen. I'm using hardware ray tracing and and we're we're really confident in the performance right now. Uh my reflections with lumen, I'm going to make sure that my roughness to trace value is set appropriately. Um because I've seen a lot of projects where like the roughness values in the project is like most of it is like 35 and the default roughness to trace is 04 which means most of the pixels on screen are tracing dedicated reflection rays which is very very expensive. So, I'm probably going to move that down and I'm probably going to set the foliage value to just zero just out of the gate, right? Um, megalytes, I I am thinking if I'm going to use mega lights in my project, yes, they're production ready in 58. They're great. This is a feature that I can leverage if I need a bunch of lights in my world, right? Um, because overlaps still matter mostly for noise, not necessarily for performance. And I do have to get really really careful about thinking about my instance overlap. Um, so that that affects ray tracing performance. The complexity of my ray tracing proxies is also going to affect performance here. I really have to think about that as I'm setting the standards for building my 60 frames per second.
And if you are using mega lights, just go go all in on mega lights. Um, and wrecked lights are still as a treat. Uh, I'm not going to use a lot of wrecked lights in my world. They are still expensive. Uh, if I'm using virtual shadow maps, uh, one of the ones that gets everybody is the virtual shadow map projection mask bits. and that is either the softness of my lights or my SMRT settings. So, I'm not really gonna have a lot of super soft lights with virtual shadow maps. Um, the light overlaps of course still matter here as well.
Caching can help, but I'm not going to rely on caching to solve all of my virtual shadow map performance problems.
Um, I am going to use resolution LOD bias. That's something I can set in my device profile. So, maybe I have higher resolution shadows in quality mode, lower resolution shadows in performance mode. Virtual texturing. I'm definitely going to use virtual texturing. Huge benefit to memory. Um, I'm going to be very careful about that r.vt.mmax uploads per frame and r.vt.mmax uploads per frame.streaming. Uh, the top value is for your, uh, runtime virtual texture and the bottom value is for all of your streaming virtual textures. The top value should be low and the bottom value should be high. Um, we've got a really good article and I'm running out of time, so I'm not going to talk about this too much, but uh, I'm going to think about my stack count, which is the number of unique UV sets in a material that affects my virtual texturing streaming performance. Pipeline state objects, PSOs. Uh, I'm going to bundle them or I'm going to pre-cache them or I'm going to do both. But I'm doing something. I have to do something with my PSOS. Uh, I'm probably going to be doing a lot of pre-caching. Um, and then when I am testing, I'm going to make sure that I clear my PSO cache so that I can see when I'm running locally whether or not uh I have an issue with my PSO generation. Time of day I'm going to skip over uh homework for this one. Uh Simon is talking about nanite foliage later. I didn't talk about that at all today. And then Jason and John are talking about shader reduction in Fortnite tomorrow as well. Uh speaking of another talk that you're going to go to after this uh is the talk about user interface. The the basic idea here is we got to work think about our layout costs. I'm not going to have canvas panels at the root of all of my widgets.
I'm going to be careful about my invalidations and I'm going to use UMG view model or uh MVVM to handle the interop of data between all of my systems. Cody's going to talk about all of this tomorrow at 9:00 a.m. I'm so sorry about that tomorrow 9:00 a.m.
slot. Uh networking. This is a fun one, right? Maybe I want to have a 100,000 players or 100 players running around my large 16 km open world blah blah blah blah blah. Uh cool thing about networking stuff to talk about today.
Iris is production and ready in 5.8. So I'm gonna I'm probably going to make use of that. Um I'm going to make sure that all of the stuff that is networking is opting into replication rather than opting out. I'm going to control the relevancy either with replication graph or Iris's filters. I'm going to think about the frequency of replication. How often does this value need to be updated? And when I'm testing, I'm going to be testing with replication enabled.
And of course budgets. I have to have budgets um because the budgets help me identify what I need to optimize, right?
Um and when not to optimize. And I'm going to think about should my budget targets be frames per second? Should it be missed VSYNC percentage? Should it be dynamic resolution? Should it be a millisecond value? This is something that I am doing very very very early in my project so that I can always go back to that. Um and that is a lot of decisions and a lot of homework and that was only a third of this talk. Um but this one's a little easier for me to rip through. So let's think about how we're monitoring for 60 frames per second, right? It's about guiding users to the right choices and knowing when things deviate. So guiding users to the right choices with things like data validators and asset referencing restrictions and our friend the submit tool all make sure that the the standards that we have set for building our world are being enforced at creation time. Monitoring for 60 frames per second is a really big topic, right? Unreal Insights. Everybody on my project knows how to use Unreal Insights because it means that they can they can profile themselves and they can determine for themselves how performant their systems are. Uh they're really really cool. Trace regions, I love them.
Trace screenshots help me add a lot of context to the thing. GPU profiler 2 means I don't have to open a GPU capture tool to figure out how long it took for the base pass shaders to run. Uh world streaming insights. Breaking news. This came out in 5.8. So that I have a heat map. Oh, somebody said whoa. Um, so that I have a heat map of the streaming performance of my world overlaid straight into Unreal Insights. This is really, really super cool. I Yeah, clap for world streaming insights. Um, speaking of cool things that have come online on top of things built on top of the trace server, Chaos Visual Debugger now has a complexity view. Oo, yeah. Um, so this is really, really cool. Uh, and of course I I have the rewind debugger at my disposal. Now, this one is a fun one. So remember when I talked about automated performance testing being really really important?
I'm going to do it every day. And then there was a part at the end of that slide that that talk where I was like okay it's buildg graph and UAT and gauntlet test controllers and I'm going to run all these tests on horde and then how I display those results. Ah that's up to you. Haha we have it now in Horde a PF trend dashboard in Horde that you can send all of your data to and it will give you all of the graphs.
So now finally we have the full picture of like I run my automated tests on Horde. It reports the results to Horde.
I can set it. Oh, I'm so excited about this one. This this literally a dream come true for me. Um so shout out to Julian Gamble for helping put that together. Um so returning to 60 frames per second. This is when I think about view modes of like, okay, I know that this is running really really slow and so I've got all these cool view modes that we can talk about later. Um substrate material count. There's a bunch of really good good ones for that.
So I can see how many BSDFs are visible.
Um, generally the the the I don't know, returning to 60 frames per second for me is a lot about just returning to best practices, right? So maybe I'm going to have to nivize my expensive animation and blueprint operations. I'm going to be reducing my shading bin count might be the big issue. Again, a lot of this is going to come down to profiling, figuring out what the big number is, and then we can talk about making it smaller. Um, yeah, ultimately returning to best practices. And of course, we have maybe we get a little dramatic. we do some input latency reduction tricks, maybe we do some uh frame generation, or maybe I made too much game and I have to take out some of my game.
And that's kind of a bummer to end on.
Um, so generally what I want you to take away from this is uh the performance of the Unreal Engine is improving. The tools to do so are improving. We can set ourselves up for success by starting off on the right foot. We have to stay v vigilant throughout our entire project and we will eventually have to get back up on the horse. And finally, you can do it. I know you can do it. Thank you everybody. Really appreciate your time.
I don't have time for questions. Scan that QR code. It'll take you to my link tree. You'll find the article and all the notes at the end of the show cuz I rip through that real quick. Thank you everybody so much. I'll see you out in the hallway. [applause]
Related Videos

Audi RS5 4.2 Tuning JDEngineering
JDEngineering
1K views•2013-11-14

DALI + KNX: 500 Lights Offline! BCU Code Lock & Short Address Fix!
EngineerIsmailTech
560 views•2026-04-13

Explaining Quality Control of Concrete
maherbader
4K views•2019-05-25

World Mining Production Peaks - Lead Antimony Arsenic Titanium & more
LucarioandDialga
1K views•2019-04-19

Tech Titans: LFP vs Sodium-Ion Battery | Which is the most effective energy storage solution?
Enfsolar
522 views•2025-11-06

Doing the Math: Analysis of Forces in a Truss Bridge
TeachEngineering
1K views•2025-06-06

Inside Midnight Fighter Jet Refuelling Secrets of Stealth Missions | WION Podcast
WION
3K views•2025-09-20

Flash Point, Fire Point & Auto Ignition Temperature
HSELessons
38K views•2019-08-28
Trending

we're almost finished the house (ep.125)
JennaPhipps
347K views•2026-07-22

We Finally Know Where Saturn’s Rings Came From
astrumspace
79K views•2026-07-22

BIG BET: Cathie Wood goes ALL IN on Elon Musk
FoxBusiness
89K views•2026-07-22

MIC DROP: Smithsonian Director Called Out For Woke Propaganda
TheAmalaEkpunobi
37K views•2026-07-23