Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
11
Question by pirulo · Feb 04, 2010 at 07:12 PM · terrain

Modifying terrain height under a gameobject at runtime

I've checked this and the Terrain and TerrainData reference.

But I tried and cannot figure out how to modify the terrain by scripting at runtime. What I actually want is to be able to raise the terrain under a certain gameobject.

Any help or examples will be appreaciated. Thanks

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

7 Replies

· Add your reply
  • Sort: 
avatar image
16
Best Answer

Answer by pirulo · Feb 05, 2010 at 03:42 AM

thank for yor answer Duck, I finally figured it out. I paste the code I used so that anyone who has the same problem can check it out. It is not that good but I hope it helps.

Unluckily if you modify the terrain at runtime it doesnt reset to the original heights it had before you played the scene.

Also, I havent thought of an algorithm to raise the terrain in a smooth way (this is plain blocky), but it would be good to raise it smoothly as if a mountain was raising.

 Terrain terr; // terrain to modify
 int hmWidth; // heightmap width
 int hmHeight; // heightmap height
 
 int posXInTerrain; // position of the game object in terrain width (x axis)
 int posYInTerrain; // position of the game object in terrain height (z axis)
 
 int size = 50; // the diameter of terrain portion that will raise under the game object
 float desiredHeight = 0; // the height we want that portion of terrain to be
 
 void Start () {
 
     terr = Terrain.activeTerrain;
     hmWidth = terr.terrainData.heightmapWidth;
     hmHeight = terr.terrainData.heightmapHeight;
 
 }
 
 void Update () {
 
     // get the normalized position of this game object relative to the terrain
     Vector3 tempCoord = (transform.position - terr.gameObject.transform.position);
     Vector3 coord;
     coord.x = tempCoord.x / terr.terrainData.size.x;
     coord.y = tempCoord.y / terr.terrainData.size.y;
     coord.z = tempCoord.z / terr.terrainData.size.z;
 
     // get the position of the terrain heightmap where this game object is
     posXInTerrain = (int) (coord.x * hmWidth); 
     posYInTerrain = (int) (coord.z * hmHeight);
 
     // we set an offset so that all the raising terrain is under this game object
     int offset = size / 2;
 
     // get the heights of the terrain under this game object
     float[,] heights = terr.terrainData.GetHeights(posXInTerrain-offset,posYInTerrain-offset,size,size);
 
     // we set each sample of the terrain in the size to the desired height
     for (int i=0; i < size; i++)
         for (int j=0; j < size; j++)
             heights[i,j] = desiredHeight;
 
     // go raising the terrain slowly
     desiredHeight += Time.deltaTime;
 
     // set the new height
     terr.terrainData.SetHeights(posXInTerrain-offset,posYInTerrain-offset,heights);
 
 }

             
Comment
Add comment · Show 9 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Jean-Fabre · Oct 22, 2010 at 01:02 PM 0
Share

What is the code format? if I save is as javascript, cSharp or boo I get lots of compile errors.

avatar image Zarenityx · Jan 07, 2013 at 08:23 PM 0
Share

It looks like C#, but it appears to be missing the Unity engine and System collections namespaces and it does not derive from $$anonymous$$onoBehavior. You probably need to add the 'using' and 'extends' parts at the beginning like any other C# code. If you are getting errors, they may be because the compiler doesn't know what those functions, variables, and class variables mean because it doesn't know where to find that information. Like trying to define an unknown word without a dictionary. It just doesn't work.

avatar image npruehs · Feb 07, 2015 at 02:42 PM 1
Share

Works like a charm. Good work.

I've added a small script for resetting the terrain after the game ends:

 using UnityEngine;
 
     public class ResetTerrainOnDestroy : $$anonymous$$onoBehaviour
     {
         #region Fields
 
         public Terrain Terrain;
 
         private float[,] originalHeights;
 
         #endregion
 
         #region $$anonymous$$ethods
 
         private void OnDestroy()
         {
             this.Terrain.terrainData.SetHeights(0, 0, this.originalHeights);
         }
 
         private void Start()
         {
             this.originalHeights = this.Terrain.terrainData.GetHeights(
                 0, 0, this.Terrain.terrainData.heightmapWidth, this.Terrain.terrainData.heightmapHeight);
         }
 
         #endregion
     }

avatar image raivoriiel npruehs · Apr 09, 2021 at 03:39 PM 0
Share

6 years later I still found this useful, thanks! I changed it a bit - heightmapwidth is now deprecated and swapped from OnDestroy to OnApplicationQuit, since (for me at least) the ingame terrain GameObject also gets destroyed and OnDestroy order is not guaranteed and thus terrain resetting was not guaranteed to work. OnApplicationQuit is called before OnDestroy tho so in any case terrain reset is guaranteed.

