Search Unity

2018.3: Update terrain collider at runtime with new Terrain API

Discussion in 'Scripting' started by derp_bot, Dec 20, 2018.

  1. derp_bot

    derp_bot

    Joined:
    Nov 21, 2012
    Posts:
    8
    Hi all,

    I am attempting to update a terrain at run time on the GPU using the new 2018.3 terrain API.

    I am using https://docs.unity3d.com/ScriptReference/TerrainData-heightmapTexture.html
    to blit a brush texture into the terrain heightmap and using a shader to directly modify the heightmap
    render texture on the GPU.

    This works as intended, however the attached terrain collider is not updated at the same time.

    I figured that is what https://docs.unity3d.com/ScriptReference/TerrainData.UpdateDirtyRegion.html
    is intended for, except it does not work. I have tried calling it directly after the blit, and also tried waiting for a frame to call it, thinking maybe the blit may not be instantaneous and needs time to propagate.

    I have also tried https://docs.unity3d.com/ScriptReference/Terrain.Flush.html, which doesn't seem to do anything except disable GPU instancing and tank performance.

    The only way I can get the collider to update is by:

    Code (CSharp):
    1.             Terrain terrain = GetComponent<Terrain>();
    2.             TerrainData terrainData = terrain.terrainData;
    3.             int width = terrainData.heightmapWidth;
    4.             int height = terrainData.heightmapHeight;
    5.             float[,] heights = terrainData.GetHeights(0,0, width, height);
    6.  
    7.             terrainData.SetHeights(0 , 0, heights);
    The GetHeights call allocates a 64mb array though for a 4097x4097 heightmap, which is clearly undesirable.

    Should UpdateDirtyRegion update the collider? The docs seem to imply it should. If so, has anyone got this to work?

    Allocating a 64mb buffer everytime I want to apply changes to the terrain is not going to work.
     
  2. CW3MH6

    CW3MH6

    Joined:
    Jul 4, 2013
    Posts:
    14
    Have you figured anything out? I am having the same issue. We modify the terrain at runtime using the new GPU based modification tools, but the colliders do not update until after I go back into Scene View and modify the terrain slightly there. Other than colliders, everything works perfectly (sculpting and painting)

    Edit:
    This function call seems to fix it, though there is a small performance hit (FPS hiccup). So I only call it when the user has let go of the mouse button and stopped modifying the terrain.

    terrain.ApplyDelayedHeightmapModification();

    Was hoping there'd be a way to do it without lagging.
     
    Last edited: Jan 28, 2019
  3. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    397
    Using that function doesn't work. It doesn't update the collider, even after calling SetHeights .
     
  4. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    397
    For anybody looking for help, to update the TerrainCollider you have to update the heights on the terraindata of both the terrainCollider and the terrain. Seems like there is a copy. Changing the terrain only will update the visualization but not the collider itself.

    terrainCollider.terrainData.setHeights(...)
    terrain.terrainData.setHeights(...)

    In v2019 the terrain has been moved to GPU and the API changed, so maybe this doesn't work. Seems like there is a function to update "dirty" data.
     
  5. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    Well ... what used to work for me was to set the TerrainCollider to use the same TerrainData object. Why maintain two separate copies? (if you need to, for performance reasons, then go ahead, that seems to be why it's an option?)