I need help deciding how to create my 512sq km world

Thanks. But with your specs I do not think I could run this on my system. And you have 40fps with only 1 mesh? And without anything else (no folliage, buildings, etc.). I do not think this is an option for me, maybe not even for the player.

What would you recommend? Should I just use landscape actors with world partition?

edit: if I reduce the resolution to 1pixel = 3pixels, I can get my landscape in a 6k x 8k pixel map, and therefore I wouldn’t even need world composition, right? I would have to scale my map 3x and that would be it? (this would correspond to 11 zooms in terresculptor DEM explorer)

Another option, is to create different levels and make the player travel between them. One level per relevant city and its surroundings, although then it wouldn’t be a “continuous” open world. Nevertheless I could cover many more locations.

Agreed. I don’t think it’s a viable solution like that, it was more of a quick test to see how it handled. Maybe @MostHost_LA has some suggestions on collision since they thought it might be a better route than the landscape system.

It could potentially work if everything was broken into small chunks and world partition loaded/unloaded collision with those cells. I have not tested how any of that works yet.

I don’t think you want to scale a landscape by that much I’ve seen in multiple places that scaling a landscape too large causes multiple issues. I was able to get nanite and hlods working using multiple landscape actors and the performance was fairly decent. However I could never get the landscape actors to line up with each other exactly. It makes no sense because the heightmap tiles I was using matched perfectly. Just more strangeness with the landscape system.

I can let you know when I have a chance to test the smaller landscape mesh chunks with world partition, or figure out some other way to optimize them to the point where it’s an option.

1 Like

It could potentially work if everything was broken into small chunks and world partition loaded/unloaded collision with those cells.

This would be using landscape actors instead of static mesh actors right?

However I could never get the landscape actors to line up with each other exactly.

Were you importing tiles as landscape actors? I read from @noone that it is unnecessary and it makes the same effect as having just one big landscape actor. He also mentioned in other posts something called batch importing for landscape actors, but he says that Epic has not provided any documentation on it, so maybe it still isn’t available. When it is available maybe it makes sense to use tiles as landscape actors.

Comment from https://www.youtube.com/watch?v=1rhB6upmskg:

"You can use tiles with World Partition but there is no reason to. It doesn’t let you create larger terrains and it doesn’t split the World Partition cells on the tile boundaries. World Partition LandscapeStreamingProxies are always the same size regardless of the heightmap size that you import.
The tiles are simply stitched in memory back into a single large heightmap, and then converted to World Partition.
So you may as well not spend the extra time tiling and just import the single PNG file.

You also cannot perform multiple imports to create larger landscapes like you can with World Composition. World Partition is limited to 16384x16384 maximum size hard coded in the engine. Anything larger than 16384 total size, regardless of whether you try to import a single file or tiles, simply errors and crashes."

In my case I was referring to using static mesh actors (as if you spawn a house or a tree) for terrain. Also, I guess that using static meshes means that for the NavMesh precise collision settings would have to be applied to static mesh tiles.

Anyways, for world partition, should we seek the smallest number of tiles or the maximum for a given ammount of components? Also, does world partition take pixels into account or distance? I mean if I have a 1pixel=2meters resolution, will the resources that UE need depend on the pixel or the distance? Because if it depends on pixels I’m confident my PC can load a 7651 × 14281 pixels map (15 components x 28 components with 1 tile) at a 2m resolution (15.3km x 25.8km). The concerns then are then in-game performance of using landscape actors instead of static mesh actors.

FWIW, I thought to add a comment, even thought it might be a diversion. It’s added here more for performative feedback… It’s long so I stuck it all under a summary-marker. Hopefully it’s useful to OP.

The Post

I’ve been watching this thread b/c I’m in a similar position to make a very large world and my method, very different, might help or at least be a point of reference about what does what and what FPS you might expect. Not trying to take over the thread, brag, etc. It’s just I have the same challenge to overcome and here’s how I am doing it…2¢.

