Search Unity

[SOLVED] Unity Editor - Issue procedurally generating terrain

Discussion in 'Scripting' started by thesupersoup, May 21, 2021.

  1. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    Hello,

    I'm working on an editor tool for generating terrain tiles for a large overworld. Ideally, this tool would generate terrain with given parameters, each in their own scene, then additive load them in editor for the developer.

    At present, the generation and additive loading seems to work fine, but the resulting terrains cannot have their heightmaps edited. Drawing holes works as expected, if that is pertinent info. What is the (hopefully simple and overlooked) solution for this problem?

    The applicable portion of the code is below (note that the user facing GUI uses some int sliders to specify factors of 64 or 8):
    Code (CSharp):
    1.  
    2. private void Generate( int x, int z, float size, int bR, int hR, int aR, int dR, int dPP, float y )
    3. {
    4.     bool saved = false;
    5.     if( !AssetDatabase.IsValidFolder($"Assets{wdPath}") )
    6.         AssetDatabase.CreateFolder( "Assets", "WorldData" );
    7.  
    8.     for( int i = 0; i < x; i++ )
    9.     {
    10.         for( int k = 0; k < z; k++ )
    11.         {
    12.  
    13.             Scene s = EditorSceneManager.NewScene( NewSceneSetup.EmptyScene );
    14.             s.name = $"Scene{i}_{k}";
    15.  
    16.             TerrainData d = new TerrainData();
    17.             d.baseMapResolution = bR * 64;
    18.             d.heightmapResolution = hR * 64;
    19.             d.alphamapResolution = aR * 64;
    20.             d.SetDetailResolution( dR * 64, dPP * 8 );
    21.             d.size = new Vector3( size, 0.0f, size ); // Have to set after other data so it doesn't get overwritten
    22.  
    23.             GameObject obj = Terrain.CreateTerrainGameObject( d );
    24.             obj.name = $"Terrain{i}_{k}";
    25.             obj.transform.position = new Vector3( i*size, y, k*size );
    26.  
    27.             Terrain t = obj.GetComponent<Terrain>();
    28.             if( t != null )
    29.             {
    30.                 t.terrainData = d;
    31.                 t.Flush();
    32.             }
    33.             else
    34.                 Debug.LogError( $"Error fetching terrain component for scene {s.name}" );
    35.  
    36.             AssetDatabase.CreateAsset( d, "Assets" + wdPath + $"/{s.name}TerrainData.asset" );
    37.  
    38.             EditorSceneManager.MoveGameObjectToScene( obj, s );
    39.  
    40.             saved = EditorSceneManager.SaveScene( s, fullPath + $"/{s.name}.unity" );
    41.             // TODO: Better error handling on failure?
    42.             if(!saved)
    43.             {
    44.                 Debug.LogError( $"Error encountered while saving scene {s.name}" );
    45.                 break;
    46.             }
    47.         }
    48.         if( !saved )
    49.         {
    50.             break;
    51.         }
    52.     }
    53.  
    54.     AssetDatabase.Refresh();
    55. }
    56.  
    Thanks for taking a look!
     
  2. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    Maybe I should have named the thread something different, like "Issue handling Terrain Tiles in Editor" so it doesn't get dismissed out of hand as a newbie question...
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,738
    Just eyeballing the code here but isn't line 36 ONLY making an asset out of the
    TerrainData
    (eg, what is in
    d
    ) and not the
    Terrain
    itself??

    It might be possible that a TerrainData can live naked on the disk like that, but I don't think I've ever seen such a thing.

    I think if you pluck apart a Terrain asset made in the editor, it IS a Terrain, and it has a TerrainData, and potentially SplatMaps and details and blah blah blah

    It would seem that just using
    d
    would not be able to get you there.
     
  4. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    Yeah that's a fair assessment. I would be inclined to agree with you, but even making a stock terrain in editor, the only asset file I see getting written in the terrain data. And most examples I find (granted, I'm leaning on random internet-goers to be relaying what actually works for them) specify just creating the terrain data asset from what I see. In the interim, I've gotten started on a trail of perhaps generating textures for the terrain as well, so I'll post whatever solution I find that works.
     
  5. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    Well, I found the issue, and it was simple.

    When specifying the TerrainData size:
    Code (CSharp):
    1. d.size = new Vector3( size, 0.0f, size ); // Have to set after other data so it doesn't get overwritten
    Unity seems to use the Y value to determine the maximum range between the lowest point and the highest point for a given terrain. So with a value of 0.0f, there was literally nothing to be done. Specifying a value solves the issue.
     
    Kurt-Dekker likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,738
    Ah yes, that makes sense now. Pretty sure the actual heightmap data (what you get from GetHeights()) is ALWAYS 0.0f to 1.0f, and that Y size you speak of determines the effective multiplier... so if you set it to zero, it's gonna never be anything but flat.
     
    thesupersoup likes this.