Which technique to build a huge world with horizons visable across a grid of levels?

So I had a conversation with ChatGPT about how to achieve this, but would appreciate anybody wanting to add to the techniques suggested in this discussion.

Me: With UE5.1 using world partition, because of memory or GPU limits loading heightmaps larger than 16321px square has proved difficult, is there a mechanism to load in or out alternative levels in a surrounding grid so that you could have a player literally walk across levels seamlessly, and so architecturally have a grid of levels? I am thinking to use Nanite in this scenario, which now works with Landscapes, although an option might be to make individual meshes from the heightmaps.

ChatGPT: Yes, it is possible to use a technique called “level streaming” to load in and out different levels in a surrounding grid, allowing a player to move seamlessly between them. This can be done using the built-in Unreal Engine features, such as World Composition for landscapes or streaming levels for meshes. Nanite can also be used in this scenario, as it has been integrated with Unreal Engine’s landscape system and can stream in high-resolution geometry on-demand. Another option could be to create individual meshes from the heightmaps, and use Unreal Engine’s built-in level streaming feature to load and unload them as the player moves through the world. The choice of approach will depend on the specific requirements of the project and the hardware limitations of the target platform.

Me: With level streaming do you define each heightmap as an individual level and if so is there a limit to how many levels can be encapsulated in a project? and how can line of sight be effected across level boundaries?
With level streaming, each heightmap can be defined as an individual level, and multiple levels can be loaded and unloaded as the player moves through the world. The number of levels that can be encapsulated in a project will depend on the hardware limitations of the target platform, as well as the complexity and size of the levels themselves.

Line of sight across level boundaries can be affected by the level streaming technique used. If you are using streaming levels with BSPs, the line of sight will be determined by the BSPs. If you are using streaming levels with meshes, the line of sight will be determined by the meshes.

One way to handle line of sight across level boundaries is to use a “portal” system. A portal is a special object that is placed at the level boundary, and it defines a transition between two levels. The engine will use the portal to determine what should be rendered in the player’s view, based on what is visible through the portal. This can help to maintain continuity of the player’s view as they move between levels.

Another way is to use precomputed visibility or Light Propagation Volumes that can be used to illuminate the scene, giving the perception of the player having a line of sight across the level boundaries.

Ultimately, the best approach will depend on the specific requirements of the project and the hardware limitations of the target platform. It’s also worth mentioning that a good balance between level size and number of levels should be achieved in order to have good performance and maintain a good player’s experience.

Me: What is a BSP? When you talk of what can be seen through a portal are you talking about a circular or square device for instance, what I perhaps should of expressed was the notion of a full horizon in the being visible across the adjacent level! Of course the target platform will have limitations but are we talking about install space? Would it be possible to limit the applications footprint in memory and GPU by loading levels from disk as required?
BSP stands for “Binary Space Partitioning”. It’s a technique used in 3D computer graphics to divide a scene into smaller, more manageable pieces. In the context of Unreal Engine, BSPs are used to create simple geometry for level design, such as walls, floors, and ceilings. BSPs can be used in conjunction with streaming levels to define the visibility across level boundaries.

ChatGPT: When I talk about what can be seen through a portal, I’m referring to the concept of a “view frustum”, which is the 3D shape that defines what a player can see in the game world. A portal is an object that is placed at the level boundary, and it defines the transition between two levels. The engine uses the portal to determine what should be rendered in the player’s view, based on what is visible through the portal.

In terms of the application’s footprint, it is possible to limit the memory and GPU usage by loading levels from disk as required. This is known as “on-demand loading” and can help to reduce the amount of memory and GPU resources that are used by the application. However, it is important to keep in mind that this can come at the cost of increased load times, which may not be desirable for certain types of games.

It’s also worth noting that the amount of storage required for the levels is also an important factor to consider. It is possible to compress or optimize the levels to reduce the storage required. Additionally, the levels can be split into smaller chunks and loaded on demand, which can help to reduce the amount of storage required.

It’s also worth mentioning that the target platform will have limitations, such as the amount of memory and storage available, the CPU and GPU performance, and the internet connectivity (if the levels are being loaded from a remote server).

