- Home /
Can I universally raise my terrain to allow greater sculpting depth while preserving details?
I created a terrain and sculpted mountains and haills and such, and was preparing to create a deep river with a dam object sunk down into it when I realized that I could only make the river so deep before it reached "0"...
Is there any way to allow Terrain to become deeper than "0" (typing negative numbers fails to be recognized, and defaults back to "0")? If not, is there any way to universally raise the altitude of the entire Terrain all at once while preserving the already-sculpted details?
Help would be really appreciated, to avoid having to start the terrain over again...
Note - if you're just starting a NEW terrain, it begins uselessly at all-zero, so you cannot do "down"
To change that (again this is only when starting fresh...)
Answer by Jadugara · May 02, 2012 at 12:13 AM
I'm coming back to answer my own question because I was finally able to fix the problem by exporting the Terrain's height-map from Unity as a 16-bit Mac file (even though I work on a PC), and then open it up in Photoshop as an 8-bit file (with neither PC or Mac checked)... This opens a RAW file with an Alpha Channel. Leave the Alpha Channel alone, but feel free to edit the single background layer as you see fit.
In my case, since I wanted to raise the entire terrain equally higher while leaving my features intact, I simply added a fill layer of pure white, then decreased the opacity to make the entire thing slightly lighter, then collapsed the layers and imported it back into Unity... It worked perfectly! And all I had to do was grab everything except the terrain and move it back up to where it needed to be to intersect the terrain before it was raised...
Hope this helps other folks out there...
Answer by AlucardJay · Feb 17, 2014 at 06:30 AM
Edit (2016): new script with undo functionality, and editor script for inspector buttons.
Disclaimer : use at your own risk. Back up your terrain before using. I won't be held responsible for lost terrain ! (though this version does have undo which should hopefully cover any accidents)
STEP ONE : save your terrain! Export it by right-clicking on it in the Project Window, then select Export Package...
How to use this :
This script can be run in the Editor without playing. Attach the script to the terrain or an empty gameobject.
Assign the terrain to be modified in the inspector.
Set the amount in units to raise or lower the terrain by. If the height of the tallest peak is greater than the max height of the terrain, these peaks will become flattened. Same if the height is lower than the min height.
Click the 'Raise/Lower Terrain' button.
If there are previous heights stored, an Undo button will show.
please note: delete the script and add a new script for editing a different terrain. I havn't included anything for checking if a different terrain is assigned in the inspector, so please delete this script and add a new script when editing a different terrain, otherwise the undo will write the previous terrains stored undo heights, and that would be very bad.
TerrainRaiseLowerHeightmap.cs :
//--------------------------------//
// TerrainRaiseLowerHeightmap.cs //
// Written by Jay Kay //
// 2016/4/8 //
//--------------------------------//
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TerrainRaiseLowerHeightmap : MonoBehaviour
{
public Terrain terrain;
public float changeHeightInUnits = 0f;
[HideInInspector] public List< float[,] > undoHeights = new List< float[,] >();
// ------------------------------------------------------- Modify Heightmap Functions
public void ModifyTerrainHeightmap()
{
// check if terrain is assigned in inspector
if ( !terrain )
{
Debug.LogError( gameObject.name + " has no terrain assigned in the inspector" );
return;
}
// get reference variables
TerrainData terrainData = terrain.terrainData;
int heightmapWidth = terrainData.heightmapWidth;
int heightmapHeight = terrainData.heightmapHeight;
// copy current heights
float[,] currentHeights = terrainData.GetHeights( 0, 0, heightmapWidth, heightmapHeight );
undoHeights.Add( currentHeights );
// make new height array
float[,] newHeights = new float[ heightmapWidth, heightmapHeight ];
float terrainHeight = terrainData.size.y;
for ( int y = 0; y < heightmapWidth; y++ )
{
for ( int x = 0; x < heightmapHeight; x++ )
{
newHeights[ y, x ] = Mathf.Clamp01( currentHeights[ y, x ] + ( changeHeightInUnits / terrainHeight ) );
}
}
// apply to terrain
terrainData.SetHeights( 0, 0, newHeights );
Debug.Log( "Raise/Lower Heights completed" );
}
// ------------------------------------------------------- Undo Functions
public void UndoModifyTerrainHeightmap()
{
// check if terrain is assigned in inspector
if ( !terrain )
{
Debug.LogError( gameObject.name + " has no terrain assigned in the inspector" );
return;
}
// get last heights
float[,] newHeights = undoHeights[ undoHeights.Count - 1 ];
// apply to terrain
terrain.terrainData.SetHeights( 0, 0, newHeights );
// remove from list
undoHeights.RemoveAt( undoHeights.Count - 1 );
Debug.Log( "Undo Heights completed" );
}
}
TerrainRaiseLowerHeightmapEditor.cs - IMPORTANT- place this script in an Editor folder :
//--------------------------------//
// TerrainRaiseLowerHeightmap.cs //
// Written by Jay Kay //
// 2016/4/8 //
//--------------------------------//
using UnityEditor;
using UnityEngine;
[ CustomEditor( typeof( TerrainRaiseLowerHeightmap ) ) ]
public class TerrainRaiseLowerHeightmapEditor : Editor
{
private GameObject obj;
private TerrainRaiseLowerHeightmap objScript;
void OnEnable()
{
obj = Selection.activeGameObject;
objScript = obj.GetComponent< TerrainRaiseLowerHeightmap >();
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
// spacing between buttons
EditorGUILayout.Space();
// check if there is a terrain
if ( objScript.terrain == null )
{
EditorGUILayout.BeginHorizontal();
GUILayout.Label( "Assign a terrain to modify", GUILayout.MinWidth( 80 ), GUILayout.MaxWidth( 350 ) );
EditorGUILayout.EndHorizontal();
return;
}
// raise/lower button
EditorGUILayout.BeginHorizontal();
if ( GUILayout.Button( "Raise/Lower Terrain", GUILayout.MinWidth( 80 ), GUILayout.MaxWidth( 350 ) ) )
{
objScript.ModifyTerrainHeightmap();
}
EditorGUILayout.EndHorizontal();
// check if there is an undo array
if ( objScript.undoHeights.Count > 0 )
{
// spacing between buttons
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
if ( GUILayout.Button( "UNDO", GUILayout.MinWidth( 80 ), GUILayout.MaxWidth( 350 ) ) )
{
objScript.UndoModifyTerrainHeightmap();
}
EditorGUILayout.EndHorizontal();
}
}
}
This script is part of an upcoming Terrain Tools package I'm currently working on =]
Original Answer (2014):
While the OP has done an excellent job of answering their own question, I would like to provide another answer using scripting.
Disclaimer : use at your own risk. Back up your terrain before using. I won't be held responsible for lost terrain !
STEP ONE : save your terrain! Export it by right-clicking on it in the Project Window, then select Export Package...
How to use this :
This script can be run in the Editor without playing. Attach the script to the terrain.
Right-click on the script component in the Inspector, then a drop-down selection box appears. Example :
There should be an option Raise Terrain Heightmap, click on this. Now the script will run and show a console message when complete.
The amount the height is raised by uses world-space values :
public var raiseHeightInUnits : float = 20.0;
so this would raise the terrain by 20 units.
Warning : if the height of the tallest peak is greater than the max height of the terrain, these peaks will become flattened. That's why it's important to backup the terrain first, in-case of any mistakes. I could write in some code to make sure this doesn't happen, but with careful implementation and gradual increments to the raiseHeightInUnits, there should be no problems =]
#pragma strict
#if UNITY_EDITOR
@ContextMenu( "Raise Terrain Heightmap" )
function RaiseTerrainHeightmap()
{
RaiseHeights();
}
#endif
public var myTerrain : Terrain;
private var terrainData : TerrainData;
private var heightmapWidth : int;
private var heightmapHeight : int;
private var heightmapData : float[,];
public var raiseHeightInUnits : float = 20.0;
function RaiseHeights()
{
// - GetTerrainData -
if ( !myTerrain )
{
//myTerrain = Terrain.activeTerrain;
Debug.LogError( gameObject.name + " has no terrain assigned in the inspector" );
}
terrainData = myTerrain.terrainData;
heightmapWidth = myTerrain.terrainData.heightmapWidth;
heightmapHeight = myTerrain.terrainData.heightmapHeight;
// --
// store old heightmap data
heightmapData = terrainData.GetHeights( 0, 0, heightmapWidth, heightmapHeight );
var terrainHeight : float = terrainData.size.y;
// --
var y : int = 0;
var x : int = 0;
// raise heights
for ( y = 0; y < heightmapHeight; y ++ )
{
for ( x = 0; x < heightmapWidth; x ++ )
{
var newHeight : float = Mathf.Clamp01( heightmapData[ y, x ] + ( raiseHeightInUnits / terrainHeight ) );
heightmapData[ y, x ] = newHeight;
}
}
terrainData.SetHeights( 0, 0, heightmapData );
Debug.Log( "RaiseHeights() completed" );
}
The script works like a charm. $$anonymous$$y sincere thanks.
Script worked great. However, if terrain isn't assigned to myTerrain, the automatic terrain selection by Terrain.activeTerrain failed on me. It picked the wrong terrain(it modified an unselected terrain, one I didn't backup). I thought it could basically select the terrain that script is attached to. $$anonymous$$ake sure to add reference to your terrain yourself.
And don't create this script in Editor folder.
Sorry to hear that. That's why there's the warning stating backup your terrain first though. I will edit the script to post a debug ins$$anonymous$$d of using activeTerrain.
It wasn't a problem for me as I had a day old backup on hard drive. :) Before using the tool I backed up just the terrain I was going to modify, but it modified another terrain. That's a usual procedure and people might lose terrain info if it uses activeterrain, which unfortunately might pick wrong terrain sometimes.
Thank you :)
This is an amazing answer... This needs many many more upvotes - thank you so much!
I was searching for THE script. You're my saver. Thanks !
Answer by JacobDSiler · Oct 15, 2019 at 07:08 AM
Here is a working version with unity 2019 and C#:
First you need the C# script, applied to any game object you wish to use to manage your terrain heights:
using UnityEngine;
using UnityEditor;
public class RaiseTerrainHeightmap : MonoBehaviour
{
public Terrain myTerrain;
private TerrainData terrainData;
private int heightmapWidth;
private int heightmapHeight;
private float[,] heightmapData = new float[0, 0];
public float raiseHeightInUnits = 20.0f;
public void RaiseHeights()
{
// - GetTerrainData -
if (!myTerrain)
{
//myTerrain = Terrain.activeTerrain;
Debug.LogError(gameObject.name + " has no terrain assigned in the inspector");
}
terrainData = myTerrain.terrainData;
heightmapWidth = myTerrain.terrainData.heightmapWidth;
heightmapHeight = myTerrain.terrainData.heightmapHeight;
// --
// store old heightmap data
heightmapData = terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight);
float terrainHeight = terrainData.size.y;
// --
var y = 0;
var x = 0;
// raise heights
for (y = 0; y < heightmapHeight; y++)
{
for (x = 0; x < heightmapWidth; x++)
{
float newHeight = Mathf.Clamp01(heightmapData[y, x] + (raiseHeightInUnits / terrainHeight));
heightmapData[y, x] = newHeight;
}
}
terrainData.SetHeights(0, 0, heightmapData);
Debug.Log("RaiseHeights() completed");
}
}
Then you need (Or I would prefer to use) an editor script (Which you save in your project directory under an Editor Folder.):
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(RaiseTerrainHeightmap))]
public class TerrainCustomEditor : Editor
{
// public RaiseHeights raiseHeights;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
RaiseTerrainHeightmap RaiseTerrain = (RaiseTerrainHeightmap)target;
if (GUILayout.Button("Raise Terrain Heightmap"))
{ RaiseTerrain.RaiseHeights(); }
}
}
I hope it helps someone out. Credit to past users in this thread for writing the UnityScript.
While the script does work for raising the terrain, it does not preserve the details of existing sculpted terrain sadly.
Excellent! It works perfectly provided that you make sure that none of your terrain goes higher than 512 units after the conversion.
The script should work as long as details (peaks and troughs) won't go higher or lower than the maximum and $$anonymous$$imum height from the terrain's settings.
If they do, they will be flattene always back up your terrain(s) before using it.
Answer by Doctor · May 01, 2012 at 01:16 PM
You could "Terrain -> Flatten HeightMap" or "Terrain ->Set Resolution". The former would require starting over, the latter would mean changing a lot/most of the features to get them to the height you want.
Other than these, I don't know how you would do that, but I hope you find what you need if my help doesn't work.
Thanks Doctor...
It looks like your suggestion about using "Terrain ->Set Resolution" may be my best quick-fix for now... Like you said, it requires re-sculping the features (since it stretches every terrain feature upward like taffy), but at least they are still there as a reference....
Hopefully there will eventually be some built-in tools that allow you to "select-all" terrain and increase its universal height equally (thus preserving the overall scale of its features) without stretching it from lowest to highest...
Oh! Hey Doctor! I was actually able to discover a way to do exactly what I wanted to do! I figured I'd share the answer with you and anyone else who might need to do this...
I was able to export the heightmap from Unity as a .RAW, and add a partial fill of white in Photoshop, then import it back into Unity, and it worked perfectly!
Check out my full answer above...(as soon as the moderators review and accept it)...
Your answer
![](https://koobas.hobune.stream/wayback/20220613070942im_/https://answers.unity.com/themes/thub/images/avi.jpg)