Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
0
Question by JMurray · Jan 13, 2015 at 10:44 AM · instantiateterrainprefabcloneheightmap

Instatiating an object. Altering that new object causes prefab to be altered.

I am new to Unity3d and I'm playing around with a proof of concept project.

I'm currently stuck because I use a blank terrain prefab (easily instantiable) that I may want to include having its own scripts.

When my worldcreator object (blank object with script) starts instantiating the terrain pieces in a grid I'm noticing something very odd.

When I instantiate the terrain prefab, alter its height map and move on to instantiating the next piece, the next instantiating piece is carrying over heightmap terrain data from the previous instantiation. When I go to the unity3d editor and drag the prefab to the scene, it as well has the altered heightmap data from the last play.

I'm kind of lost as to why this would happen and I'm wondering if I'm not understanding what exactly instantiating really is or why the prefab in my project would be altered. Before today I thought prefabs were "read only" from a code perspective till they were instantiated and then altered based on in-game variables.

Here is my code.

 #pragma strict
 
 public var maxStrength: float = 1;
 public var numOfTerrainBySide: int = 4;
 public var terrainXsize = 500; //not used
 public var terrainZsize = 500;
 public var terrainYsize = 50;
 public var terrainHeightMapSize = 512;
 public var worldPiece: Terrain; //Prefab blank terrain linked from /prefabs/worldpiece
 
 private var wploc : Vector3;
 private var wprot : Quaternion;
 
 function Start()
 {
     //get starting position of blank object "WorldCreator"
     wploc = transform.position;
     wprot = transform.rotation;
     buildWorld();
 }
 
 function buildWorld()
 {
 
     //for each numOfTerrainBySide on X axis
     for(var z = 1; z-1 < numOfTerrainBySide; z ++)
     {
         //for each numOfTerrainBySide on Z axis per X
         for(var x = 1; x-1 < numOfTerrainBySide; x++)
         {
         var newloc = Vector3(terrainXsize * x - terrainXsize, wploc.y, terrainZsize * z - terrainZsize);
         buildWorldPiece(newloc,wprot,x,z);        
         }
 
     }
 }
 
 function buildWorldPiece(wploc,wprot,gridx,gridz)
 {
     //create terrain from prefab object
      var newterrain : Terrain = new Instantiate(worldPiece, wploc, wprot);
      
      //name object based on it's grid location
      newterrain.name = "wp_" + gridx + "_" + gridz;
      
      var xRes = newterrain.terrainData.heightmapWidth; 
      var yRes = newterrain.terrainData.heightmapHeight;
      var heights = newterrain.terrainData.GetHeights(0, 0, xRes, yRes);
 
     for (var x: int = 0; x < yRes; x++) 
     {
         for (var z: int = 0; z < xRes; z++) 
         {            
             //proof of concept to put border around edges of multiple terrains
             if (gridx == 1 && z == 0)
             {
             heights[x,z] = Random.Range(1.0f, terrainYsize);
             }
             
             if (gridz == 1 && x == 0)
             {
             heights[x,z] = Random.Range(1.0f, terrainYsize);
             }
             
             if (gridx == numOfTerrainBySide && z == terrainHeightMapSize)
             {
             heights[x,z] = Random.Range(1.0f, terrainYsize);
             }
             
             if (gridz == numOfTerrainBySide && x == terrainHeightMapSize)
             {
             heights[x,z] = Random.Range(1.0f, terrainYsize);
             }
             
         }
     }
 
     newterrain.terrainData.SetHeights(0, 0, heights);
 
 }




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

2 Replies

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

Answer by Baste · Jan 13, 2015 at 11:59 AM

Instantiate is just a normal method on UnityEngine.Object. The new keyword in front of Instantiate makes no sense, and I'm surprised it even compiles.

I'm not quite sure what's happening, but I have an idea. Instantiate makes a copy of prefabs, but it doesn't make a deep copy. Which means that if the prefab references some other object, the reference will be copied, not the referenced object.

