Search Unity

DIstant terrain rendering, low poly mesh or terrains?

Discussion in 'World Building' started by BIGTIMEMASTER, Apr 18, 2020.

  1. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    What are some techniques used in open world games for distance terrain rendering? To be clear, not talking about props which cannot be reached, but terrain which is part of the playable area, just far in the distance.

    We are loading each terrain tile as a separate scene based on player proximity. My idea is to use low poly mesh version of each terrain for the distance views. This does mean that each terrain is using a material and probably two textures (color and normal).

    I look at the size difference between a mesh and a terrain and the terrain is significantly lighter. But is there more to the picture than that? People seem to generally suggest that unity terrain is inefficient, but based on all the factors I can see, it seems lighter than using a mesh.

    Does anybody know what sort of methods might be used in games like arma, just cause, Ubisoft games?
     
  2. ron-bohn

    ron-bohn

    Joined:
    Oct 5, 2015
    Posts:
    318
    I've used meshes like you described and it works. Plus, if you have the opportunity to static batch those distant meshes. So if you're streaming 1km x 1km chunks for example, you could just put your distance meshes in the same scene as the main starting player/camera and always make it visible, just put it like .5 meters below your terrain or terrain mesh surfaces of the scenes that you are streaming.

    When I did this last it worked really well for extremely far distances and I mainly used it for the horizons of a 30km x 30km test city. Also, my meshes were all atlased, prefabbed, and I used layer culling. I also used no lod's and my "mesh" distance object(s) were effectively like 1 huge lod, accomplishing the same thing that hundreds of lod's would have done, except with much lighter overhead.

    Your project is probably not the exact same as what I was doing, because I had very low memory overhead and therefore didn't need streaming. It worked well from a flight perspective, allowing the player to see 10km in each direction. I used fog to blend the horizon just right.
     
  3. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    2,266
    Don't know for sure how other games are approaching this. I do know Ubisoft uses shader splatting, so they're able to render parts of the terrain using a simplified shader, so far impossible in Unity unfortunately. I supposed the geometry is dynamically tessellated, much like the Unity terrain does it.

    For one project I'm working on, the terrain as a whole is 4096x4096 units, consisting out of 256 tiles. Couldn't use actual terrains for everything, because all the (uncompressed) height and splatmaps take up too much memory and take ages to load. So only 9 real terrains are loaded around the player, and the rest are low poly mesh terrains.

    Earlier on, these were 1:1 copies of the terrain topology with their own diffuse and normal map. But because every tile was unique, this cost a constant ~247 drawcalls to render, and required a sizable chunk of memory for all the textures which affected loading times.

    Currently, the mesh terrains are all identical (flat) subdivided planes. And they're shaded through a single diffuse/normal map that represents the terrain as a whole. In the mesh terrain shader, the UVs are aligned so they match the total terrain bounds. Meaning they match the diffuse/normal information of the real terrains at any point in the world.

    Consequently, a global heightmap is used (with the same UVs) to displace the flat vertices upwards. This looks exactly the same as the previous method. But the result is that all the low poly terrains render in one drawcall, since they use an identical mesh and material. The mesh and textures are cached once the first one loads, so the rest load pretty much instantly.
     
  4. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    very clever solutions.

    i am doing some testing today. i am making use of the new instanced terrain feature which may save me from having to do somethign as sophisticated as what you guys have described, but we will see what the results are. Now if I need to improve performance I have some good ideas to start from. Thanks!
     
    ron-bohn likes this.
  5. ron-bohn

    ron-bohn

    Joined:
    Oct 5, 2015
    Posts:
    318
    What about solutions like microsplat and texture arrays? Do you know how their methods are different, or am I missing something? Thanks in advance!

    Actually in a way the methods we described might sound a lot more complicated than they really are. Much more simple than say scene streaming. A more simplified description is:

    "Meshes were used and shared the same material so the distant terrain/scenery is optmized for draw-calls"

    Aside from atlasing to make your distant meshes share one material, the most complicated part is layer culling which you can do without coding even with this free asset: https://assetstore.unity.com/packages/tools/camera/per-layer-camera-culling-35100 (this is what I used in the example I described in my previous post).

    Either way, hope your testing goes well. Let us know what you turn up!
     
    BIGTIMEMASTER likes this.
  6. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I think i have a clear understanding what you guys are talking about. If i was going to implement @StaggartCreations I may have a few more specific questions, but the idea is clear enough. I just mean that these are sophisticated in the fact that they required you to think outside the box and bit and develop your own solution, rather than something obvious and direct.

    I am using microsplat as well, so maybe that will keep things running smooth without needing to do as much manual work.
     
    ron-bohn likes this.
  7. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    2,266
    From what I've gathered, Microsplat (I'm using this as well) uses texture arrays for the terrain materials. Where the splatmap channel defines the index for the related item in the array. Eg. the green channel on the second splatmap references item number 6 in the array. I believe Megasplat goes one one step further and uses a single splatmap (index map in this case is a better term). Where the values (0 through 255) represent the array index, which is why it supports 256 materials. This is a high-level observation, so may not be entirely correct ;)

    All in all, I think the biggest optimization for distant terrains falls on memory. Unity terrains are fortunately much faster to render since Instanced Rendering was introduced in 2018.3. But the height- and splatmaps in the TerrainData asset are uncompressed, so take up a lot of memory, and need extra time to load in. For the project I'm currently working on, it's limited to 8 terrain materials (2 splatmaps of 256px). Since an extra splatmap starts to introduce hickups in the streaming (especially on non-SSD systems, particularly bad on the Switch). But this is probably very project specific.
     
    ron-bohn likes this.
  8. ron-bohn

    ron-bohn

    Joined:
    Oct 5, 2015
    Posts:
    318
    I'm still catching up on the terrain improvements and actually just started today using 2018 LTS Standard for non-experimental new projects going forward. I've been mesh only for a while and just started using terrains again experimenting with gpu instancing for vegetation...especially grass. Also, that's good to know about the uncompressed splatmaps...I never knew the why behind that performance bump. Thank you very much for your explanation.
     
  9. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    yeah this has been very informative. a short masterclass :)
     
  10. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    Pretty close, it's two indexes and a blend weight between them, allowing for 2 layers of painting on each vertex or terrain point. With both layers active, this means 6 samples per pixel per set of textures. MicroSplat uses a different technique, but once it's done sampling (or generating) the splat map info, it only samples 4 sets of textures per pixel. Both are designed to have a consistent sampling cost regardless of how many textures are used on the terrain, MicroSplat's one exception being the splat maps, which can become quite large if you have a lot of textures.

    That said, I allow you to export the splat maps and use them from external files. This allows you to compress them, for a large memory and loading savings. On PC it's a 4:1 savings, on platforms that support better texture compression formats it can be much higher.

    I think this is true for streaming, but in terms of drawing it's all about micro triangles and fill rate. Unity's base map technique can be a nice savings, as it swaps the splat mapping for a simple diffuse/normal map lookup. But when you're on a reasonable GPU, the actual cost of doing splat maps can be quite cheap, since all the textures are in a low mip and fit in the cache anyway. Given the new features Unity has added for basemap generation, I suspect they are going to be enabling a Virtual Texture Cache at some point in the future, where a lot of this becomes moot because everything gets rendered to what is effectively a giant base map texture. At that point, the gains of having dynamic LOD combined with terrain instancing should make it very comparable to rendering meshes with a simple shader, sans the loading cost, as you point out.

    But there's no reason that can't be mipped and streamed too, especially if Unity introduces the concept of static vs. dynamic terrain, such that terrain which isn't going to be runtime modified can take advantage of that to compress more of the data as well as mip it for streamed loading.

    Oh, using a height map, the way described above, to displace the distance terrain in a shader. Definitely the way to go. This lets you share one grid mesh for everything, and only load in height maps to represent the terrain, along with a normal and diffuse representation. This is essentially what the new Unity Draw Instance does, it just uses one mesh which it scales and draws for every LOD. Want to go up a detail level? Draw 4 of them scaled to half size so they occupy the space of one, and adjust the UVs in the shader to match the new scale/offset.
     
  11. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    @jbooth,

    i am pretty new to this stuff so bear with my ignorance, but you are saying that there is a difference between unity internal generated splatmap and, using microsplat, if we select the "use custom splatmap" option, then provide a splatmap from world machine, then that splatmap is able to make use of compression (resulting in memory saved).

    Is that right?

    And if so, any tips about best optimization for compression there? Any special settings we should be aware of here?

    upload_2020-4-23_14-26-0.png

    Thanks!
     
  12. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    Yes- it will change the blending slightly as artifacts are introduced with compression, and you won't be able to paint with unity's tools in this mode, but otherwise yes. You can also paint with the unity tools and export that data as well.

    In terms of compression it's pretty different depending on platform, but DXT5 is going to give you a 4:1 memory savings, where as on mobile there are far more options.
     
    BIGTIMEMASTER likes this.