Overall my setup uses landscapes with attached RVTs and heightmeshes (meshii?). Alluded to up above in MostHost_LA’s post (I need help deciding how to create my 512sq km world - #4 by MostHost_LA) where one might chunk-up the landscape vs using one large setup, I’d be using 10km by 10km chunks for something ~30km wide and ~50km long (an ovalish island mass). Each chunk is large enough that you would only ever see into the adjacent ones so worst-case would be a 4-corners scenario. MAYBE with a flying mount, but I imagine if they are high enough to see more than 1 adjacent-cell, I would be able to swap out imposters, etc…

Taking a 2k heightmap at 1pixel/meter to a landscape of 256 components, scaled to 500x500x300. If I mathed correctly, that should be 10km per-side(?).

Landscape is set to not render into anything but the RVT and only has to handle height information as well as a mineral/veggie/water map (basecolor channel) and the vertexnormalws (normal channel). On the other end I was able to get the entirety of the display-layer in just the heightmesh. It rules out RVT-blending but the material can be applied to meshes as well as the heightmesh and still sample alpha-maps from the RVT, blend against that, etc…

I don’t think world-streaming/world-composition, landscape-nanite even apply since the landscape is never rendered. ‘Tessellation’ is applied in the heightmesh, can be adjusted, yadda, and height-information can be VERY detailed (pics at bottom).

Regardless, for performance on the following machine

Specs

Test Conditions

On that 10km x 10km square (made per the above), on Epic quality, with screen-percentage at 100 (I use a temporal-sample-index in my materials so I’m obligated to use TSR). UltraDynamicSky & Weather, stock-settings, Volumetric-clouds.

RVTs. NOTE: there seems to be a bug when you set the height-value above 256KTex, or for me at least it presents here, so I would rather use 12,0,1 and get more, smaller, more-granular tiles for performance reasons, but I am stuck using 11,1,1. Assume a slight uptick in perf if that gets resolved:

To my eyes, disk-cost is low:

Level:

Nothing else is running:
image

I ran the tests in a standalone game-instance as run from the editor.

Results - Screenies

1920x1080:

4k (ugh, the pain):

4k @ 50% screen-%:

stat-values:

draw-calls are looooooooooooow:

Fidelity of the heightmesh for detail. It can certainly be made more-dense if you wish it to be…

My material is NOT cheap :frowning:

landscape:
Base pass shader without light map: 65 instructions
Base pass vertex shader: 372 instructions
Texture samplers: 1/16
Texture Lookups (Est.): VS(4), PS(14)
User interpolators: 4/4 Scalars (1/4 Vectors) (TexCoords: 4, Custom: 0)
LWC Promote usages (Est.): 17
LWC Demote usages (Est.): 6
LWC Add usages (Est.): 5
LWC Divide usages (Est.): 6
LWC Multiply Vector Vector usages (Est.): 4
LWC Other usages (Est.): 1
Shader Count: 11

heightmesh:
Base pass shader: 591 instructions
Base pass vertex shader: 184 instructions
Texture samplers: 3/16
Texture Lookups (Est.): VS(0), PS(12)
Virtual Texture Lookups (Est.): 6
Virtual Texture Stacks: 1
User interpolators: 16/16 Scalars (4/4 Vectors) (TexCoords: 16, Custom: 0)
LWC Constructor usages (Est.): 6
LWC Promote usages (Est.): 19
LWC Demote usages (Est.): 10
LWC Add usages (Est.): 8
LWC Subtract usages (Est.): 5
LWC Divide usages (Est.): 4
LWC Multiply Vector Vector usages (Est.): 9
LWC Other usages (Est.): 1
Shader Count: 5

I’ve already dropped 4 landscapes in and run a 4corners test, the numbers weren’t terrible but it was pre 5.3 and pre-much-stuff-done to the landscape material. I’d be happy to rerun tests sooner vs later if anyone feels it’s worthwhile. I have to do it anyways so this weekend would be fine I guess. Just let me know.

Otherwise, carry on with your regularly scheduled programming…

2 Likes

So, if I understand correctly, you have made a basic landscape, you have created meshes to which you have applied the heightmaps so that they were shaped as you wanted and finally the RVT passes the texture from the landscape onto the meshes? Is it like this video?:

Or this video? It is in blender instead of UE, but it’s just to see how to apply the heightmap to a static mesh (minute 3:20):

Please correct me if I’m wrong. Also, could you explain in more detail how to do it like you’ve done? You seem to have 100+ FPS which is kind of great.

Although in your case it seems that you really have a massive map (1500 sq km?). In my case it’s only 12,29 km x 24,58 km = ~300sq km at a 2m resolution, the pixels are:
width: 6144
height: 12288
But then again, you have a really good performance, so it still interests me. Does your method pose any problems in terms of NavMesh, splines, and whatever else?

With your system maybe I can make a larger terrain so that the map is not sharply cut and the player can see some continuity, even if it’s inaccessible terrain.

I’m using the virtual heightfield mesh, it’s not a static mesh or a landscape-mesh in and of itself. It IS driven by a landscape but you never see it.

Crushed for performance

Overall, you have a material on the landscape render it’s height in a runtime virtual texture (RVT). The heightmesh is set to sample from that RVT and render it’s height as stored therein. Since it can be drive by materials, you can use textures + maths to make all sorts of interesting and organic mixes. There are also other channels in the RVT for basecolor, roughness and the like but they are just lanes/channels. In my case I use them to carry alpha-information for minerals, veggies, and water locations.

You can then set the landscape to just not render in the mainpass, make it unlit, no lighting at all b/c it’s just a glorified render-target… Even if you render PBR information into it, don’t light it, it will be light when one samples it in the heightmesh.

As an aside, with nanite on the landscape one could get a similar result with small-scale deformation and skip the heightmesh. The landscape could still also render to the RVT if you need to sample that information elsewhere. However, no idea on performance as I have not tried this.

Otherwise, to explain:

  • enable this plugin:

  • there is sample content under the Engine folder in the Content Browser:
    image

  • this is a good video on how to set up the runtime texture volumes, etc: https://www.youtube.com/watch?v=guRRhz0miO0

  • ref:

  • coming in from the left, the red circle is the result of all my displacement-math, the same you might do on a landscape currently. take a heightmap, do stuff, but in this case inside of pumping it right to WPO, we add it on top of the z-value of the world-position of the pixel, and pipe it to the worldheight of the RVT output node. That’s the worldheight of the heightmesh when it renders, it’s only z-deformation; _height_mesh, get it? :smiley:

  • that height RVT is rendering to a virtual texture:

  • which is then sampled from the heightmesh:

  • the landscape also renders into the virtual textures:

The heightmesh is this endlessly tessellating surface that in it’s material, I sample from the RVT holding the alphas and paint rock, stone, etc accordingly. It’s height, as shown in that wireframe shot in my last post, is whatever was written to the output node in the landscape material. You can also write that displacement-value out to the WPO of the landscape if you want it to drive collision as well.

The overall intent here is to make the landscape large, to express large-features, but it CAN also express small-details like divots, rocks, all that stuff as well. I’m still of the intent to use rock-meshes and the like to blend in with the landscape ala Elden Ring and the like. As well, since it’s a landscape, the grass-system is available; a lot of ancillary stuff can be driven by the fact it’s a landscape material. There is also potential to capture critter movement/velocity on a render-target, and use that to drive footprints, crushing down snow, ripples in water, etc.

To your questions:

But then again, you have a really good performance, so it still interests me. Does your method pose any problems in terms of NavMesh, splines, and whatever else?

The landscape is still there for collision and navmesh. You can use landscape-splines, the water-system, and anything else that interacts with the landscape. Since the worldheight is sampled in the material, it’s done last, after landscape-stamps, layer-edits, and even math in the material.

As well, since landscape-splines and water-bodies can write layer information into the landscape, their named-layers can be sampled in the landscape material, effecting a pass-through. In my case, water bodies write their alpha into the landscape material which goes into the RVT which on the heightmesh, I can pull the appropriate textures from the texture-array I use therein, and automagically have the underwater parts go all underwatery, blend the landscape to sand/worn rocks, add in a mask for algea, etc; whatever you can think of. Once you can persistently track the where (alpha) of the things you want, you can paint (display) them however you want.

Would You Like To Know More?

1 Like

Tomorrow I’ll read more carefully your answers and I’ll try to implement it. For now I have managed to get this potato landscape using world partition and streaming:

This is only with one component loaded, so I do not know why are there parts of other components loaded. Anyways at least I was able to import it, that’s a start.

There are so many options in each menu that I do not know if I’m missing something.

I’ve not played around with the world-composition. I was sucked into tessellated-non-tiling landscapes early on and that necessitated using the heightmesh once tessellation was discontinued.

I have, however, been very impressed with what it can do.

As well, to reiterate, it’s just one landscape, merely scaled up massively. It could even get bigger, use a single 4k heightmap or the like. I didn’t even get into world-streaming multiple landscape as I don’t think it even matters; the landscape(s) will be hidden behind the heightmesh…

Glad I was able to get you thinking. I love this stuff, so feel free to ping me with questions.

Would a tutorial on setting up a heightmesh be helpful here?

1 Like

Re the tile alignment in blender (or anything really), you have to make sure your rotations are correct and your exported heightmap shares the exact same format.

Re the collisions, you just create simple convex collisions for the tiles - using automated systems or the engine.
You set the number of poligons to maximum and the number of vertex to maximum you get faily decent performance and fairly decent collision.

Definitely don’t go with complex as simple.

The heightmesh sounds like an interesting alternative, but the load of it for a tiled or tiled like world may not work.
On the other hand, RVT on world comp tiles are probably still broken - to where you need a different material set up for each tile, I’m sure.

Each component is a drawcall. So less components means better perofromance.
To a point anyway.
Generally definitely use 2x2, so its less componentns.
The rest depends on the size you need really.

1 Like

For your stats to be meaningful we need the size on screen(resolution) and also you really have to test it as standalone with the engine closed or minimized.

Just because 4k is getting 30ish fps doesnt mean that there arent other things you ought to disable to properly test this.

Whats going on with the sky for instance? If you are using the cloud thing, thats probably what is eating up your FPS more than anything.

If you want to know your unit cost, disable everything. Leave just 1 directional light, no athmosphere, no skylight, literally just the landacape.

At that point you will know that just the landscape/rtv combo costs X.

Based on that you can take educated guesses as to how much adding other elements (like coulds) which may have to be similarly tested will end up costing in worse case scenarios.

While what you are getting is interesting, the cost of rendering a landacape tile on your pc without the rtv and everything should also be used as a compartive factor.

Then you can safely say “using this costs less” or “using this costs more”.

As of right now, what you can say is: “using this looks way better for what I think is about the same performance cost of the scaled landscape itself”.

Its most definitely an interesting approach and something that should definitely be investigated further if the unit tests prove the cost is about the same, slightly more, or flat out less.

Unfortunaly as I already stated, I don’t think this can work on world composition simply because they never finished implementing the RTV correctly.

1 Like

Numbers were just for reference; I almost never see hard numbers on anything, just projects I can explore locally.

FWIW, I’m not holding it out as what I think I can get away with, downgrades to some things are likely.

The scene is about as bare-bones as one can make it. There is only the one directional-light (the sun), and no static lights. If there are other things I can turn off/trace, I’d love to learn (no sarcasm, genuine question!).

FYI, resolutions are noted above the screenshots, and the stats-output shows the volumetric-clouds @ .55ms; not too bad. Certainly not the costliest thing in the scene.

While what you are getting is interesting, the cost of rendering a landacape tile on your pc without the rtv and everything should also be used as a compartive factor.

→ Up until nanite-tessellation, I wouldn’t have been able to do this. I do plan on trying since it’s going to give the same visual result but unsure how the tessellation will work. The height-mesh does quite well with transitioning LOD’s, there’s just no swimming anymore as far as I can see.

As well my RVT densities are low; they can hit 4MT which at 256KT per cell, that would be (if I have my #'s right) a 40km x 40km square, all for 1 landscape and accompanying set of RVTs + 1 heightmesh, nothing more than I am already using right now, just a larger underlying landscape… Only reason I have not yet tried this is the aforementioned bug. If I set the worldheight RVT density too high, the heightmesh quarters itself (I reported it)… :frowning:

Again, not to hijack this guys thread but given I’ve been able to check all the functional requirements for my setup, my current metric was to be able to get on a horse in the game and just be able to ride across a singular biome, like a desert, to the entirety of this song

One thing to note is if anyone chooses to paint PBR information into the RVT, use it with heightmesh blending and whatnot, you can select landscape components and put different materials on them. IF I recall correctly, the material-binning solution will work with material-instances off the same root material (eg: all switches are set the same, all paths the same) so if, for example, you change only the textures and some scalar values in the instance, and don’t change anything that would otherwise cause a recompile, you could still benefit from the binning process by having the ‘same’ (root) material across the entire landscape. (Someone has to confirm the binning process DOES work this way, I want to say I remember this from the nanite-reveal a couple years back but plz confirm…). This might allow one to streamline, use the same root material on the same, singular landscape, but also have desert here, water there, etc, etc…

EDIT: just musing about, I could do 2 30km x 30km blocks north-south of one another, and only double the current setup. 2MT per RVT, still 4MT total (same cost). And I am guessing with clever use of big static meshes like mountains, or landscape design, one wouldn’t need to be able to see the other landscape at all, so still just the one.

1 Like

@Frenetic
If you could do a tutorial it would be great.

@MostHost_LA

Re the tile alignment in blender (or anything really), you have to make sure your rotations are correct and your exported heightmap shares the exact same format.

But the problem is when importing into Blender, the tile meshes do not adjust well. When exporting the tiles from TerreSculptor they are exported with the same settings. What I believe is happening is that when tiling the heightmap the greyscale is being recalculated for each tile individually, so in one tile the white part can be 1000m and in another one 600m. If I send all the heightmap tiles into QGIS and I merge them, then split them again preserving greyscale it should work. I will test it later.

RVT on world comp tiles are probably still broken

But we’re talking world partition. Also, is it better to use RVT or SVT if my world partition landscape uses streaming?

So less components means better perofromance.

Do you know the performance implications of each element in world partition: component, quads, sections? I just decided to go for a resolution that is a prime number for both height and width so that tiles would not get generated within components.

Also, with my current map and world partition, since it is less than 16k x 16k pixels, I can still have Edit layers enabled, which allows me to modify the terrain in game, which is great for adjustments, specially with a rough terrain like mine I can create flat paths.

As for performance, with all eight regions loaded I still get 100 fps in Editor without nanite. Upon checking the nanite box, I had 80 fps (without building data). Upon building data for nanite, 70 fps. Why is it that nanite makes things worse if my poly count is high? I have like 170 million tris across all landscape.

Anyways, since I’m having good performance with the simplest of methods (import a heightmap directly into UE) I might try to use this one. Maybe later with the rest of assets that the game will have (characters, buildings, folliage) this performance drops a lot. I don’t know.

No idea. I know RVT wont really work on landacape tiles unless you set up different materials on each.

This probably has to do with your crop/cut.
You can tey to cut the tiles with an extra pixel all around, so that there is a clear overlap of 1m at all borders.
If that solves the positioning you can then just redact the mesh by eliminating the extra border.

No, I use world composition because world partition has literlaly never worked.

Assumuing its similar, then the implications have to do with the tris cound of each component.
The hogher the tris count (of lod0) the bigger the size of the component (at lod0) the harder it will be for the system to handle.

Well, for one it was just released.
On top of that unless you have a very special setup where you benefit from nanite (ei: 1 vert per cm), I don’t think there is much of a benefit from it.

1 Like

Well, I have been able to create a 32x32km map at a 3m resolution which is around 12k x 12k pixels. But when importing the map, it only creates 4 regions that cover 4x4 proxies. That means that I still need 5 regions more that for some reason are not being created. The proxies of these missing regions are there but they cannot be loaded. Only the proxys that have regions covering them can be loaded. Something I’m doing wrong.

Nevertheless, if I crop the map into what I really need and use a 16km x 26km map at a 2m resolution, which is about 8k x 12k pixels then I can load the map correctly. Since that is what I need I guess I could make that work.

On the other hand, maybe I use level system in which each level has a small terrain heightmap of some relevant location, and I will connect these levels with some teletransportation. Maybe I would set these levels with world partition too if they are bigger than 8k x 8k, but the bottom line is I wouldn’t need to worry about performance. Of course it wouldn’t really be an open world, since you would be able to free roam only some locations and not the real life full map. Maybe it’s also better like this in order to avoid having to populate irrelevant areas. On the other hand, I will have to establish some logic to reduce stats when travelling form one level to another.

edit: I have been playing around with an 8k map without world partition and I might have subestimated how big this maps can actually be even if they seem little at the editor viewport. I think I’m going to stick to the idea explained above and not create such a huge map, but rather small pieces of it that will be in different levels.

edit2: now I can use a single static mesh as landscape too, since I will be using just one static mesh and not have problems with the edges not matching.

Thanks a lot to everyone who participated in this thread @MostHost_LA @noone @Frenetic @TimBayer @game-maker

Even though I will not create one huge open world, I will surely run into problems of other kinds and I will open other threads hahaha

I created that tutorial. When it’s published I’ll come back here and update w/link.

Here you go: Implementing a landscape with a virtual heightfield mesh. | Community tutorial