Me: So lets say that in game a player was standing on a hill and had an unobscured view of the horizon as he would with natural 360 degrees vision, well perhaps 120 degrees without turning his head, so we could not then use BSP’s to divide the scene. Or could we? And lets say we used 4k size levels as tiles in the grid, representing 4km in the world, with an Earth sized world, the horizon would be perhaps 3 to 4 tiles away and the line of sight take in a broad swathe as well, marking a quadrant encompassing several tiles. Is this achievable with any of these techniques you described?
It is possible to achieve an unobscured view of the horizon with a player standing on a hill, using the techniques that I described. However, the specific approach will depend on the requirements of the project and the hardware limitations of the target platform.

ChatGPT: One approach is to use a combination of BSPs and streaming levels. BSPs can be used to define the visibility across level boundaries, but they will not be able to capture a full 360-degree view of the horizon. However, you can use the streaming levels to load in additional levels as the player moves through the world, which will allow them to see more of the horizon.

Another approach could be to use the Nanite technology which can stream in high-resolution geometry on-demand, this will allow you to have a high-resolution view of the horizon, but it will come at the cost of higher memory and GPU usage.

Me: As for the level size, using 4k size levels as tiles in the grid, representing 4km in the world, you would have a big amount of levels and this could be a challenge in terms of performance and storage space. However, it’s possible to split the levels into smaller chunks, which can be loaded on demand, this will reduce the amount of storage required and improve performance.

ChatGPT: It’s important to keep in mind that the line of sight will take into account the distance of the horizon and the player’s field of view. Therefore, it’s possible that you’ll need to use a combination of techniques, such as precomputed visibility or Light Propagation Volumes, to ensure that the player can see a broad swath of the world while maintaining good performance.

Ultimately, the best approach will depend on the specific requirements of the project, the hardware limitations of the target platform, and the trade-offs between performance, storage, and visual quality.

Me: Lets say the target system had mid-level capabilities (I realise this is quite vague) what would be a better level size than that which I suggested? And are you saying that you could only load smaller chunks from neighbouring levels?

ChatGPT: The best level size for a project will depend on the specific requirements of the project, the hardware limitations of the target platform, and the trade-offs between performance, storage, and visual quality.

For a target system with mid-level capabilities, a smaller level size would be more appropriate than the 4km x 4km size that you suggested. A good rule of thumb is to keep the level size as small as possible while still maintaining the desired level of visual quality. For example, a level size of 1km x 1km or smaller would be more appropriate for a target system with mid-level capabilities.

When it comes to loading smaller chunks from neighboring levels, it’s possible to use a technique called “chunked loading” or “cell loading” where instead of loading the entire level, the engine loads smaller sections of the level (or “chunks”) as the player moves through the world. This can help to reduce the amount of memory and GPU resources that are used by the application, while still allowing the player to see a broad swath of the world.

It’s also worth noting that preloading certain areas of the level or using a multi-threaded loading system can help to reduce the load times and improve the player’s experience.

Additionally, it’s important to consider the trade-offs between the level size, the number of levels and the hardware limitations. A good balance between these elements should be achieved in order to have good performance and maintain a good player’s experience.

Me: So using “chunked loading” or “cell loading” where instead of loading the entire level, the engine loads smaller sections of the level (or “chunks”) as the player moves through the world. Would that mean that chunks from the current level as well as neighbouring levels could be loaded simultaneously thus making seamless line of sight across levels?
Yes, using “chunked loading” or “cell loading” can allow chunks from the current level as well as neighboring levels to be loaded simultaneously, which can help to create a seamless line of sight across levels.

ChatGPT: When the player moves through the world, the engine can use their position and the camera’s field of view to determine which chunks of the current level and neighboring levels should be loaded. The chunks are typically loaded in advance of the player’s movement, allowing the engine to have the next set of chunks ready to be rendered as soon as the player enters them.

This approach can help to create a seamless line of sight across levels, as the engine can blend the visible chunks together to create a continuous view of the world. The chunks are typically loaded and unloaded as the player moves through the world, which can help to reduce the amount of memory and GPU resources that are used by the application.

However, it’s worth mentioning that this technique can come at the cost of increased load times, which may not be desirable for certain types of games. Additionally, it’s important to consider the trade-offs between the level size, the number of levels, the chunk size, and the hardware limitations. A good balance between these elements should be achieved in order to have good performance and maintain a good player’s experience.

Hi Andy,

:robot: “So I had a conversation with ChatGPT about how to achieve this” :robot:

Welcome to the future. :stuck_out_tongue_winking_eye:

