Tilting the terrain

I do know that rotating the terrain is impossible.
Hi, I’m trying to make a terrain that on one side it has a height of 400, and on the other it has a height of 300, so basically I’m trying to make a slow incline. The only way that I know how to do this is by using unity’s terrain height painting tool, but it comes out looking very rough, where as I want it to be flat. There has to be a better way of doing this, something that I am overlooking, but after searching I found nothing. Any suggestions?

Generate it in some terrain modelling app. Ot if you want just simple decline, make gradient in photoshop and eport as raw.

Setting the terrain heights in code and using SetHeights() would probably be the easiest and most flexible.

–Eric

I wrote a script a while back to do just this. It’s not pretty, but it worked great:

using UnityEditor;
using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

public class TerrainSlopeTool : EditorWindow {
	
	static float _startingX = 0f;
	static float _startingY = 0f;
	static float _endingX = 1f;
	static float _endingY = 0f;
	static float _scale = 0f;
	
	[MenuItem("Meriwether/Show Terrain Slope Tool")]
	static void ShowWindow() {
		EditorWindow.GetWindow<TerrainSlopeTool> ();
	}
	
	public void OnGUI(){
		if (GUILayout.Button("Apply Slope")){
			SlopeTerrain();
		}
		
		if (GUILayout.Button("Lower Terrain")){
			LowerTerrain();
		}
		
		if (GUILayout.Button("Scale Terrain")){
			ScaleTerrain();
		}
	}
	
	static void SlopeTerrain(){
		GameObject source = Selection.activeGameObject;
		
		if (source == null || source.GetComponent(typeof(Terrain)) == null){
			Debug.LogError("Cannot apply slope, no valid terrain selected!");
			return;
		}
		
		Terrain sourceTerrain = (Terrain)source.GetComponent(typeof(Terrain));
		TerrainData tdata = sourceTerrain.terrainData;
		
		float[,] sourceHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		float[,] newHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		
		bool clippedBelow = false;
		bool clippedAbove = false;
		
		for (int i = 0; i < tdata.heightmapWidth; i++){
			for (int j = 0; j < tdata.heightmapHeight; j++){
				float floati = i;
				float floatj = j;
				float widthp = floati / tdata.heightmapWidth;
				float heightp = floatj / tdata.heightmapWidth;
				
				newHeights[i,j] = sourceHeights[i,j] + Mathf.Lerp(_startingX, _endingX, widthp) + Mathf.Lerp(_startingY, _endingY, heightp);
				
				if (newHeights[i,j] < 0){
					clippedBelow = true;
				} else if (newHeights[i,j] > 1) {
					clippedAbove = true;
				}
			}
		}
		
		if (clippedBelow){
			Debug.LogWarning("Warning: Clipped below 0!");
		}
		if (clippedAbove){
			Debug.LogWarning("Warning: Clipped above 1!");
		}
		
		tdata.SetHeights(0, 0, newHeights);
		
		tdata.RefreshPrototypes();
		sourceTerrain.Flush();
	}
	
	static void LowerTerrain(){
		GameObject source = Selection.activeGameObject;
		
		if (source == null || source.GetComponent(typeof(Terrain)) == null){
			Debug.LogError("Cannot lower terrain, no valid terrain selected!");
			return;
		}
		
		Terrain sourceTerrain = (Terrain)source.GetComponent(typeof(Terrain));
		TerrainData tdata = sourceTerrain.terrainData;
		
		float[,] sourceHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		float[,] newHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		
		float lowestValue = 1;
		
		for (int i = 0; i < tdata.heightmapWidth; i++){
			for (int j = 0; j < tdata.heightmapHeight; j++){
				if (sourceHeights[i,j] < lowestValue){
					lowestValue = sourceHeights[i,j];
				}
			}
		}
		
		for (int i = 0; i < tdata.heightmapWidth; i++){
			for (int j = 0; j < tdata.heightmapHeight; j++){
				if (sourceHeights[i,j] < lowestValue){
					lowestValue = sourceHeights[i,j];
				}
				newHeights[i,j] = sourceHeights[i,j] - lowestValue;
			}
		}
		
		tdata.SetHeights(0, 0, newHeights);
		
		tdata.RefreshPrototypes();
		sourceTerrain.Flush();
	}
	
	static void ScaleTerrain(){
		GameObject source = Selection.activeGameObject;
		
		if (source == null || source.GetComponent(typeof(Terrain)) == null){
			Debug.LogError("Cannot lower terrain, no valid terrain selected!");
			return;
		}
		
		Terrain sourceTerrain = (Terrain)source.GetComponent(typeof(Terrain));
		TerrainData tdata = sourceTerrain.terrainData;
		
		float[,] sourceHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		float[,] newHeights = tdata.GetHeights(0,0,tdata.heightmapWidth,tdata.heightmapHeight);
		
		for (int i = 0; i < tdata.heightmapWidth; i++){
			for (int j = 0; j < tdata.heightmapHeight; j++){

				newHeights[i,j] = sourceHeights[i,j] * _scale;
			}
		}
		
		tdata.SetHeights(0, 0, newHeights);
		
		tdata.RefreshPrototypes();
		sourceTerrain.Flush();
	}
}

It would take all of a minute to make those variables editable on the window, no clue why I didn’t bother doing that.

Thank you all so much for the help, but I ended up using KyleStaves’ code, and since I have very little knowledge on c# scripting, how would I go about making those variables editable?