- Home /
Trees not being placed correctly by script on unity terrain.
I'm making a script to make a randomly generated terrain using the unity terrain engine. So far I've been able to set the heights and paint textures on the terrain. Now I want to place trees on it. For testing, I'm having the trees be place in a long diagonal line under the terrain.
// This code is run for every point on the terrain heightmap x,y position
float percent = UnityEngine.Random.value;
if (percent >= 0.5f)
{
placedTrees++;
//Vector3 treePos = new Vector3(x * (4000 / 256) + t.transform.position.x, 0.0f, y * (4000 / 256) + t.transform.position.z);
Vector3 treePos = new Vector3(0 + placedTrees, 0, 0 + placedTrees);
TreeInstance tree = new TreeInstance();
tree.color = baseTree.color;
tree.heightScale = baseTree.heightScale;
tree.lightmapColor = baseTree.lightmapColor;
tree.position = treePos;
tree.prototypeIndex = baseTree.prototypeIndex;
tree.widthScale = baseTree.widthScale;
treeList.Add(tree);
}
//run after the loop
Debug.Log("trees placed: " + placedTrees);
Debug.Log("tree array size: " + treeList.Count);
t.terrainData.treeInstances = treeList.ToArray();
The two debug logs print the same result (usually around 2500), but yet only one tree appear in the scene. The full function can be found here.
Thanks in advance for any help.
What is the class TreeInstance? Normally you would need to instantiate a game object from a prefab with Instantiate ins$$anonymous$$d of using new. Something like
GameObject treeGO = Instantiate(prefab, new Vector3(x,y,z), Quaternion.Identity) as GameObject;
TreeInstance tree = treeGO.GetComponent<TreeInstance>();
This is if the class TreeInstance is a component that can be added to a game object. Alternatively you can generate a new game object and add the TreeInstance component.
Answer by kvoepel3 · Mar 12, 2015 at 03:42 AM
I realize this question is old, but it comes up in every single google search about Unity trees, so I'm going to answer it in hopes that someone who is a similarly frustrated Unity noob like myself (tackling run-time procedural terrain, which is probably not a great place to start) stumbles across it and gets what they need.
The problem with the trees is right here:
Vector3 treePos = new Vector3(0 + placedTrees, 0, 0 + placedTrees);
There are two reasons why trees would show up where you don't want them, when you initialize the position in this way.
1) The Vector3 object that the TreeInstance expects contains a local terrain position, so all three elements of the vector should be floats between 1 and 0. Anything larger than 1 seems to be treated as 1, so since you're using an integer counter, all of your trees will effectively be given the position of <1, 0, 1> (which is smashed into one corner of the terrain, probably either high above or far beneath it, depending on your scale). The way to fix this is to divide each of these elements by the dimension of your terrain.
Vector3 treePos = new Vector3(0.0f + placedTrees / t.terrainData.heightmapWidth, 0.0f, 0.0f + placedTrees / t.terrainData.heightmapHeight);
If you needed to divide the middle parameter, you'd need to do it by the value of the "Terrain Height" property in the editor. I'm currently too noobish to figure out how to get at that in a script. Since mine was 1000, I just hardcoded a 1000.0f in there, and viola, this code drew a line of trees across my Perlin terrain that looked like they belonged there.
My final code looked thusly:
new Vector3(i/terData.heightmapWidth, terData.GetHeight((int)i, (int)i) / 1000f, i/terData.heightmapHeight);
2) For a 3D noob like me, thinking about 3 dimensional vectors can get confusing. It's very easy to understand that a Vector3 is x, y, z, but when thinking about height maps I'm only ever working with x and y. On a heightmap, x and y represent dimensions on the plane, but in the Vector3 used by TreeInstance/TerrainData, y represents the elevation, where x and z are on the plane. The OP probably didn't have this problem, but someone reading it might.
Happy run-time procedurally placed trees y'all.
Answer by oleg_v · Oct 05, 2020 at 12:15 AM
Small addition: vertical scale is in terrainData.heightmapScale.y
ps. Still can't get good info about terrain API via google :)
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Multiple Cars not working 1 Answer
getting an object to stick to terrain in c# 1 Answer
Gather all coordinates of a terrain into a data structure. 1 Answer
Flat Low Poly Terrain / Script a terrain 2 Answers