First red-flag is when ChatGPT mentions “World Composition” (I know it’s trained on older data), but please ask ChatGPT if it knows that in UE5 the ‘World Composition’ system has been replaced with 'World Partition

World Partition is going to be a good starting point for huge worlds. See the Valley of the Ancient sample for an implementation of this.

ChatGPT is leading you down a weird rabbit hole with the mention of BSP. I guess in the context of level streaming it would just be BSP volumes instead of BSP geometry, but World Partition should automate streaming based on position/view.

Dalle Image generated from prompt: “huge world with horizons visible across a grid of levels”

The only way to achieve anything truly massive - from sourced heightmap data - is to create your own octree based procedural mesh generation system that replaces the landscape trash system.

That way you can also automatically account for planet curvature and esri conversions when taking the heightmaps into account.

Its also not going to be accurate to real life within something like 80m or so, regardless. Because
A) sourced data is not accurate, a 20m dtm is already only ok for 20m, when you stretch that one pixel of data to cover 20m the result has already introduced potentially damning errors.
B) even with lidar 1:1 data, you have to deal with the conversion factors which using a spherical approximation already introduce errors - most visible when measuring/comparing distances between features.

Octree plus mesh streaming within the fustrum is about the only way to actually achieve an OK frame rate and visible horizon result.

I believe some games like Rage for one, implement something similar.

Really, its only unreal that is so stuck in time that it offers no easy to achieve something playable without having to code your own system(s).

Ps:
Valley of the ancients is hardly a “sample” or something to consider at all within this scope.
Its a bunch of instanced meshes stuck together. A 2 year old could have come up with a better solution and less overall drawcall counts…

Pps:
quote=“Andy_Seabrook, post:1, topic:756541”]
Me: As for the level size, using 4k size levels as tiles in the grid, representing 4km in the world, you would have a big amount of levels and this could be a challenge in terms of performance and storage space. However, it’s possible to split the levels into smaller chunks, which can be loaded on demand, this will reduce the amount of storage required and improve performance.
[/quote]
Completely the opposite.
The smaller the levels, the more drawcalls, the more looking at an horizon will cost.
Also, the more memory footprint, and more overall filesize.
As smaller level chuncks end up requiring more files to be generated for painting - and while the overall data may be the same amount, each file has its own header data to add to the tot.

HI thanks for coming back. So first up for the appolgy in the quote above, that was actually a continuation of ChatGPT output. I added the Me: erroneously. So when I say huge in the title, I am not thinking continental in scale, this was simply that the hyped endless world partition based level has not been delivered as far as I can see, and I am thinking of say 100km square solutions. I am really not as mentioned able to build much bigger than 16321px. Of course scaling is going to loose detail in the heightmap, so not keen.
My current position was to manage a series of disperate levels representing disperate locations in a world and just accepting a travel-time based approach through the void to a chosen level. However it had seemed that World Partition might reduce this need and I could generate much larger continuous spaces for each level. Still with the disperate level approach but needing far less of them and thus not interfearing with emersion at the same order of magnitude.

So as reagrds Octree, not being sure where to start I threw it at ChatGPT again. It would be interesting to hear what you think.

ChatGPT: An Octree-based level of detail (LOD) system can be implemented in both C++ and Blueprints in Unreal Engine 5 (UE5).

C++:
If you have experience with C++ and prefer to work with code, you can create an Octree data structure using C++ and implement the LOD system using C++. This will allow you to have more control over the performance and behavior of the LOD system, and you can take advantage of the full power of C++ to optimize the system for your specific needs.

Blueprints:
If you prefer a more visual approach, you can also implement an Octree-based LOD system using Blueprints in UE5.
You can use the built-in “Streaming Levels” Blueprint nodes to handle loading and unloading of levels, as well as Blueprint nodes for Octree, such as “Create Octree Component” and “Box Overlap” which allows you to define your Octree structure and detect player position.

It’s worth noting that you can also use a combination of both C++ and Blueprints, where you can create the Octree structure in C++ and use Blueprints to handle the LOD system and level streaming.

It depends on your own experience and preference, as well as the complexity and performance requirements of your game.

ChatGPT is definitly failing any game design course exams in spite of apparently passing law ones…

No, you definitely would need a c++ solution, and it would have to be mixed in to mesh streaming, from a custom peocedural mesh generation system.

Either way, I have several 200km^2 maps running in ue4 - yea at rediculously barely playable 90fps on a 1080.
It’s definitley not impossible to exceed the size you listed.

