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
3
Question by AlCrawford · Jan 04, 2010 at 07:16 PM · terraingraphicsasset

Just How Malleable Are Terrains, Really?

I'm currently working on the early stages of a project that will depend heavily on being able to modify the terrain. Altering heightmaps, altering textures, adding/removing mesh objects, associating arbitrary attributes with a terrain, and so forth. Oh, and all of these will need to be persistable. Also, being able to generate terrains, and package them up for dynamic loading, server-side. Plus I'd like a pony :-)

Now I know the only documented (and thus "official") aspect of terrains that can be changed at runtime is the heightmap. What else is there that's undocumented and Unity is willing to let people know about?

If it's not feasible to do what I want with existing terrains, I may have to resort to using mesh objects to do what I'd like. Ideally I'd like to have a completely new class of object - say, DynamicTerrain - that supported the abilities I need without having to compromise the current Terrain class. Now I know what that would involve, but I've got 20 years of C/C++ experience, nothing else on my plate (I've got a defense background but I'm stuck in a state that's got no defense work in it), and would be happy to give any resulting implementation of dynamic terrains to Unity - in addition to the project I'm currently trying to get going, having a more malleable terrain available would open up the possibility of several additional projects for me (of course, then I'd also need a fisheye lens camera option, but that's another question for another time...)

Pie in the sky, I know, but I thought it wouldn't hurt to at least ask.

Al

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

3 Replies

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

Answer by Jaap Kreijkamp · Jan 05, 2010 at 04:13 AM

I would say the pony is the easiest requirement.

The terrain asset is quite limited in what you can do with it in runtime. However... there are some undocumented API's you can use to basically construct/modify anything in a terrain. A simple google gave me the following code, don't know where it's from but it seems to use about anything terrain related to construct one dynamically. As the TerrainData API is undocumented it's unsupported and not guaranteed to work now or in the future...

I don't know who's the owner of the code below and haven't tried it myself but should be helpful to see how you can use the API.

Good luck with your project and pony.

//Download terrain assets referenced in headers i = 1; for(var v : String in trnArr) { //v = "name;r:width,height,length,heightmapResolution //,detailResolution,controlResolution,textureResolution;h:heightMapUrl"; var vS2 : String[] = v.Split(";"[0]); var tName = vS2[0]; for(i2 = 1; i2<vS2.length; i2++) { var str : String[] = vS2[i2].Split(":"[0]); if(str[0] == "r") var tRes : String[] = str[1].Split(","[0]); else if(str[0] == "h") var tHtmp : String = whirld.getURL(str[1]); else if(str[0] == "l") var tLtmp : String = whirld.getURL(str[1]); else if(str[0] == "s") var tSpmp : String = whirld.getURL(str[1]); else if(str[0] == "s2") var tSpmp2 : String = whirld.getURL(str[1]); else if(str[0] == "t") var tTxts : String[] = str[1].Split(","[0]); else if(str[0] == "d") var tDtmp : String = whirld.getURL(str[1]); } whirld.statusTxt = "Downloading Terrain " + i + " of " + trnArr.length + " (" + tName + "): " + tHtmp; www = new WWW(tHtmp); while(!www.isDone) { whirld.progress = www.progress; yield new WaitForSeconds(.1); } if (www.error != null) whirld.info += "\nTerrain Undownloadable: " + tName + " " + tHtmp + " (" + www.error + ")"; else { whirld.statusTxt = "Initializing " + tName + "..."; whirld.progress = 0; if(Application.isPlaying) yield;

     var tWidth : int = parseInt(tRes[0]);
     var tHeight : int = parseInt(tRes[1]);
     var tLength : int = parseInt(tRes[2]);
     var tHRes : int = parseInt(tRes[3]);
     //var tDRes : int = parseInt(tRes[4]);
     //var tCRes : int = parseInt(tRes[5]);
     //var tBRes : int = parseInt(tRes[6]);
     var trnDat : TerrainData = new TerrainData();

     //Heights
     trnDat.heightmapResolution = tHRes;
     //trnDat.Init(tCRes, tDRes, tBRes);
     var hmap = trnDat.GetHeights(0, 0, tHRes, tHRes);
     var br : BinaryReader;
     if(true) { //Terrain RAW file is compressed
         /*var stream = new DeflateStream(new MemoryStream(www.bytes), CompressionMode.Decompress);
         var buffer : byte[] = new byte[4096];
         var ms : MemoryStream = new MemoryStream();
         var bytesRead : int = 0;
         while (bytesRead &gt; 0) {
             bytesRead = stream.Read(buffer, 0, buffer.Length);
             if (bytesRead &gt; 0) ms.Write(buffer, 0, bytesRead);
         }
         br = new BinaryReader(ms);*/
         br = new BinaryReader(new MemoryStream(new Ionic.Zlib.GZipStream(new MemoryStream(), Ionic.Zlib.CompressionMode.Decompress).UncompressBuffer(www.bytes)));
     }
     else br = new BinaryReader(new MemoryStream(www.bytes));
     for (var x : int = 0; x &lt; tHRes; x++) for (var y : int = 0; y &lt; tHRes; y++) hmap[x, y] = br.ReadUInt16() / 65535.00000000;
     trnDat.SetHeights(0, 0, hmap);
     trnDat.size = Vector3(tWidth, tHeight, tLength);                

     //Textures
     if(tTxts) {
         var splatPrototypes : SplatPrototype[] = new SplatPrototype[tTxts.length];
         for(i=0; i &lt; tTxts.length; i++) {
             var splatTxt : String[] = tTxts[i].Split("="[0]);
             var splatTxtSize : String[] = splatTxt[1].Split("x"[0]);
             whirld.statusTxt = "Downloading Terrain Texture " + (i + 1) + " of " + tTxts.length + " (" + splatTxt[0] + ")";
             www = new WWW(whirld.getURL(splatTxt[0]));
             while(!www.isDone) {
                 whirld.progress = www.progress;
                 yield new WaitForSeconds(.1);
             }
             if (www.error != null) whirld.info += "\nTerrain Texture Undownloadable: #" + (i + 1) + " (" + splatTxt[0] + ")";
             else {
                 whirld.statusTxt = "Initializing Terrain Texture " + (i + 1) + " of " + tTxts.length + "...";
                 yield;
                 splatPrototypes[i] = new SplatPrototype();
                 splatPrototypes[i].texture = new Texture2D(4, 4, TextureFormat.DXT1, true);
                 www.LoadImageIntoTexture(splatPrototypes[i].texture);
                 splatPrototypes[i].texture.Apply(true);
                 splatPrototypes[i].texture.Compress(true);
                 splatPrototypes[i].tileSize = Vector2(parseInt(splatTxtSize[0]), parseInt(splatTxtSize[1]));
             }
         }
     }
     else {
         splatPrototypes = new SplatPrototype[whirld.worldTerrainTextures.length];
         for(i=0; i &lt; whirld.worldTerrainTextures.length; i++) {
             splatPrototypes[i] = new SplatPrototype();
             splatPrototypes[i].texture = whirld.worldTerrainTextures[i];
             splatPrototypes[i].tileSize = Vector2(15, 15);
         }
     }
     trnDat.splatPrototypes = splatPrototypes;

     //Lightmap
     if(tLtmp) {
         whirld.statusTxt = "Downloading Terrain Lightmap (" + tName + ")";
         www = new WWW(tLtmp);
         while(!www.isDone) {
             whirld.progress = www.progress;
             yield new WaitForSeconds(.1);
         }
         if (www.error != null) whirld.info += "\nTerrain Lightmap Undownloadable: " + tName + " " + tLtmp + " (" + www.error + ")";
         else {
             trnDat.lightmap = www.texture;
         }
     }

     //Splatmap
     if(tSpmp) {
         if(tSpmp2) {
             whirld.statusTxt = "Downloading Augmentative Terrain Texturemap (" + tName + ")";
             www = new WWW(tSpmp2);
             while(!www.isDone) {
                 whirld.progress = www.progress;
                 yield new WaitForSeconds(.1);
             }
             var mapColors2 = www.texture.GetPixels();
         }
         whirld.statusTxt = "Downloading Terrain Texturemap (" + tName + ")";
         www = new WWW(tSpmp);
         while(!www.isDone) {
             whirld.progress = www.progress;
             yield new WaitForSeconds(.1);
         }
         whirld.progress = 0;
         whirld.statusTxt = "Mapping Terrain Textures...";
         yield;
         if (www.error != null) whirld.info += "\nTerrain Texturemap Undownloadable: " + tName + " " + tLtmp + " (" + www.error + ")";
         else {
             if (www.texture.format != TextureFormat.ARGB32 || www.texture.width != www.texture.height || Mathf.ClosestPowerOfTwo(www.texture.width) != www.texture.width) {
                 whirld.info += "\nTerrain Splatmap Unusable: Splatmap must be in RGBA 32 bit format, square, and it's size a power of 2";
             }
             else {
                 trnDat.alphamapResolution = www.texture.width;
                 var splatmapData = trnDat.GetAlphamaps(0, 0, www.texture.width, www.texture.width);
                 var mapColors = www.texture.GetPixels();
                 var ht : int = www.texture.height;
                 var wd : int = www.texture.width;
                 for (y = 0; y &lt; ht; y++) for (x = 0; x &lt; wd; x++) for (z = 0; z &lt; trnDat.alphamapLayers; z++) {
                     if(z &lt; 4) splatmapData[x,y,z] = mapColors[x * wd + y][z];
                     else splatmapData[x,y,z] = mapColors2[x * wd + y][z-4];
                 }
                 trnDat.SetAlphamaps(0, 0, splatmapData);
             }
         }
     }

     //Details (rocks, trees, grass, etc)
     if(tDtmp) {
         whirld.statusTxt = "Downloading Terrain Details (" + tDtmp + ")";
         www = new WWW(tDtmp);
         while(!www.isDone) {
             whirld.progress = www.progress;
             yield new WaitForSeconds(.1);
         }
         if (www.error != null) whirld.info += "\nTerrain Details Undownloadable: " + tName + " " + tDtmp + " (" + www.error + ")";
         else {
             var treePrototypes : Array = new Array();
             var treeInstances : Array = new Array();
             var treeProto : TreePrototype;
             var detailProto : DetailPrototype;
             var detailPrototypes : Array = new Array();
             file = new Ionic.Zlib.GZipStream(new MemoryStream(), Ionic.Zlib.CompressionMode.Decompress).UncompressString(www.bytes).Split("\n"[0]);
             for (i=0; i &lt; file.length; i++) {
                 if(file[i] == "" || i == file.length - 1) { //Apply Existing Trees
                     if(treeProto) {
                         treePrototypes.Add(treeProto);
                         treeProto = null;
                         //continue;
                     }
                     if(detailProto) {
                         detailPrototypes.Add(detailProto);
                         detailProto = null;
                         //continue;
                     }
                 }
                 if(file[i].length &gt; 10 &amp;&amp; file[i].Substring(0, 10) == "detailmap2") {
                     whirld.statusTxt = "Downloading Augmentative Terrain Detail Map (" + whirld.getURL(file[i].Substring(11)) + ")";
                     www = new WWW(whirld.getURL(file[i].Substring(11)));
                     while(!www.isDone) {
                         whirld.progress = www.progress;
                         yield new WaitForSeconds(.1);
                     }
                     if (www.error != null) whirld.info += "\nAugmentative Terrain Detail Map Undownloadable: " + tName + " " + file[i].Substring(11) + " (" + www.error + ")";
                     else {
                         tex = www.texture;
                         pixels = www.texture.GetPixels();
                         if(detailPrototypes.length &gt; 4) var detLayer4 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 4);
                         if(detailPrototypes.length &gt; 5) var detLayer5 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 5);
                         if(detailPrototypes.length &gt; 6) var detLayer6 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 6);
                         if(detailPrototypes.length &gt; 7) var detLayer7 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 7);
                         i2 = 0;
                         for(iY = 0; iY &lt; trnDat.detailResolution; iY++) {
                             for(iX = 0; iX &lt; trnDat.detailResolution; iX++) {
                                 if(detailPrototypes.length &gt; 4) detLayer4[iX, iY] = Mathf.RoundToInt(pixels[i2].r * 16);
                                 if(detailPrototypes.length &gt; 5) detLayer5[iX, iY] = Mathf.RoundToInt(pixels[i2].g * 16);
                                 if(detailPrototypes.length &gt; 6) detLayer6[iX, iY] = Mathf.RoundToInt(pixels[i2].b * 16);
                                 if(detailPrototypes.length &gt; 7) detLayer7[iX, iY] = Mathf.RoundToInt(pixels[i2].a * 16);
                                 i2 += 1;
                             }
                         }
                     }
                 }
                 else if(file[i].length &gt; 10 &amp;&amp; file[i].Substring(0, 9) == "detailmap") {
                     whirld.statusTxt = "Downloading Terrain Detail Map (" + whirld.getURL(file[i].Substring(10)) + ")";
                     www = new WWW(whirld.getURL(file[i].Substring(10)));
                     while(!www.isDone) {
                         whirld.progress = www.progress;
                         yield new WaitForSeconds(.1);
                     }
                     if (www.error != null) whirld.info += "\nTerrain Detail Map Undownloadable: " + tName + " " + file[i].Substring(10) + " (" + www.error + ")";
                     else {
                         tex = www.texture;
                         pixels = www.texture.GetPixels();
                         trnDat.detailResolution = www.texture.width;
                         if(detailPrototypes.length &gt; 0) var detLayer0 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 0);
                         if(detailPrototypes.length &gt; 1) var detLayer1 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 1);
                         if(detailPrototypes.length &gt; 2) var detLayer2 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 2);
                         if(detailPrototypes.length &gt; 3) var detLayer3 = trnDat.GetDetailLayer(0, 0, trnDat.detailResolution, trnDat.detailResolution, 3);
                         i2 = 0;
                         for(iY = 0; iY &lt; trnDat.detailResolution; iY++) {
                             for(iX = 0; iX &lt; trnDat.detailResolution; iX++) {
                                 if(detailPrototypes.length &gt; 0) detLayer0[iX, iY] = Mathf.RoundToInt(pixels[i2].r * 16);
                                 if(detailPrototypes.length &gt; 1) detLayer1[iX, iY] = Mathf.RoundToInt(pixels[i2].g * 16);
                                 if(detailPrototypes.length &gt; 2) detLayer2[iX, iY] = Mathf.RoundToInt(pixels[i2].b * 16);
                                 if(detailPrototypes.length &gt; 3) detLayer3[iX, iY] = Mathf.RoundToInt(pixels[i2].a * 16);
                                 i2 += 1;
                             }
                         }
                     }
                 }
                 else if(file[i] == "tree") { //Create new tree prototype
                     treeProto = new TreePrototype();
                 }
                 else if(file[i] == "detail") {
                     detailProto = new DetailPrototype();
                 }
                 else if(treeProto) {
                     if(file[i].Substring(0, 1) == "m") {
                         //treeProto.prefab = Resources.Load(file[i].Substring(2));
                         //treeProto.prefab = Game.Controller.prefab;
                         //prefab.AddComponent(MeshFilter);
                         //prefab.AddComponent(MeshRenderer);
                         if(objects.ContainsKey(file[i].Substring(2))) {
                             treeProto.prefab = prefabs.Pop();
                             treeProto.prefab.name = file[i].Substring(2);
                             if(!treeProto.prefab.GetComponent(MeshFilter)) treeProto.prefab.AddComponent(MeshFilter);
                             treeProto.prefab.GetComponent(MeshFilter).mesh = objects[file[i].Substring(2)].GetComponent(MeshFilter).mesh;
                             if(!treeProto.prefab.GetComponent(MeshRenderer)) treeProto.prefab.AddComponent(MeshRenderer);
                             treeProto.prefab.GetComponent(MeshRenderer).materials = objects[file[i].Substring(2)].GetComponent(MeshRenderer).materials;
                             //treeProto.prefab = objects[file[i].Substring(2)];
                         }
                         else whirld.info += "\nTerrain Detail Mesh not found: " + file[i].Substring(2);
                     }
                     else if(file[i].Substring(0, 1) == "b") treeProto.bendFactor = parseFloat(file[i].Substring(2));
                     else if(file[i+1] == "") { //Read detail objects
                         var treedat : String[] = file[i].Split(";"[0]);
                         for(var tr : String in treedat) {
                             if(!tr) continue;
                             var tree = tr.Split(","[0]);
                             if(!tree[0] || tree[0] == "") continue;
                             var treeInstance = new TreeInstance();
                             treeInstance.prototypeIndex = treePrototypes.length;
                             treeInstance.position = Vector3(parseFloat(tree[0]), parseFloat(tree[1]), parseFloat(tree[2]));
                             treeInstance.widthScale = parseFloat(tree[3]);
                             treeInstance.heightScale = parseFloat(tree[4]);
                             var c : float = Random.Range(.6, .7);
                             treeInstance.color = Color(c - .15, c - .15, c - .15, 1);
                             treeInstance.lightmapColor = Color(c + .15, c + .15, c + .15, 0);
                             treeInstances.Add(treeInstance);
                         }
                     }
                 }
                 else if(detailProto) {
                     l = file[i].Split(" "[0]);
                     if(l[0] == "pO") {
                         if(objects.ContainsKey(l[1])) {
                             //detailProto.prototype = objects[l[1]];
                             detailProto.prototype = prefabs.Pop();
                             detailProto.prototype.name = l[1];
                             if(!detailProto.prototype.GetComponent(MeshFilter)) detailProto.prototype.AddComponent(MeshFilter);
                             detailProto.prototype.GetComponent(MeshFilter).mesh = objects[l[1]].GetComponent(MeshFilter).mesh;
                             if(!detailProto.prototype.GetComponent(MeshRenderer)) detailProto.prototype.AddComponent(MeshRenderer);
                             detailProto.prototype.GetComponent(MeshRenderer).material = objects[l[1]].GetComponent(MeshRenderer).material;
                         }
                         else whirld.info += "\nTerrain Detail Mesh not found: " + l[1];
                     }
                     else if(l[0] == "pT") {
                         l[1] = whirld.getURL(l[1]);
                         whirld.statusTxt = "Downloading Terrain Detail Texture (" + l[1] + ")";
                         www = new WWW(l[1]);
                         while(!www.isDone) {
                             whirld.progress = www.progress;
                             yield new WaitForSeconds(.1);
                         }
                         if (www.error != null) whirld.info += "\nTerrain Detail Texture Undownloadable: " + l[1];
                         else {
                             whirld.statusTxt = "Initializing " + vS[0] + "...";
                             whirld.progress = 0;
                             yield;
                             mshTxt = new Texture2D(4, 4, TextureFormat.DXT5, true);
                             www.LoadImageIntoTexture(mshTxt);
                             mshTxt.Apply(true);
                             mshTxt.Compress(true);
                             mshTxt.wrapMode = TextureWrapMode.Clamp;
                             detailProto.prototypeTexture = mshTxt;
                         }
                     }
                     else if(l[0] == "minW") detailProto.minWidth = parseFloat(l[1]);
                     else if(l[0] == "maxW") detailProto.maxWidth = parseFloat(l[1]);
                     else if(l[0] == "minH") detailProto.minHeight = parseFloat(l[1]);
                     else if(l[0] == "maxH") detailProto.maxHeight = parseFloat(l[1]);
                     else if(l[0] == "nS") detailProto.noiseSpread = parseFloat(l[1]);
                     else if(l[0] == "bF") detailProto.bendFactor = parseFloat(l[1]);
                     else if(l[0] == "hC") detailProto.healthyColor = Color(parseFloat(l[1]), parseFloat(l[2]), parseFloat(l[3]));
                     else if(l[0] == "dC") detailProto.dryColor = Color(parseFloat(l[1]), parseFloat(l[2]), parseFloat(l[3]));
                     else if(l[0] == "lF") detailProto.lightmapFactor = parseFloat(l[1]);
                     else if(l[0] == "gL") detailProto.grayscaleLighting = (l[1] == "1" ? true : false);
                     else if(l[0] == "rM") {
                         if(l[1] == "GrassBillboard") detailProto.renderMode = DetailRenderMode.GrassBillboard;
                         else if(l[1] == "VertexLit") detailProto.renderMode = DetailRenderMode.VertexLit;
                         else detailProto.renderMode = DetailRenderMode.Grass;
                     }
                     else if(l[0] == "uM") detailProto.usePrototypeMesh = (l[1] == "1" ? true : false);
                 }
             }
             trnDat.treePrototypes = treePrototypes.ToBuiltin(TreePrototype);
             trnDat.treeInstances = treeInstances.ToBuiltin(TreeInstance);
             trnDat.detailPrototypes = detailPrototypes.ToBuiltin(DetailPrototype);
             if(detailPrototypes.length &gt; 0) trnDat.SetDetailLayer(0, 0, 0, detLayer0);
             if(detailPrototypes.length &gt; 1) trnDat.SetDetailLayer(0, 0, 1, detLayer1);
             if(detailPrototypes.length &gt; 2) trnDat.SetDetailLayer(0, 0, 2, detLayer2);
             if(detailPrototypes.length &gt; 3) trnDat.SetDetailLayer(0, 0, 3, detLayer3);
             if(detailPrototypes.length &gt; 4) trnDat.SetDetailLayer(0, 0, 4, detLayer4);
             if(detailPrototypes.length &gt; 5) trnDat.SetDetailLayer(0, 0, 5, detLayer5);
             if(detailPrototypes.length &gt; 6) trnDat.SetDetailLayer(0, 0, 6, detLayer6);
             if(detailPrototypes.length &gt; 7) trnDat.SetDetailLayer(0, 0, 7, detLayer7);
             //trnDat.RefreshPrototypes();
             //trnDat.RecalculateTreePositions();
         }
         /*for(i=0; i&lt;trnDat.treePrototypes.length; i++) {
             trnDat.treePrototypes[i].prefab.name = trnDat.treePrototypes[i].prefab.name.Replace(" ", "_");
             MeshWriteObj(trnDat.treePrototypes[i].prefab.GetComponent(MeshFilter), trnDat.treePrototypes[i].prefab.name);
             data = "[msh:" + trnDat.treePrototypes[i].prefab.name + "," + trnDat.treePrototypes[i].prefab.name + ".obj.gz]" + data;
             trnV += (trnV != "" ? "\n\n" : "") + "tree\nm:" + trnDat.treePrototypes[i].prefab.name + "\nb:" + trnDat.treePrototypes[i].bendFactor + "\n";
             for(var tree : TreeInstance in trnDat.treeInstances) {
                 if(tree.prototypeIndex != i) continue;
                 trnV += tree.position.x.ToString("F1", System.Globalization.CultureInfo.InvariantCulture) + "," + tree.position.y.ToString("F1", System.Globalization.CultureInfo.InvariantCulture) + "," + tree.position.z.ToString("F1", System.Globalization.CultureInfo.InvariantCulture) + "," + tree.widthScale.ToString("F1", System.Globalization.CultureInfo.InvariantCulture) + "," + tree.heightScale.ToString("F1", System.Globalization.CultureInfo.InvariantCulture) + ";";
             }
         }*/
     }

     //Go!
     var trnObj : GameObject = new GameObject(tName);
     trnObj.AddComponent(Terrain);
     trnObj.GetComponent(Terrain).terrainData = trnDat;
     trnObj.AddComponent(TerrainCollider);
     trnObj.GetComponent(TerrainCollider).terrainData = trnDat;

     objects.Add(tName, trnObj);
     GameObject.Destroy(trnObj);
     whirld.statusTxt = "";
 }
 i++;

}

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 AlCrawford · Jan 09, 2010 at 10:00 PM 0
Share

