Search Unity

Creating new TerrainLayer via code

Discussion in 'World Building' started by seelanv, Jun 10, 2019.

  1. seelanv

    seelanv

    Joined:
    Jun 2, 2017
    Posts:
    3
    I am getting the following issue when creating the TerrainLayer via code. The reference on the TerrainData gets cleared whenever the Editor refreshes (i.e. saving the scene, or play mode transition, or code compiles), or when I call AssetDatabase.SaveAssets. To resolve this, I had to explicitly save the new TerrainLayer by calling AssetDatabase.AddObjectToAsset, and adding to the TerrainData that I had already written out. Seems to fix the missing reference issue, and it shows up properly in the Terrain settings.

    Is this the correct way to create or update Terrain Layers via code?
     
  2. wyattt_

    wyattt_

    Unity Technologies

    Joined:
    May 9, 2018
    Posts:
    424
    You do have to make an asset out of it if you want it to persist Editor reloads but you don't have to add it as a sub-asset to a TerrainData asset
     
  3. seelanv

    seelanv

    Joined:
    Jun 2, 2017
    Posts:
    3
    Thank you.

    There seems to be a bug with TerrainLayer references being kept around in the terrain painting tool. When I update a TerrainLayer and save it via code, if the terrain painting tool had reference to it prior, this error is produced:

    Code (CSharp):
    1. MissingReferenceException: The object of type 'TerrainLayer' has been destroyed but you are still trying to access it.
    2. Your script should either check if it is null or you should not destroy the object.
    3. UnityEngine.Object.get_name () (at C:/buildslave/unity/build/Runtime/Export/Scripting/UnityEngineObject.bindings.cs:189)
    4. UnityEditor.Experimental.TerrainAPI.PaintTextureTool.DrawFoldoutEditor (UnityEditor.Editor editor, System.Int32 controlId, System.Boolean& visible) (at C:/buildslave/unity/build/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs:82)
    5. UnityEditor.Experimental.TerrainAPI.PaintTextureTool.OnInspectorGUI (UnityEngine.Terrain terrain, UnityEditor.Experimental.TerrainAPI.IOnInspectorGUI editContext) (at C:/buildslave/unity/build/Modules/TerrainEditor/PaintTools/PaintTextureTool.cs:158)
    6. UnityEditor.TerrainInspector.ShowPaint () (at C:/buildslave/unity/build/Modules/TerrainEditor/TerrainInspector.cs:1375)
    7. UnityEditor.TerrainInspector.OnInspectorGUI () (at C:/buildslave/unity/build/Modules/TerrainEditor/TerrainInspector.cs:1784)
    8. UnityEditor.UIElements.InspectorElement+<CreateIMGUIInspectorFromEditor>c__AnonStorey1.<>m__0 () (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorElement.cs:445)
    9. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    10.  
    This is on 2019.1.0f2. Should be easy to reproduce by creating a TerrainLayer, painting with it, then updating and saving it via code, then opening the painting UI section again.
     
  4. seelanv

    seelanv

    Joined:
    Jun 2, 2017
    Posts:
    3
  5. ivantriumphov

    ivantriumphov

    Joined:
    Jun 24, 2019
    Posts:
    5
    Resources are predefined.
    [code = CSharp]
    public void Texturing (Terrain [] terrains, string url_pref = "")
    {
    foreach (var t in terrains) {
    Debug.log (t.name);
    t.terrainData.size = new Vector3 (2000, 168, 2000);
    // Texture2D tex = Resources.Load ("");
    List <TerrainLayer> tl = new List <TerrainLayer> ();
    DirectoryInfo dir = new DirectoryInfo (Application.dataPath + "/ Resources / Layer / SimpleGrass");
    foreach (var item в dir.GetFiles ("*. terrainlayer"))
    tl.Add (Resources.Load <TerrainLayer> ("Слой / SimpleGrass /" + item.Name.Split () [0]) '');
    t.terrainData.terrainLayers = tl.ToArray ();
    }
    }
    [/ Код]
     
    Last edited: Nov 5, 2019
    MichaelEGA likes this.
  6. MichaelEGA

    MichaelEGA

    Joined:
    Oct 11, 2019
    Posts:
    40
    Old thread, but been looking for this for a while. Thanks ivantriumphov it works.

    My version:
    Code (CSharp):
    1. List<string> textureLayers = new List<string>();
    2.  
    3. if (floraAndTextureType == "Forest")
    4. {
    5.             textureLayers.Add("RiverMud");
    6.             textureLayers.Add("MountainRock1");
    7.             textureLayers.Add("ForestGround1");
    8.             textureLayers.Add("ForestGround2");
    9. }
    10.  
    11. if (textureLayers.Count > 0)
    12. {
    13.             List<TerrainLayer> tl = new List<TerrainLayer>();
    14.  
    15.             for (int i = 0; i < textureLayers.Count; i++)
    16.             {
    17.                 tl.Add(Resources.Load<TerrainLayer>("Terrain/" + textureLayers[i]));
    18.             }
    19.  
    20.             terrainData.terrainLayers = tl.ToArray();
    21. }