UDK seems to have limited tools to help optimize large maps for a multiplayer game. Would anyone here have some good suggestions, tools, console commands, etc… that can help with such a thing?
I’m primarily facing the issue of large number of draw calls specifically when flying around in the map where you can see well off into the distance. I’m not use level streaming either since it is a multiplayer game with outdoor levels so streaming doesn’t seem to work well.
I’ve played around a lot with precomputed visibility and cull volumes to try and help but its really not enough. Even gone as far as to combining objects that share the same materials together that are clustered together. However this still doesn’t make much of a dent on draw call issues.
I’m curious how others may approach it but also if anyone has any useful debugging tools/options that can help identify problem areas.
I agree with many of your comments. But I disagree about you not using level streaming in multiplay.
I don’t use level streaming to control load/unload in multiplay of my game. Because such control sometimes causes ‘fall in a death’ for multiplay users. (If a user moves while sub streaming levels are not loaded, he has no choice but to fall and die.)
So my game loads all sub streaming levels at start in multiplay. And level streaming is only used to control show/hide sub streaming levels according to the user’s location. This method does not help conserve memory at all. However, it is helpful enough to reduce the number of draw calls.
The picture above is a screenshot of the Kismet nodes I created to control the show/hide sub streaming levels in multiplay of my game. Please refer to the picture above.
I use streaming levels, but you can try to use sethidden() in static meshes and others, by distance to the player. It’s faster than leave them with the maxdrawdistance (still casts shadows and collision).
One alternative to streaming levels is an actor to store staticmeshes around, and hide/destroy them when the player is far. In this way you have more control for the garbage collector.
Also if you use the foliage actor, you can hide far clusters.
Hey thanks for the input, I didn’t think about just having a level streamed in but not visible. But it would be worth testing if it helps to reduce drawcalls overall.
I’m curious how you would prevent popping in/out of objects if all the levels are streamed in but hidden. My main issue is mainly when the players can fly around in a helicopter and be able to see almost the entire map, and as I mentioned its an outdoor environment with little to no interiors. So my original concern with streaming was that we would end up seeing a lot of popping or entire sections of the levels being loaded in as the player moves along.
Honestly, I hadn’t thought about the popping problem. Because my game is mainly about sword fighting at close range. In my game, users mainly focus on the enemies in front of them holding a sword. So even if there is the popping problem in the background, they can’t afford to concern it.
UE4 has a feature called HLOD. Based on that, I guess that if you make a HLOD-like feature in UE3, you can solve the popping problem. Good luck.
Got any videos / screenshots showing parts of the map that are performing well / badly?
What hardware are you using to test (ms / fps stats). One of the things about sticking with UDK over time, is that newer hardware helps cover up lack of performance.
Popping in / out of meshes in large worlds with flying aircraft really risks breaking player immersion. So the usual optimization methods aren’t the way to go here anyway.
But…
Its definitely possible to use the entire level or map space of UDK to get ‘infinite’ views though (multiplayer). Think ± 250,000 x,y,z max world size units or 10km x 10km x 10km approx.
That’s without any kind of level-streaming / culling / mesh-hiding / lods. The latter doesn’t work with ‘infinite’ views anyway (sniper scopes aimed at landscapes clash with placed meshes).
Probably the biggest gotcha though is foliage. Can’t help with that (tested sci-fi levels with minimal foliage). Merging actors can help for a lot of the rest (pity UDK never had that feature).
Hehe yeah I have noticed that perf with newer hardware does help a lot. But its still pushing it quite a bit. Playtesters have a varity of both low and high end PCs, and even on high end aircraft gameplay causes FPS to dip quite a lot.
On my computer I have a ryzen 9 7950x, 64gb ddr5 and a rtx 3070. It is reasonable on my PC but even then its rough with ground having locked 120fps and air going down to 35-50.
And an example of how FPS is like on both foot vs air. These I would consider to be on the very high end (minus GPU, but GPU has never been an issue for UDK. Its mostly CPU bound).
For other testers that range from gtx 980s to gtx 4090s its mostly always been related to draw calls. An average PC tends to drop to below 30fps for in flight gameplay vs roughly 60 on foot. Dipping below 30 is a no-no.
As for HLODs, would that even be an option? I dont think UDK has anything like that nor is there access to engine code to be able to change anything as far as I’m aware.
Does Dx11 help? We’ve generally stuck to Dx9, mostly because we found it caused issues with some shaders.
OMG~~~ Your maps are really fantastic and wonderful.
If you have a license to modify UE3 in C++, I think DX11 will help you create a HLOD-like feature. And I think it’s a matter to decide by the development direction of your game.
By the way, how about creating a map for flying play and a map for walking play, and displaying only one of them depending on the player’s altitude?
Creating 2 such wonderful and complicated maps will be a challenge for you. However, using 2 maps is expected to solve your problem even if you don’t implement a HLOD-like feature.
Interesting… With huge maps the stats don’t always help much (CPU bound vs GPU bound insights). Are the maps mostly made up of landscapes with smaller meshes, or are maps mostly lots of different sized meshes? Either way, no megascans rocks, right?
Question: How quickly can you disable collision on most of the map, spawn a flying vehicle and re-test? Or clone the project if needed, and brute force delete things if that’s faster. Basically wondering if collision complexity is a bigger factor than draw calls in flying mode.
Hey thanks, yeah for a UDK game its not bad looking
Well we dont have a license, we’re straight up on the last version of the UDK. We dont have access to any engine code. But I guess my question about DX11 is more so about just UDK’s implementation of it. I don’t know if it improves optimizations at all or not for just stock UDK.
I have also tested disabling all collision except on landscape as a quick test and honestly it barely made a dent when flying around.
I was wondering if the simpligon mesh proxy generator could be used some how to swap between the merged and unmerged based on distance? It would be similar to an HLOD method in theory. Is something like that possible?
Also does this tool have an option for merging meshes only without creating a proxy? There are a lot of modular assets that share the same textures that can be merged.
How to swap between the merged and unmerged based on distance?
=> I think it depends on the direction you write your code. If I make that feature, I will create many invisible volumes to differentiate between the merged and the unmerged on distance, and handle the LOD via the player’s position and the position/radius of those volumes.
Does this tool have an option for merging meshes only without creating a proxy?
=> As far as I know there is no such option.(I could be wrong.)
Unfortunately no it doesn’t have such an option as that would be a huge time saver. I did try duplicating a group of assets and creating a proxy for the duplicate and then using the min/max draw distance to manually change visibility. Its not an elegant solution but it did roughly give me a 10fps improvement. Though not nearly as much as I was expecting.
I was reading through the docs and noticed that Dx11 uses a deferred renderer which might help with draw calls in general. However for some reason it does not appear to compile any shaders when I try switching to Dx11, and as a result immediately crashes.
“and then using the min/max draw distance to manually change visibility. Its not an elegant solution but it did roughly give me a 10fps improvement. Though not nearly as much as I was expecting”
With mindrawdistance still projects shadows (almost using dynamic lights)… try to do a SetHidden(true); also.
Yeah I noticed that as well. Apparently just disabling cast shadows on the proxy mesh with the min distance was sufficient enough to resolve the issue. Though I’m not sure if there is still some underlying overhead from hidden vs min draw distance.