Search Unity

Create new terrain at runtime from a sample of another terrain

Discussion in 'Scripting' started by par-002, Sep 3, 2020.

  1. par-002

    par-002

    Joined:
    Jul 4, 2012
    Posts:
    52
    I put this in the World Building forum but it doesn't have nearly the traction this forum does. Plus, this is most likely a coding question :)

    I am not exactly sure how to word my question but this is what I'd like to do:

    During runtime, take any random bounding box of a terrain in one scene, grab the heightmap and texture information about the terrain and then create a replica terrain (for another scene) of just the area inside the bounding box. I need to do this at runtime because the terrains are dynamically generated.

    Original Terrain:


    Pseudo Bounding Box:


    New Terrain:


    Is this even possible?

    Thanks!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    This is extra complicated because that 2D rectangle gets projected to an irregular shape when using a perspective camera.

    I'd break this problem space down into at least two separate problems:
    1. Given a rectangular subsection of the Terrain defined by a https://docs.unity3d.com/ScriptReference/Rect.html, generate a height map of that rectangular section by sampling the existing terrain. You can decide on a sampling resolution, then iterate over world space using that resolution and sampling the height of the terrain with https://docs.unity3d.com/ScriptReference/Terrain.SampleHeight.html
    2. Given a rectangle on screen, calculate a bounding rectangle that captures the irregular shape of the screen rectangle when projected onto the terrain from a perspective camera. Then you can feed that rect into the results from the first step, and voila
    If necessary, the sampling of the terrain can be done in a coroutine if it is too slow to be done in a single frame.
     
  3. par-002

    par-002

    Joined:
    Jul 4, 2012
    Posts:
    52
    Interesting... I understand #1 pretty well but not exactly sure what #2 is doing. Thanks for the reply!

    What if, instead of SampleHeight, I basically do all the fancy position normalization with the rectangle corners so they are in Terrain coordinates and then iterate over the result of
    float[,] heights = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution);
    between those positions...

    Would you mind elaborating on #2 a bit more? I might just not be getting it.
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    So if you look at this image:



    And you take the 4 blue "corner points" of that rectangle, and you project them from the camera onto the terrain, and look at where those points intersect with the terrain from straight above, the shape it would form would be like this green trapezoid here. Even uglier if the camera is rotated on the y axis:

    upload_2020-9-2_20-56-21.png
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    So part two would be taking that trapezoid and calculating this red bounding rectangle:
    upload_2020-9-2_20-58-49.png
    Then you can use the red rectangle to be the area of the terrain that you sample.
     
  6. par-002

    par-002

    Joined:
    Jul 4, 2012
    Posts:
    52
    Ah my bad, I should have made a better picture. That rectangle was just a quick example of "snagging a portion of the terrain", not literally grabbing the terrain from the camera's viewport.

    I don't need a trapezoid, I'll literally just be using a bounds rectangle from the Terrain's plane.
     
    PraetorBlue likes this.
  7. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    Oh that's a lot easier! I had fun in MSPaint at least lol.
     
    par-002 likes this.