30 fps, 33.3 ms
100 fps, 10ms
For this assignment, we optimize Neo Mottel and Ryan O'Grady's team thesis environment. Our goal was to get the fps as high as possible in editor- no blueprints edited for this.
A personal goal of mine was to do minimal edits to the actual level.
Optimization with Nanite is rather different from regular optimization. Triangle count is very cheap, having good cluster sizes, not to many shading bins or raster bins, and not too much Nanite overdraw is what matters.
The very first thing I did was enable Nanite on the meshes that were overlooked. Anything black in the visualizers do not have nanite on, though there is also a button in the content drawer to quickly enable it on selected assets too.
The second thing I did was soften edges. Some sculpted meshes had all hard edges, which makes the vertex count triple the triangle amount. A mesh with all softened edges would have vertex count be half of triangle. Not to say that hard edges are evil, but its good to remove them when unnecessary.
I also went through the heavier meshes and used the built-in nanite tools to reduce their triangle count.
49 fps 20.1 ms
Virtual shadow maps go hand in hand with Nanite. Enabling it slightly changed shadows and performance.
Modern realistic games like rendering at lower resolutions and then upscale them to 4k. Here forcing the viewport to render at 1080p instead of the highlighted text's 2160 saved me almost 4ms, getting over 60fps.
The disclaimer here is that I adjusted a setting for the editor viewport. From what I can find most settings are for r.ScreenPercentage instead and there are differing options to change it between editor, PIE, and standalone game.
51 fps 19.28 ms
64 fps 15.39 ms
By default the editor graphic quality settings are at Epic. Lowering it to High and setting a few options to Low barely affects the actual look of the game- only the lighting, which can be easily adjusted with the skylight intensity and post process.
This project was started with Lumen and I switched it to the cheaper SSGI (Screen Space Global Illumination) for lighting and reflections through the post process volume.
*Lumens actually gets disabled on Medium and Low scalability and replaced with SSGI, which I also set in Scalability.
*These should've been the very first thing I set!
100 fps, 10ms
I took a look at Unreal Insights and the GPU profile, but as you can see I made most of my gains through Nanite and pressing switches.
Looking at Unreal Insights, WaitForGatherDynamicMesh was taking 8ms. Scrolling down to a background task, it looked like it was the OcclusionPipeline but also "oversubscription"- which I did not comprehend the Unreal documentation for.
I knew nanite handles occlusion in it's own different way, so I wasn't sure where to dig into this, as other tasks for nanite didn't seem to show this.
Unreal Insights - Scalability settings brought oversubscription down to 3.5ms from this picture's 7.9ms.
Stat GPUProfile - Lighting was taking up most of rendering before "day" 3.
Virtual textures were enabled for this project and I turned them off for a moment to see what would happen. Basically, there's a little bit of overhead to them but it's probably worth keeping on- I wasn't focused on memory for this optimization project but I'm heeding the texture budget warning. 12GB of memory!
So what's that "DynRes Unsupported" at the third-bottom of stat unit? I stumbled upon it while trying to figure out how to actually do upscaling right. It basically upscales, well, dynamically. It's disabled by default and is NOT supported on Windows- Microsoft's Xbox One, Xbox Series S, and Xbox Series X, PlayStation 4 and PlayStation 5 (excluding PSVR), and Nintendo Switch.
30 fps, 33.3 ms
100 fps, 10ms
https://dev.epicgames.com/documentation/en-us/unreal-engine/working-with-naniteenabled-content
Hitting 60 FPS in UE5 and Keeping It There (Presented by Epic Games) GDC Hey look have my notes from that talk for free