Search Unity

Export Terrain Heightmap 2 PNG

Discussion in 'Made With Unity' started by pete, Jul 21, 2010.

  1. pete

    pete

    Joined:
    Jul 21, 2005
    Posts:
    1,647
    I had to find a way to edit a terrain heightmap in Gimp on a Mac which doesn't like 16 bit as far as I can tell. Searching the forums turned up not so much. So I wrote this script to use in conjunction with Eric5h5's apply heightmap script on the wiki.

    Works fine except for a couple things:
    - I didn't try it on a scene with more than one terrain. The selection stuff was copied out of another script (the raw one?). Doesn't look like there's a check for multiple terrains but it didn't matter for my project. So I'm not sure how it will behave if you have several and don't select one.
    - The biggest problem is it outputs an 8 bit image. The result is 256 levels of gray. When applying the exported PNG to a new terrain you'll get the general shape but banding causes it to stair step. Using the smooth brush fixes it but just isn't good enough for some(most?) projects. Scaling it down to 256 x 256 helps some but still not enough.

    I went another route in the end. So, my problem's solved. Don't think it's worth the wiki at this point but feel free to put it up there if you want. I'm not going to mess with it anymore. Anyone else who wants to can have at it.

    Save it as HeightmapExportPNG.js and put it in an Assets/Editor folder in your project. Export Height Map as PNG should show up under the Terrain menu. Selecting it will generate a PNG and save it to the Assets folder as DuplicateHeightmap.png. See Eric's script on the wiki to apply it to a new terrain:
    http://www.unifycommunity.com/wiki/index.php?title=HeightmapFromTexture

    Code (csharp):
    1. import UnityEngine;
    2. import UnityEditor;
    3. import System.Collections;
    4. import System.IO;
    5.  
    6. class HeightmapExportPNG extends EditorWindow
    7. {
    8.     static var terraindata : TerrainData;
    9.    
    10.     @MenuItem ("Terrain/Export Height Map as PNG")
    11.     static function Init () {
    12.         terraindata = null;
    13.         var terrain : Terrain = null;
    14.        
    15.         if ( Selection.activeGameObject )
    16.             terrain = Selection.activeGameObject.GetComponent( Terrain );
    17.  
    18.         if (!terrain) {
    19.             terrain = Terrain.activeTerrain;
    20.         }
    21.         if (terrain) {
    22.             terraindata = terrain.terrainData;
    23.         }
    24.         if (terraindata == null) {
    25.             EditorUtility.DisplayDialog("No terrain selected", "Please select a terrain.", "Cancel");
    26.             return;
    27.         }
    28.        
    29.         //// get the terrain heights into an array and apply them to a texture2D
    30.         var myBytes : byte[];
    31.         var myIndex : int = 0;
    32.         var rawHeights = new Array(0.0,0.0);
    33.         var duplicateHeightMap = new Texture2D(terraindata.heightmapWidth, terraindata.heightmapHeight, TextureFormat.ARGB32, false);
    34.         rawHeights = terraindata.GetHeights(0, 0, terraindata.heightmapWidth, terraindata.heightmapHeight);
    35.  
    36.         /// run through the array row by row
    37.         for (y=0; y < duplicateHeightMap.height; ++y)
    38.         {
    39.             for (x=0; x < duplicateHeightMap.width; ++x)
    40.             {
    41.                 /// for wach pixel set RGB to the same so it's gray
    42.                 var color = Vector4(rawHeights[myIndex], rawHeights[myIndex], rawHeights[myIndex], 1.0);
    43.                 duplicateHeightMap.SetPixel (x, y, color);
    44.                 myIndex++;
    45.             }
    46.         }
    47.         // Apply all SetPixel calls
    48.         duplicateHeightMap.Apply();
    49.  
    50.         /// make it a PNG and save it to the Assets folder
    51.         myBytes = duplicateHeightMap.EncodeToPNG();
    52.         var filename : String = "DupeHeightMap.png";
    53.         File.WriteAllBytes(Application.dataPath + "/" + filename, myBytes);
    54.         EditorUtility.DisplayDialog("Heightmap Duplicated", "Saved as PNG in Assets/ as: " + filename, "");
    55.     }
    56. }
     
    MikeHazeJr likes this.
  2. CommunityUS

    CommunityUS

    Joined:
    Sep 2, 2011
    Posts:
    240
    Works great in 4.2

    Thanks for sharing. I was going RAR with RAWs
     
  3. nickfourtimes

    nickfourtimes

    Joined:
    Oct 13, 2010
    Posts:
    219
    Works great in 4.3.3 as well. Super helpful, A++++++ would shop here again.
     
  4. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    PNG files actually can support 16-bit per channel, but Unity's PNG saving routines are only 8-bit.
     
  5. Dragovv

    Dragovv

    Joined:
    Apr 1, 2017
    Posts:
    1
    Hi, i am using Unity 2017.1.0b1 (latest for may 2017), and i cant find the button to export. Is this code outdated (Terrain menu was removed, isn't it?) and can i update it myself?
     
  6. LevonRavel

    LevonRavel

    Joined:
    Feb 26, 2014
    Posts:
    179
    For anyone looking for this I made it so you can choose how you want to save the image.. You must type yourfilename.yourextension jpg/png file saves out as 512x512. Same as before only does one terrain in the scene also you can find the extension in the editor under Window/Terrain to image.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.IO;
    4.  
    5. class HeightmapExportPNG : EditorWindow
    6. {
    7.     static TerrainData terraindata;
    8.  
    9.  
    10.     [MenuItem("Window/Terrain to image")]
    11.     static void Init()
    12.     {
    13.         terraindata = null;
    14.         Terrain terrain = null;
    15.  
    16.         if (Selection.activeGameObject)
    17.             terrain = Selection.activeGameObject.GetComponent<Terrain>();
    18.  
    19.         if (!terrain)
    20.         {
    21.             terrain = Terrain.activeTerrain;
    22.         }
    23.         if (terrain)
    24.         {
    25.             terraindata = terrain.terrainData;
    26.         }
    27.         if (terraindata == null)
    28.         {
    29.             EditorUtility.DisplayDialog("No terrain selected", "Please select a terrain.", "Cancel");
    30.             return;
    31.         }
    32.  
    33.         //// get the terrain heights into an array and apply them to a texture2D
    34.         byte[] myBytes;
    35.         int myIndex = 0;
    36.         Texture2D duplicateHeightMap = new Texture2D(terraindata.heightmapWidth, terraindata.heightmapHeight, TextureFormat.ARGB32, false);
    37.         float[,] rawHeights = terraindata.GetHeights(0, 0, terraindata.heightmapWidth, terraindata.heightmapHeight);
    38.  
    39.         /// run through the array row by row
    40.         for (int y = 0; y < duplicateHeightMap.height; y++)
    41.         {
    42.             for (int x = 0; x < duplicateHeightMap.width; x++)
    43.             {
    44.                 /// for wach pixel set RGB to the same so it's gray
    45.                 var color = new Vector4(rawHeights[x,y], rawHeights[x,y], rawHeights[x,y], 1);
    46.                 duplicateHeightMap.SetPixel(x, y, color);
    47.                 myIndex++;
    48.             }
    49.         }
    50.         // Apply all SetPixel calls
    51.         duplicateHeightMap.Apply();
    52.  
    53.         string path = EditorUtility.SaveFilePanel(
    54.                 "Save texture as",
    55.                 "",
    56.                 "Rename Me",
    57.                 "png, jpg");
    58.  
    59.         var extension = Path.GetExtension(path);
    60.         byte[] pngData = null;// duplicateHeightMap.EncodeToPNG();
    61.  
    62.         switch(extension)
    63.         {
    64.             case ".jpg":
    65.                 pngData = duplicateHeightMap.EncodeToJPG();
    66.                 break;
    67.  
    68.             case ".png":
    69.                 pngData = duplicateHeightMap.EncodeToPNG();
    70.                 break;
    71.         }
    72.  
    73.         if (pngData != null)
    74.         {
    75.             File.WriteAllBytes(path, pngData);
    76.             EditorUtility.DisplayDialog("Heightmap Duplicated", "Saved as" + extension + " in " + path, "Awesome");
    77.         }else
    78.         {
    79.             EditorUtility.DisplayDialog("Failed to duplicate height map", "eh something happen hu? lol", "Check Script");
    80.         }
    81.  
    82.         AssetDatabase.Refresh();
    83.     }
    84. }
    85.  
    -Levon