Search Unity

Terrain Compression for vert/tris on the GPU

Discussion in 'World Building' started by crysicle, Jul 27, 2019.

  1. crysicle

    crysicle

    Joined:
    Oct 24, 2018
    Posts:
    72
    Is there a way to compress the verts/tris of the terrain without going through SyncHeightmap()? I need to do it each frame after manipulating the whole heightmap for which SyncHeightmap() is way too slow. Without compression, vert/tris count is too high even on lower resolution terrains, the problem is magnified further without compression if the terrain is casting shadows, which almost triples the vert/tris count. There are a few other methods which can do the compression, but all have a similar performance impact as the parameter TerrainHeightmapSyncControl doesn't have an option to sync vert/tris LOD directly and needs to do a GPU to CPU request.

    According to the docs on TerrainHeightmapSyncControl.HeightAndLod:
    -Synchronizes height data of the heightmap texture from the GPU back to CPU memory. Then computes LOD data, used for determining the tessellation level, from the height data.

    Could this be done on the GPU before the data sync or must the algorythm exist explicitly on the CPU?

    Verts/Tris not synced - https://i.imgur.com/ZUX8jQI.png
    Verts/Tris synced - https://i.imgur.com/zwd9qD4.png

    2019.1.8f1
     
  2. ChrisTchou

    ChrisTchou

    Unity Technologies

    Joined:
    Apr 26, 2017
    Posts:
    65
    Short answer: no, the LOD is only updated by SyncHeightmap().

    Tell me about your use case though:

    Do you need collision to be updated? If so the GPU->CPU copy is required, as physics is 100% on the CPU.

    Are you seeing vertex count as an issue? or draw call count?
    One option is to just not use LOD, if you're trying to do something completely dynamic, and don't care about collision.
     
  3. crysicle

    crysicle

    Joined:
    Oct 24, 2018
    Posts:
    72
    For my case i'm creating a system where you can manipulate up to 3000x3000 heightmaps every frame without incuring heavy penalty on the FPS. Currently the main bottleneck is the vert/tris count. On terrain resolutions of around 4096x4096, if the vert/tris LOD is not synced, the vert count goes up to more than 100 million. The only resolution on which the system can work at the moment without problems is around 1024x1024, because the vert count only goes up to 6.5 million, and 2.6 if you disable terrains casting shadows.

    As for collisions, i created an addittional system to create meshes only in specific areas where terrain synchronization is needed as well as calculate tree/detail position and rotation inside a shader and get the information back asynchronosly.

    Here's a few examples of 1024x1024 terrain being manipulated:
    Mandelbrot - https://i.imgur.com/uZBTtIx.gifv
    Painting - https://i.imgur.com/xKSdPOO.gifv
     
  4. ChrisTchou

    ChrisTchou

    Unity Technologies

    Joined:
    Apr 26, 2017
    Posts:
    65
    So you are building a 4k x 4k heightmap on the GPU and want to render the Terrain from that, with collisions handled through a custom mesh you build where needed?

    Is it all procedurally generated? Or do you need editor painting & sculpting + dynamic runtime modification?
    Do you need global illumination on your Terrain, or path finding?

    I'm interested because we are working on the new Environment system, and want to make it as flexible as possible to handle use cases like this. :)

    Also if you don't need much other than a nice heightmap render with simple LOD, that could be done with a custom renderer.
     
  5. crysicle

    crysicle

    Joined:
    Oct 24, 2018
    Posts:
    72
    Pretty much, though 4k x 4k is probably something only 1080 TI and greater GPUs would be able to handle. On my geforce 970, the terraformation system can handle up to around 2800x2800 heightmap modification with negligable FPS impact, though it sometimes stutters. At 4k x 4k, the FPS dips to 30.

    It's a hybrid between procedural generation and sampling values from textures which can then further be used to generate new information. It can animate a spritesheet, paint proceduraly, remap values, cascade, resize, rotate, move, or negate effects from other terraformations as well as some other stuff.

    Example of a noise texture as input into the system with some remap -


    As this is a system i'm making for my game, there will be scenarios where i will use it extensively in certain areas and very little in others, possibly incorporate it into a combat system where you could punch down a mountain like in one punch man or similar collossal type effects like an armageddon to simulate meteor terraforming physics both on land and water, or smaller magnitude effects. Some effects will stay persistant while others will wane over time.

    Both. Though navmesh support is of greater importance than GI for me personally. Haven't yet looked at either much yet, been too busy integrating features and solving the collision problems.

    It's something that's been on my mind for a long time. I was hoping to find a way around most of the problems i encountered using the terrain componant for this system because it makes the modification to terrain relatively simple as well as provide some nice quad tree optimizations which i don't need to integrate myself. While i did find a solution for the collissions, i can't for the vert/tris LOD since it's a black box issue. I will most likely go with your suggestion after i finish tinkering with my system.
     
    Last edited: Jul 30, 2019
  6. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    830
    This is slightly unrelated, but please make it able to support mesh-based terrains. Most of my terrains are either sculpted and texture painted outside of Unity as part of a huge grid (so that I may have caves/overhangs without being limited by heightmaps in terms of form). I would prefer similar optimizations as the new terrain with it being GPU based and able to be linked to other bits of terrain procedurally. The only major difference would be that it could be divided and linked vertically too and that it is mesh based rather than heightmap based.

    It would be great if an imposter could be generated for larger, distant chunks of the world and this be taken into account for streaming the world. If my chunk size was 100m x 10m x 100m, being able to tell the system that for every 1000m on the x and z axis, drop an imposter LOD with full lighting baked in here when the camera gets too far away.

    Doing this with hexagonal streaming in mind would make things even more flexible, since less terrains could be loaded at a time in any direction. Using this same API for procedural stuff like mentioned here would be handy as well!