To achieve those maps, I just picked 8km size, the second to last option to be precise.
The last option is a performance killer.
The second to last, set to 4km seems to perform OK ish.

For the 200km I had to double the components for it to have a decent amount of drawcalls with impostors.

Its something around 625 map tiles from corner to corner - so if you were at the corner and saw the horizon of the opposite corner you’d have approximately 625 draw calls and meshes on top of the level tile you are on with whatever it contains (Those would be double with 4km map sizes).

World origin shifting is fairly aggressive, set to around 200m or so maximum distance.

Overall, it works ok. Its just the engine that is completely trashed by the last 3 years of epic just not giving a s*t about performance and rendering.

To give you a comparison, cryengine works the same scene with similar but differnt setups for distances and maps at 144fps or more on the same low end graphics card.
Even pre ue4.18 - when they changed landscape LODs from being managed by distance to being managed by screen size - can’t compete with it.

The reason you need octree is that the landscape system in unreal is completely 2d.
The labdscape will be rendered even if the player is nowhere near it. Or under it.
An octree system can by nature prevent that - as well as allowing you to load/stream whatever is relevant to the cell you are in and its ajacents.

While it wont fix the issues with the rendering pipeline, doing things right can result in great performance.
Let me see if I can find a link to the procedural thing that was shared here on the forums for you to check…
Here: Procedural Landscape from Shader Graph w/ Geometry Clipmaps BP/C++

C++ is where it all began for me but haven’t touched it for around 25 years. So reluctant not because I see it as particularly difficult but rather as a time consuming drain to reacquaint myself, and I ain’t getting any younger. The learning curve with Unreal is already sufficient to put game aspirations far enough ahead. Its not that I wont, but that I wont lightly. So I have to rethink.

So perhaps scaling is the answer! But I am weary of difficulties ahead that I am unaware of.

"The furthest photographed sightline in the world is 443 km, from Pic de Finestrelles in the Spanish Pyrenees to Pic Gaspard in the French Alps, almost 100x further than what can be seen driving along the prairies and staring at the horizon. "The Longest Sightline on Earth — Calgary Vision Centre

Well perhaps that is beyond reach, and a target I don’t really need to replicate, but with 1:10 scale a single 8129/8161 px level would become 80km, a compromise that I might live with. Under which basis, from the centre of a level/landscape 40km to the boundary of it doesn’t then require a seamless path other than perhaps into a single adjacent level. So I wonder if it is possible to load sufficient levels to provide for both a long line of sight, when a player is at elevation, and to be able to pass into a loaded adjacent level. If using a grid of 9, I might get away with loading only 4 at any one time to provide for line of sight. And on crossing a boundary re-centring on the new centre of the grid (no-doubt massively underestimating the difficulties involved with this).

The map is using real-earth landscape from DEMs, and targeting the Medieval genera, so not necessary to cater for anything airborne. Just possible high elevations, and even those I might be able to keep to a minimum and with serious elevations probably way off in the future, if maybe the learning curve or technology has moved on somewhat. Starting in the UK there are not so many high elevations.

So I guess I need to learn about “level streaming” amongst other things. Could I work with loading a grid of 9 levels, so that with the player character standing on a peak, I can take a 360 degrees spin and see as far as far as the far side of each adjacent level, and also be able to walk across into one neighbouring level, without a visual load delay (loosing emersion), and without having to delve into C++. Or can it just not be done. I guess each level would need to be rendered, perhaps in the background as the player character ascends in elevation. That is, any low altitude line of sight would at most extend into a single neighbouring level.

@MostHost_LA If you have already addressed this and I have not grasped the gravity - apologies. But would be grateful if you could chime in further. Also curious about the practicalities of having to scale everything should I go that route, meshes, textures etc, and any difficulties with physics, Niagara etc

Ditch the heightmp idea.
Work in something like houdiny and produce meshes to use as terrain.
It will probably allow you to make longer than photographed horizon lines.

If you do not need 100% realism, the meshes dont have to bend into a sphere, so the view can be near infinite.

Using a DCC to produce meshes has several benefits, the main one is that you can reduce the tris count drastically with analytical procedures while maintaining near conpletely accurate topology.
At a distance, that’s all you need.

You can just encircle your olay area with the proper meshes, but since landscapes perform so poorly id suggest ditching it alltogether.