Full working example:

     using System.Collections;
     using System.Collections.Generic;
     using UnityEngine;
     
     public class MapReset : MonoBehaviour
     {
         public Terrain terrain;
         private float[,] originalHeights;
     
         private void OnApplicationQuit() {
             this.terrain.terrainData.SetHeights(0, 0, this.originalHeights);   
         }
     
         private void Start()
         {
             this.originalHeights = this.terrain.terrainData.GetHeights(
                 0, 0, this.terrain.terrainData.heightmapResolution, this.terrain.terrainData.heightmapResolution);
         }
     }
 
avatar image TubooBokBok · Feb 14, 2015 at 01:17 AM 0
Share

Ok so I know I am abit late to this post, but I am getting a few error with Pirulo's script aswell. I am receiving errors for the lines:

         for (int i=0; i&lt;size; i++)
             for (int j=0; j&lt;size; j++)

I am receiving the following errors in Unity.:

error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement

and

error CS1525: Unexpected symbol ;', expecting )', or `,'

Is anyone able to help me out and explain what is causing these errors?

Thanks a lot!

avatar image Zarenityx · Feb 14, 2015 at 11:07 AM 0
Share

@TubooBokBok I think that there was a small problem when the code was copied. The problematic lines:

          for (int i=0; i&lt;size; i++)
              for (int j=0; j&lt;size; j++)
  

should be this:

          for (int i=0; i<size; i++)
              for (int j=0; j<size; j++)

If there are still problems, try changing < to ,=, etc. get turned into <, >, &eq, etc. I hope this solves your error.

Show more comments
avatar image
9
Best Answer

Answer by duck · Feb 04, 2010 at 07:53 PM

You need to use GetHeights and SetHeights. Specifically:

  • convert your GameObject's position to normalized terrain coordinates (i.e. in the range 0-1)
  • use terrainData.GetHeights(x,y,width,height) to get an array containing the current height at that location (in your case, width and height would probably be 1,1)
  • Modify the values in the array, to increase the height
  • use terrainData.SetHeights(x,y,yourHeightArray) to write the new heights back to that location on the terrain.
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

Answer by JOKaija · Feb 10, 2015 at 08:33 PM

I made a little modification for code. Took couple of hours, so there maid be a fine adjusting....

This is, what I'm using, when settling buildings over terrain, which is not flat.

Before inserting a building to the terrain, first look terrain height with raycast at wanted position.

Then call the routine with raycasted height + xxx (extra height). You can set width & height & terrain texture with size also.

Routine can fine adjust raised terrain edges within given distance from newly levelled area.

If you want to test this piece of fixed code, just create a new scene. Add terrain to it. Add two textures to it. Add camera pointing to terrain. Add this script to your terrain inspector. Left mouse click raises and right lovers pointed terrain. Also, enable "Test with mouse" from scipt's inspector.

 using UnityEngine;
 using System.Collections;
 
 public class RaiseLowerTerrain : MonoBehaviour
 {
     public bool TestWithMouse = false;
     public Terrain myTerrain;
     public int SmoothArea;
     private int xResolution;
     private int zResolution;
     private float[,] heights;
     private float[,] heightMapBackup;
     protected const float DEPTH_METER_CONVERT=0.05f;
     protected const float TEXTURE_SIZE_MULTIPLIER = 1.25f;
     public int DeformationTextureNum = 1;
     protected int alphaMapWidth;
     protected int alphaMapHeight;
     protected int numOfAlphaLayers;
     private float[, ,] alphaMapBackup;
 
 
     void Start()
     {
         xResolution = myTerrain.terrainData.heightmapWidth;
         zResolution = myTerrain.terrainData.heightmapHeight;
         alphaMapWidth = myTerrain.terrainData.alphamapWidth;
         alphaMapHeight = myTerrain.terrainData.alphamapHeight;
         numOfAlphaLayers = myTerrain.terrainData.alphamapLayers;
 
         if (Debug.isDebugBuild)
         {
             heights = myTerrain.terrainData.GetHeights (0, 0, xResolution, zResolution);    
             heightMapBackup = myTerrain.terrainData.GetHeights(0, 0, xResolution, zResolution);
             alphaMapBackup = myTerrain.terrainData.GetAlphamaps(0, 0, alphaMapWidth, alphaMapHeight);   
         }
 
     }

     void OnApplicationQuit()
     {
         if (Debug.isDebugBuild)
         {
             myTerrain.terrainData.SetHeights(0, 0, heightMapBackup);
             myTerrain.terrainData.SetAlphamaps(0, 0, alphaMapBackup);
         }
     }
 
     
     void Update()
     {
         // This is just for testing with mouse!
         // Point mouse to the Terrain. Left mouse button
         // raises and right mouse button lowers terrain.
         if (TestWithMouse == true) 
         {
             if (Input.GetMouseButtonDown (0)) 
             {
                 RaycastHit hit;
                 Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
                 if (Physics.Raycast (ray, out hit)) 
                 {
                     // area middle point x and z, area width, area height, smoothing distance, area height adjust
                     raiselowerTerrainArea (hit.point, 10, 10, SmoothArea, 0.01f); 
                     // area middle point x and z, area size, texture ID from terrain textures
                     TextureDeformation (hit.point, 10 * 2f, DeformationTextureNum);
                 }
             }
             if (Input.GetMouseButtonDown (1)) 
             {
                 RaycastHit hit;
                 Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
                 if (Physics.Raycast (ray, out hit)) 
                 {
                     // area middle point x and z, area width, area height, smoothing distance, area height adjust
                     raiselowerTerrainArea (hit.point, 10, 10, SmoothArea, -0.01f);
                     // area middle point x and z, area size, texture ID from terrain textures
                     TextureDeformation (hit.point, 10 * 2f, 0);
                 }
             }
         }
     }
     
 
     private void raiselowerTerrainArea(Vector3 point, int lenx, int lenz, int smooth, float incdec)
     {
         int areax;
         int areaz;
         smooth += 1;
         float smoothing;
         int terX =(int)((point.x / myTerrain.terrainData.size.x) * xResolution);
         int terZ =(int)((point.z / myTerrain.terrainData.size.z) * zResolution);
         lenx += smooth;
         lenz += smooth;
         terX -= (lenx / 2);
         terZ -= (lenz / 2);
         if (terX < 0) terX = 0;
         if (terX > xResolution)    terX = xResolution;
         if (terZ < 0) terZ = 0;
         if (terZ > zResolution)    terZ = zResolution;
         float[,] heights = myTerrain.terrainData.GetHeights(terX, terZ, lenx, lenz);
         float y = heights[lenx/2,lenz/2];
         y += incdec;
         for (smoothing=1; smoothing < smooth+1; smoothing++) 
         {
             float multiplier = smoothing / smooth;
             for (areax = (int)(smoothing/2); areax < lenx-(smoothing/2); areax++) 
             {
                 for (areaz = (int)(smoothing/2); areaz < lenz-(smoothing/2); areaz++) 
                 {
                     if ((areax > -1) && (areaz > -1) && (areax < xResolution) && (areaz < zResolution)) 
                     {
                         heights [areax, areaz] = Mathf.Clamp((float)y*multiplier,0,1);
                     }
                 }
             }
         }
         myTerrain.terrainData.SetHeights (terX, terZ, heights);
     }
 
     private void raiselowerTerrainPoint(Vector3 point, float incdec)
     {
         int terX =(int)((point.x / myTerrain.terrainData.size.x) * xResolution);
         int terZ =(int)((point.z / myTerrain.terrainData.size.z) * zResolution);
         float y = heights[terX,terZ];
         y += incdec;
         float[,] height = new float[1,1];
         height[0,0] = Mathf.Clamp(y,0,1);
         heights[terX,terZ] = Mathf.Clamp(y,0,1);
         myTerrain.terrainData.SetHeights(terX, terZ, height);
     }
 
     protected void TextureDeformation(Vector3 pos, float craterSizeInMeters,int textureIDnum)
     {
         Vector3 alphaMapTerrainPos = GetRelativeTerrainPositionFromPos(pos, myTerrain, alphaMapWidth, alphaMapHeight);
         int alphaMapCraterWidth = (int)(craterSizeInMeters * (alphaMapWidth / myTerrain.terrainData.size.x));
         int alphaMapCraterLength = (int)(craterSizeInMeters * (alphaMapHeight / myTerrain.terrainData.size.z));
         int alphaMapStartPosX = (int)(alphaMapTerrainPos.x - (alphaMapCraterWidth / 2));
         int alphaMapStartPosZ = (int)(alphaMapTerrainPos.z - (alphaMapCraterLength/2));
         float[, ,] alphas = myTerrain.terrainData.GetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphaMapCraterWidth, alphaMapCraterLength);
         float circlePosX;
         float circlePosY;
         float distanceFromCenter;
         for (int i = 0; i < alphaMapCraterLength; i++) //width
         {
             for (int j = 0; j < alphaMapCraterWidth; j++) //height
             {
                 circlePosX = (j - (alphaMapCraterWidth / 2)) / (alphaMapWidth / myTerrain.terrainData.size.x);
                 circlePosY = (i - (alphaMapCraterLength / 2)) / (alphaMapHeight / myTerrain.terrainData.size.z);
                 distanceFromCenter = Mathf.Abs(Mathf.Sqrt(circlePosX * circlePosX + circlePosY * circlePosY));
                 if (distanceFromCenter < (craterSizeInMeters / 2.0f))
                 {
                     for (int layerCount = 0; layerCount < numOfAlphaLayers; layerCount++)
                     {
                         //could add blending here in the future
                         if (layerCount == textureIDnum)
                         {
                             alphas[i, j, layerCount] = 1;
                         }
                         else
                         {
                             alphas[i, j, layerCount] = 0;
                         }
                     }
                 }
             }
         } 
         myTerrain.terrainData.SetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphas);
     }
 
     protected Vector3 GetNormalizedPositionRelativeToTerrain(Vector3 pos, Terrain terrain)
     {
         Vector3 tempCoord = (pos - terrain.gameObject.transform.position);
         Vector3 coord;
         coord.x = tempCoord.x / myTerrain.terrainData.size.x;
         coord.y = tempCoord.y / myTerrain.terrainData.size.y;
         coord.z = tempCoord.z / myTerrain.terrainData.size.z;
         return coord;
     }
 
     protected Vector3 GetRelativeTerrainPositionFromPos(Vector3 pos,Terrain terrain, int mapWidth, int mapHeight)
     {
         Vector3 coord = GetNormalizedPositionRelativeToTerrain(pos, terrain);
         return new Vector3((coord.x * mapWidth), 0, (coord.z * mapHeight));
     }     
 }


rgds: Jari Kaija jari.kaija@live.com

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Victor_cross · Dec 16, 2015 at 09:00 AM 0
Share

Hi guys Script worked when attached to terrain object but when I pressed play and while I had a first person controller on I only got it to change from one terrain texture or the other. That is all that happened no height change I wanted to use the script to say attach it to a shovel so the player can change the terrain that way. Sorry for being a noob but as they say if you don't ask you will never know;)

avatar image MaximilianPs · Apr 04, 2016 at 08:17 AM 0
Share

The textures change at the right position (but with "test with mouse"), where the object is placed, but for some reason the terrain elevate on the bottom-right corner, I guess at coords 0,0 and it just elevate. While I would flat it at 0 (on Y) any advice ?

Sorry for necromancing this post. ^_^

avatar image jacobian · Sep 18, 2020 at 04:55 AM 0
Share

Had to do this for it to work for me. Seems code was expecting terrain to be placed at the origin.

 private void raiselowerTerrainArea(Vector3 point, int lenx, int lenz, int smooth, float incdec)
 {
     var pointLocalised = myTerrain.transform.InverseTransformPoint(point);

     int areax;
     int areaz;
     smooth += 1;
     float smoothing;
     int terX = (int)((pointLocalised.x / myTerrain.terrainData.size.x) * xResolution);
     int terZ = (int)((pointLocalised.z / myTerrain.terrainData.size.z) * zResolution);



avatar image
0

Answer by Simon Wittber · Feb 08, 2012 at 04:26 AM

Terrain Destruction does all this for you. It's cheap and simple, and fast.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image williampigmeu · Aug 03, 2012 at 03:48 PM 0
Share

We want a FREE alternative.

avatar image
0

Answer by Victor_cross · Jul 27, 2017 at 01:11 AM

That script above worked great. Could you tell me what part of the script I should be looking at to say deform the terrain less. And how would go attaching the script to a object like a shovel or a pick axe so the players could flatten at a slow rate. Script works great :) But It would be nice to punch a hole in terrain and stitch it internally to make a cave.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Menyus777 · Jul 28, 2017 at 08:01 PM 0
Share

To deform less,smooth the terrain, to do this in runtime apply gausian blurr on the heightmap, to apply terrain modification to a shovel use linecasting, then calculate the Terrain Hit into Heightmap coordinates and modify the terrain accordingly.

avatar image Victor_cross · Jul 30, 2017 at 02:14 AM 0
Share

I made the suggested changes and it worked well. Hey guys is there a way to modify the script in question to utilize the middle mouse scroll button and allow the player to punch a hole in the terrain and create internal mesh e.g to create a basic cave.

avatar image Menyus777 Victor_cross · Jul 30, 2017 at 09:00 AM 0
Share

Unity engine on its own does not support holes in its terrain system, there are plugins which solved this, i have no idea how tho, only one which is they they copy the terrain area and where the hole needs to be created they stitch it

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

17 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Make a simple tree 1 Answer

Tree Billboarding Settings 1 Answer

Messed up terrain texture on Android 5 device 0 Answers

need trigger + collide 2 Answers

How to increase Distribution, area spread of trees over the limit ? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges