This section will run through some of the large problems I have had while creating Fractured Dream.
The biggest problem that has happened so far involves the landscape and the collision of the landscape. Fractured Dream is built on a very large open world, where the entire landscape needs to have accurate collisions. The main issues were editing, triangle count, performance, and concave collisions.
Starting with the simplest fix was editing. When I started modeling the landscape, I started with just the starter island mesh. Quickly I realized that starting with just the single mesh was not going to work as when I attempted to move to the next chunk, there was always a noticeable seam between the island mesh and the next mesh. I could have used objects in game to cover the seam, but it did not seem like the most efficient method.
So, the next thing I tried was just one large mesh for the entire world, which immediately ran into performance problems in blender when I attempted to do any detailed work. What I then attempted was one large mesh split into chunks and this worked, only problem was again the seams between chunks, in the end I went with this method, I just avoid messing with the edges of the chunks.
When I sculpted changes, I would create a chunk out of a larger chunk that includes more landscape than I was going to edit, that way I could easily avoid messing with the edges. Which then I can rejoin the separated chunk with absolutely no seams.
Reducing the triangle count was extremely important, which will be more explained inside the collisions segment. There were two problems with that,
- Manually reducing the triangle count for the entire world would take forever.
- Using outside blender programs to clean topology would edit the seams breaking and causing seem issues.
I found 2 solutions depending on the situation.
- Using geometry nodes when the entire edge of the chunk was lower or higher than the majority of the chunk, as you can filter out by world height.
- The decimate modifier in blender only works on the selected vertices, so do not select near the edges, then manual fix issues.
Most of the time I use the decimate modifier, sometimes I use the geometry nodes method if I also want to add some quick vertex displacement, like on cliffs.
Performance was also a fairly simple solution; it was all to do with chunking. What I did was try and map out where players would spend the most time and create chunks for those, so the rest of the chunks do not need collisions. I also set up the landscapes as occluders, this way if only one chunk was visible, the rest were hidden. Reducing the triangle count also helped.
The last, and biggest, landscape problem was collisions. The issue comes from Unreal Engine having some major collision limitations.
- Unreal Engine cannot calculate large concave shapes’ collision without using complex collisions.
- Nanite breaks complex collisions, when meshes have more than 32k triangles or unclean geometry
- Complex collisions are expensive
To attempt to solve this I had a couple solution, the first test was to put the mesh into a program called instant meshes. This took the imported mesh and cleaned the geometry automatically. Then I took the chunk of land I cleaned and split it up into smaller chunks less than 32k triangles. There were 2 issues with this method. First the large chunk had a seam now when compared to the rest of the world, and the second problem was there were close to 70 small chunks that had to be manually split and worked with, this was too many to make it seem reasonable.
With this issue I decided to pivot and attempt a different solution where I two copies of the same mesh, one that will be visually render, and one that will just be for collisions. I tried this and found that a very similar result, by performance metrics, was by just using a single mesh without nanite fixing the collision issues, with this solution I just had to spend more time on optimizing the mesh so that the triangle count was not too high. Currently as of writing this, there is still one problem as Unreal Engine does not like calculating large shadows created by non-nanite objects. Currently I have not found the solution to this, but there are two purposed solutions.
- Going back to using a collision mesh and a visual mesh, where the visual mesh is nanite.
- Changing from virtual shadow maps to traditional shadow maps
The only issue with just having two separate meshes is that it will break my vertex painting on the landscape, I use vertex painting for biome blending and paths. You can use vertex painting on nanite objects, it just is a different method and I am not sure of the performance implications yet.