Thanks - the code looks pretty straightforward. I'll have to play with code that modifies the Terrain object's hidden properties at runtime to see whether dynamic changes (e.g. chop down a tree) are reflected immediately, or whether it's going to involve rebuilding and reloading the entire terrain object. The latter is, obviously, not very practical, even if I make the assumption that I can modify my code easily enough to keep up with changes in the implementation.

avatar image
2

Answer by Tom 1 · Jan 25, 2010 at 08:16 PM

You can modify almost anything about terrain at runtime. However, as Jaap already outlined, the API is largely undocumented. But textures (splatmaps), trees, grass and detail meshes are all scriptable.

Yes, chopping down a tree is instant. If you search the forum or look at my website, I created a script to destroy trees at runtime.

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 Jean-Fabre · Sep 03, 2010 at 06:16 PM 0
Share

nice resources tom

avatar image
2

Answer by Sean Baggaley · Jan 27, 2010 at 10:01 AM

Just a heads-up: The script Jaap Kreijkamp found appears to be from the "Whirld" project on the Unify Community wiki.

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 Simon Wittber · Feb 08, 2012 at 04:25 AM 0
Share

And there is also Terrain Destruction which does some simple terrain digging.

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

1 Person is following this question.

avatar image

Related Questions

Normal maps on terrain textures not showing in editor 1 Answer

How to create a plow of fields ? 0 Answers

LWRP - Placing markers on terrain and gameobject dynamically 0 Answers

Placing tree objects with Terrain or Polybrush which one is useful ?? 0 Answers

White lines between gameObject and water asset. 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