So I'd guess that your terrain is being copied, but the terrainData object being referenced is separate, so newterrain.terrainData references the same data as the prefab.

Try to do this in Instantiate:

 var newterrain : Terrain = new Instantiate(worldPiece, wploc, wprot);
 print("terrain is the same object: " + (newterrain == worldPiece));
 print("terrainData is the same object: " + (newterrain.terrainData == worldPiece.terrainData));

I'm 99% sure you'll get true on the first one, and false on the second one.

To fix this, you'll have to create a copy of the terrain data, and assign that to the instantiated Terrain copy. That'll take some work on the Unity internals - post a reply if you can't figure it out on your own.

Comment
Add comment · Show 2 · 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 JMurray · Jan 13, 2015 at 06:05 PM 0
Share

I was 99% sure your expected results would come out but I got the following.

 terrain is the same object: False
 terrainData is the same object: True

I think I'm getting the above results because terrain == worldpiece is doing an object comparison (are they the same object) when the newterrain.terrainData == worldpiece.terrainData is doing a terrainData comparison and is ignore object information. Since terrainData is being replicated between the objects it is the same between all pieces and the worldpiece.

The "new" in front of instantiate was a last $$anonymous$$ute compile to see if it would force a new object with new terrain data. I had it using just instantiate without the new.

The other solution I had was to apply new terraindata() to the object after its being instantiated (thats why I had terrainsize variables at the top of the script).

However, I had an issue where the terrain object was not applying the size.

 newterrain.terrainData.size = Vector3(terrainXsize, terrainYsize, terrainZsize);

The new terrains however had a size of 8000x500x50. Blew my $$anonymous$$d why it wasn't applying an X size to the newterrain object when Y and Z were being applied.

EDIT: The below code keeps my terrain prefab intact and preserves its terrain data. Unfortunately size is not changing to 500x50x500 and it is creating each world piece 8000x50x8000.

 //create terrain from prefab object
  var newterrain : Terrain = Instantiate(worldPiece, wploc, wprot);
  
  //create new terrainData to resolve problem with terrain data being copied to prefab
  
  newterrain.terrainData = new TerrainData();
  
  newterrain.terrainData.size = new Vector3(terrainXsize, terrainYsize, terrainZsize);
  newterrain.terrainData.heightmapResolution = terrainHeight$$anonymous$$apResolution;

Edit: I figured out my issues with applying the size. I had to apply the heightmap resolution first before applying size.

avatar image Owen-Reynolds · Jan 13, 2015 at 06:57 PM 0
Share

The same thing happens if you use a terrain in 2 scenes and modify one of them. They both change, because Unity purposely doesn't make copies of terrain data.

Terrain is just funny that way. Lots of terrain-only optimizations and special-cases (for any game engine.) I'm a little surprised Instantiate works on terrain at all.

avatar image
0

Answer by JMurray · Jan 16, 2015 at 05:40 PM

For the sake of the community I'm including that I also dropped the initiate on terrain and ended up going the route of creating a new object.

//create terrain out of thin air var newTerrainObject : GameObject = new GameObject(); newTerrainObject.transform.parent = transform; var newTerrain : Terrain = new newTerrainObject.gameObject.AddComponent("Terrain");

  //move new terrain to location
  newTerrainObject.transform.position= newloc;
  
  //layer tag object
  newTerrainObject.layer = terrainLayerMask;
  
  //create new terrainData to resolve problem with terrain data being copied to prefab
  newTerrain.terrainData = new TerrainData();
  
  //set terraindata to minimum requirements. heightmapResolution must be set before size.
  newTerrain.terrainData.heightmapResolution = terrainHeightMapResolution;
  newTerrain.terrainData.size = new Vector3(terrainXsize, terrainYsize, terrainZsize);

This ended up resolving a bunch of issues in the end.

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

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

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Cloned Object does not run Scripts 2 Answers

Instantiated clones arent behaving the same as the prefab 1 Answer

Deleting a GameObject 2 Answers

Cast Source Instantiating Error 1 Answer

Instantiate Clones Itself - Rather than Prefab 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