Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Using Tree gameobjects vs Unity's built in system

Discussion in 'Scripting' started by jc_lvngstn, May 22, 2013.

  1. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Not that i know of : /
     
  2. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    So, I just did a script to do this, but it is still in processes. Here are the results so far:

    $CappingUnityTrees.jpg

    When I get it "done", I'll upload it in a sample project. But the way it works so far:

    First, you have to add another material to the tree, for the chop texture. I think the break material could be used it if was looked ok.

    As you can see, there are issues where the cap seems disconnected from the trunk. It looks like it is due to scaling, too early to know for sure. If that is a case it is something of a bummer. I don't know why this is the case, unless unity "knows" that the point of the cap I added isn't part of the original tree. And yet...it still draws the cap.

    I'm going to examine the vertex colors of the original tree, to see if that is the issue. I may just need to mimic those. Maybe it is applying incorrect wind bending because right now, my new one is black. But that shouldn't be an issue, because I just added the point of the cap as a new vertex. Anyway...I dunno, I'll keep working on it.

    Anyway...I just added a script to the original tree, to add the cap. Any changes to the tree will probably remove it, so you will have to run the script again. A nice editor for it would be great, but I probably won't be going that far. The good thing is, after you run the script, painted trees have the cap.

    Ok...rant on :)
    What would be really, REALLY nice is if UT could just find the time to do something like this. There is already a slot for the break material. Just add a "Add Trunk Cap" checkbox already!!! Heck. I've been in situations where I HAD to use an external modeller just because I needed trees to chop, but they didn't have the dumb cap and it looks goofy. Others have brought up this also. It's like the bowing tree billboard issues, where they tilt down as you tilt the camera. Others (lars bertram) had to find a solution to the issue, when UT should have done it long ago. I know it's not a cool sparkly thing to show off at Unite, but it's one of many small, continue improvements that are badly needed.

    Ok rant off. It just bugs me. But hopefully this will help some folks when I get it done.

    [Edit] Sorry for the horribly dark lighting, my only excuse was it was early this morning. My apologies.
     
    Last edited: Mar 12, 2014
    Jaqal likes this.
  3. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Ooh, I would love that tree capping code. In the effort of making all our tree-filled lives less annoying, here's some code I wrote to dynamically swap terrain trees for game object trees as you move through the world. That way you can put scripts and things on the tree prefab so they are interactive. If you use this, make sure you turn "Create Tree Colliders" off since the game object version has a collider, and for this version you will also need to add a "blank" tree as the final tree prototype in the terrain list... I use a cube with the renderer disabled, so it stops complaining about not having a renderer attached. Then attach the "DynamicTreeManager" to each terrain. Don't attach "DynamicTree" to the trees; that happens automatically.

    Code (csharp):
    1.  
    2. public class DynamicTree : MonoBehaviour
    3. {
    4.     public TreeInstance terrainTree;
    5.     public int prototypeIndex;
    6. }
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class DynamicTreeManager : MonoBehaviour
    7. {
    8.     public Terrain terrain;
    9.     public float pollingTime = 1f;
    10.     public float swapDistance = 10f;
    11.     public float randomRotation = 0f;
    12.  
    13.     protected List<DynamicTree> dynTrees;
    14.     protected TreeInstance[] terrainTrees;
    15.     protected float timer = 0f;
    16.     protected int blankTreeIndex;
    17.    
    18.     protected void Awake()
    19.     {
    20.         if (!terrain)
    21.             terrain = GetComponent<Terrain>();
    22.     }
    23.  
    24.     protected void Start()
    25.     {
    26.         PopulateTrees();
    27.     }
    28.  
    29.     public void PopulateTrees()
    30.     {
    31.         dynTrees = new List<DynamicTree>(terrain.terrainData.treeInstances.Length);
    32.         terrainTrees = (TreeInstance[]) terrain.terrainData.treeInstances.Clone();
    33.         var treeParent = new GameObject {name = "Dynamic Trees"};
    34.         treeParent.transform.parent = terrain.transform;
    35.         blankTreeIndex = terrain.terrainData.treePrototypes.Length - 1;
    36.  
    37.         for (int i = 0; i < terrain.terrainData.treeInstances.Length; i++)
    38.         {
    39.             var tree = terrain.terrainData.treeInstances[i];
    40.             var treePos = Vector3.Scale(tree.position, terrain.terrainData.size) + terrain.transform.position;
    41.             var treePrefab = terrain.terrainData.treePrototypes[tree.prototypeIndex].prefab;
    42.             var treeObj = (GameObject) Instantiate(treePrefab);
    43.             treeObj.transform.position = treePos;
    44.             treeObj.transform.Rotate(Vector3.up, Random.Range(0f,randomRotation));
    45.             treeObj.transform.parent = treeParent.transform;
    46.             treeObj.transform.localScale = new Vector3(tree.widthScale, tree.heightScale, tree.widthScale);
    47.             var dynTree = treeObj.AddComponent<DynamicTree>();
    48.             dynTree.terrainTree = tree;
    49.             dynTree.prototypeIndex = tree.prototypeIndex;
    50.             treeObj.SetActive(false);
    51.             dynTrees.Add(dynTree);
    52.         }
    53.     }
    54.  
    55.     protected void Update()
    56.     {
    57.         if ((timer += Time.deltaTime) < pollingTime)
    58.             return;
    59.  
    60.         timer -= pollingTime;
    61.         ScanTrees(Camera.main.transform.position);
    62.     }
    63.  
    64.     public void ScanTrees(Vector3 center)
    65.     {
    66.         var distanceSquared = swapDistance*swapDistance;
    67.         for (int i = 0; i < dynTrees.Count; i++)
    68.         {
    69.             var tree = dynTrees[i];
    70.             if (!tree) continue;
    71.  
    72.             if ((center - tree.transform.position).sqrMagnitude < distanceSquared)
    73.             {
    74.                 tree.gameObject.SetActive(true);
    75.                 terrainTrees[i].prototypeIndex = blankTreeIndex;
    76.             }
    77.             else
    78.             {
    79.                 tree.gameObject.SetActive(false);
    80.                 terrainTrees[i].prototypeIndex = tree.prototypeIndex;
    81.             }
    82.         }
    83.         terrain.terrainData.treeInstances = terrainTrees;
    84.     }
    85.  
    86.     public void ResetTrees()
    87.     {
    88.         for (int i = 0; i < dynTrees.Count; i++)
    89.         {
    90.             var tree = dynTrees[i];
    91.             if (!tree) continue;
    92.  
    93.             tree.gameObject.SetActive(false);
    94.             terrainTrees[i].prototypeIndex = tree.prototypeIndex;
    95.         }
    96.         terrain.terrainData.treeInstances = terrainTrees;
    97.     }
    98.  
    99.     protected void OnApplicationQuit()
    100.     {
    101.         ResetTrees();
    102.     }
    103.  
    104.     protected void OnDestroy()
    105.     {
    106.         ResetTrees();
    107.     }
    108.  
    109.     protected void OnDisable()
    110.     {
    111.         ResetTrees();
    112.     }
    113. }
     
  4. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,899
    hi there,
    if i can help with chopped trees: just let me know.

    lars
     
  5. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    Still working on it, having some trouble getting the uvs right so the texture displays correctly.
     
  6. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    makeshiftwings: Very clever solution, how heavy is it to create/destroy object trees several times/sec when moving around in a decently dense forest?
    I think it might be a bit to much computation for me that will have several NPCs also running around interacting with the trees?
     
  7. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    It doesn't create or destroy them while running. It creates all the gameobjects once in the Start() method, and then just sets them active/inactive as you move around. I didn't notice any real framerate hit at all, but please feel free to try the script and see how it performs on your scene; I'd be interested to know.
     
  8. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Ok, did not have time to looks through the code, but that seems to be a better solution : )
    Interesting approach indeed : )
     
  9. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    Thanks for the code, makeshiftwings. Interesting, I've never seen this before:

    Code (csharp):
    1. terrainTrees = (TreeInstance[]) terrain.terrainData.treeInstances.Clone();
    I wonder how different that works internally than

    Code (csharp):
    1. terrainTrees = (new List<TreeInstance>(terrain.terrainData.treeInstances)).ToArray();
    If that would even work. I suspect the clone is both cheaper and faster.
    [Edit] I did a little research. ToArray() just does an Array.Copy into a new array internally, and returns that so it's not too bad. I think the main issue is that it has to copy the original array to the List for construction, THEN copy that to a new array.
    I like the clone method you used :) Learn something new every day!


    So, for both of your projects, does tree collision need to be handled on the client side, for both the player AND other players/npcs? Or does it just need to check for the player?
     
    Last edited: Mar 13, 2014
  10. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Since my NPCs will be able to cut trees i need them to be able to detect them, and that also raises question regarding this approach, and that is the detection distance, for the player it can be really short, but for the NPCs, it might need to be very long if the closets tree is far. I really like the idea though and maybe a hybrid solution for NPCs can be a good solution.
     
  11. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Mine is from an FPS perspective, and while there are NPC's who interact with the trees, I kind of "fake" a lot of the NPC interactions by just having them look busy while the actual game logic runs separately... for example, if you have two guys set to chop wood, the actual game logic just basically adds X amount of wood to your stockpile every Y seconds, while the NPC's only actually walk around to nearby trees and chop them down if you're watching them. I do this so I can unload chunks of the world but still have the game update on a macro-level what is happening in the unloaded chunks. But this approach probably wouldn't work as well if you wanted a deep simulation or if you were from an RTS perspective flying around the map a lot.

    I do all my collision detection client-side currently, but I haven't really spent much time on multiplayer so I might end up changing that. Like I said I turn off terrain tree colliders, so only the nearby ones actually have colliders, so entities can walk right through the trees that are far away, but with a decent swapping distance you usually don't actually see that happen. Though again, it probably depends a lot on your camera perspective and how quickly it moves around.
     
    Last edited: Mar 13, 2014
  12. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    Here is the package I have so far. Just run it and you should see that the tree and terrain trees have caps.
    But the texture is jacked up. I'm trying to get it to map to the break texture that is in the top right hand corner, but I'm just not seeing something.

    Anyway...that's what I have so far. Feel free to work on the uv thing or improve the overall approach :)
    I may work on the uv thing some more this weekend.


    It may take a while to sync with my dropbox, I was behind on syncing other things so it may take quite some time to catch up.

    https://dl.dropboxusercontent.com/u/174731243/Unity%20Tree%20Caps/TreeCaps.unitypackage
     
  13. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    I agree with the idea that for the most part...stuff can be faked. For example, in my case, npcs collision pretty much has to happen server side, so I need to cheat as much as possible whenever possible. For example: NPCs moving through trees. If no player is even around...who cares? I'll track on the server if a player is in the region, and if not...it just moves them happily through trees.
    If/when a player does come into the region though, the server will just say...ok, Mr. NPC you are here and there is a tree here also. So...you need to move a little ways away from it. Mr. NPC says fine!

    So I think there are different conditions that may call for less "AI" collision, and some that call for a lot more. Like when a npc is actually engaged with a player. At that point it needs to do move advanced collision detection. Luckily...for the most part, this doesn't happen that often. I mean...at any one time, how many people are likely to be engaged in combat with a npc? A dozen? I don't know yet, but it will be still be a small percentage of the time I think.
    But you know how things change heh.
     
  14. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    Greetings y'all.

    I've been working on a few scripts to mass place tree's as game objects with the same features offered by the built in Unity terrain tree placer and then some. I need scripts attached to my tree's so the built in mass place tree function is not an option. I have everything on my to-do list finished except billboarding. I read through this forum thoroughly and gained a lot of insight.

    My placement script currently;

    1. Randomly generates a location for the tree.
    a. Allows for any number of tree prefabs to be placed (can change in editor.)
    b. Allows for any number of each prefab to be placed (can change in editor.)
    2. Checks for slope of ground and does not place tree on steep slope.
    3. Randomly generates rotation for the tree.
    4. Finds the distance of the tree to the ground and places tree on ground.
    5. Allows for offset adjustment to submerge tree trunk beneath ground (can change in editor.)
    6. Instantiates the tree with position and rotation.

    My Tree Controller script currently;

    1. Generates a random spring color for the leaves between two colors (colors can be changed in editor.)
    2. Gradually fades the tree color between spring and fall colors (fall colors can be changed in editor as well as the rate of change.)
    3. Gradually increases the size of the tree to simulate growth (growth rate can be changed in editor.) (Start and end size can be changed in editor.)
    4. Gradually sinks the tree into the ground as it grows to prevent the larger trunk from protruding through the ground on slope (amount of offset can be changed in editor.) (Sink Rate is equal to Grow Rate.)

    The only thing i'm missing from my phase one tree scripts is billboarding.

    @virror - I read through your billboarding script but have not yet attempted to implement it as you later post that it was buggy. You stated that you have worked out the bugs but I did not see the updated bug free script. Will you post that script for me and are you willing to walk me through implementation a bit?

    I'm happy to share the scripts i'm using for tree's if anyone is interested.

    There is more I would like to do with my tree's such as allow them to propagate and allow the player to harvest them, however this is phase two.

    Here is a link to my tree scripts in use via web player https://dl.dropboxusercontent.com/u/43302734/Dropbox Unity3d Trial.html
     
  15. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Hey! I don't have the original script anymore, but i think the script posted there works fairly well though. It creates a new menu at Window/TreeSystem and then you just select a prefab and click the "Create LOD object" button to make an object. This script has evolved to a way more advanced billboarding system i was working on before that made 8 billboards from different angles and smoothly faded between them in a billboard shader and also supported normal maps and stuff. Drawback with that one is that it currently not working very good at all because of some shader bugs that i never managed to solve and i suck at shader programming, lol. But feel free to try that out as well if you want to: https://dl.dropboxusercontent.com/u/1688685/TreeSystem.rar

    Also i had another approach to making the random trees, i place them using the built in terrain tools and then i have a script that automatically replaces them with prefabs. Its looks up the correct prefab, adds some random size/rotation and places it with a small offset so the trunk is hidden properly.
     
    Last edited: May 15, 2014
  16. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    423
    Hello Virror. I've downloaded and tried your tree system, but i couldn't make it work. Can you explain how i should use it?
     
  17. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    @virror Thanks for replying so quick virror. Ill try out the scripts soon and see if I can get them working. The LOD portion of the script requires Unity Pro correct? I'm still using the free version.
     
  18. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    Hey guys.

    I got the TreeToBillboard script working. It takes the screenshot and saves it to a resources folder within my assets folder. I checked the alpha is transparent box to make the transparency take effect. I then applied the texture to a material, created a plane mesh, rotated it 90 degrees on the X axis and applied the material to it. The problem I'm having now is the tree appears in the middle of the plane as it should however the area of the plane that should be transparent is filled in with the colors of the tree. Basically the tree texture was stretched around the material rather than being stamped on to it. Did you have this issue and if so, how did you overcome it?
     
  19. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    Nevermind my last post, I got it working by changing the shader to transparent/diffuse.
     
  20. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Hey, sorry i did not reply earlier, i missed that someone wrote here : /
    Great that you got the script to work : )
    Its quite basic but it gets the job done : p
     
  21. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @MMOERPG I would love to take a look at your scripts for the Growth and Placement if you still don't mind.

    @makeshiftwings I am attempting to use your script and it seems to be working well but I have one problem. I am using a basic health and rigidbody script to chop down trees but when I cut the trees down while using your DynamicTree scripts when they fall I am left with a standing collider less clone. Any suggestions as why this is happening.

    Code (JavaScript):
    1.  
    2.  
    3. var treeLife = 100;
    4.  
    5. function ApplyDamage (TheDamage : int)
    6. {
    7.     treeLife -= TheDamage;
    8.     Debug.Log("Tree Hit by Object");
    9.  
    10.     if(treeLife <= 0)
    11.     {
    12.         Dead();
    13.     }
    14. }
    15.  
    16. function Dead ()
    17. {
    18.     rigidbody.isKinematic = false;
    19.     rigidbody.AddForce(-transform.forward * 10);
    20.     yield WaitForSeconds(20);
    21.     Destroy(gameObject);
    22. }
    23.  
     
    Last edited: Jul 4, 2014
  22. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50

    Hi Jaqal. I'm happy to share the scripts with you.

    First is the mass placement. It's currently set up for only two tree objects but with some minor tweaking more can be added. I plan to add an automated input from the editor so the number of different tree objects can be input and the options of which tree and quantity will auto populate but currently its hard coded.

    To initiate it, create an empty game object and add this script to it. Then drag the Tree game object prefab you wish to place into the slot for tree0. Next choose a second Tree prefab and drag into the slot for tree1. Next choose the quantity of each. Then hit play. If they spawn above ground then change the amount that they are offset in the inspector. (Additional offsetting (sinking into the ground as they grow) is handled in the tree controller script along with the growth function and others.) Which I will post after this one.

    There is some code in here that sets up the framework for my billboard/LOD script so just ignor it or delete it. Or I can repost later if you like with a cleaner version. This script will also create four game objects. Two that will be parents for your trees that are spawned (one for each prefap) and two that are parents for the billboards that I spawn with another script. As the tree's spawn they are automatically made children of these two game objects and named accordingly to tidy up the editor and allow them to be easily referenced without an array (an array is likely a cleaner way to reference them but I have not gotten around to including that code.)
    Let me know if you have any trouble and i'll be happy to help.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class RandomTreePlacement : MonoBehaviour
    5. {
    6.     public GameObject Tree0;
    7.     public GameObject Tree1;
    8.     public float numberOfTree0;
    9.     public float numberOfTree1;
    10.     public float belowGround = 0.5f;
    11.     [HideInInspector] public GameObject tree0BB;
    12.     [HideInInspector] public GameObject tree1BB;
    13.     [HideInInspector] public GameObject tree0;
    14.     [HideInInspector] public GameObject tree1;
    15.  
    16.     private GameObject tree0Obj;
    17.     private GameObject tree1Obj;
    18.     private float tree0Count = 0;
    19.     private float Offset = 10.0f;
    20.     private bool TerrainOnly = true;
    21.     private string tree0Name;
    22.     private string tree1Name;
    23.  
    24.     void Start()
    25.     {
    26.         tree0Name = Tree0.transform.name.ToString();
    27.         tree1Name = Tree1.transform.name.ToString ();
    28.         tree0 = new GameObject (tree0Name);
    29.         tree1 = new GameObject (tree1Name);
    30.         tree0BB = new GameObject (tree0Name + "BillBoard");
    31.         tree1BB = new GameObject (tree1Name + "BillBoard");
    32.         tree0.tag = "Tree0";
    33.         tree1.tag = "Tree1";
    34.         tree0BB.tag = "Tree0BB";
    35.         tree1BB.tag = "Tree1BB";
    36.  
    37.         for(int i = 0; i<numberOfTree0; i++)
    38.         {
    39.             RandomPlaceTree ();
    40.             tree0Obj.name = tree0Name + i;
    41.             tree0Count++;
    42.         }
    43.  
    44.         for(int i = 0; i<numberOfTree1; i++)
    45.         {
    46.             RandomPlaceTree ();
    47.             tree1Obj.name = tree1Name + i;
    48.         }
    49.     }
    50.  
    51.     void RandomPlaceTree()
    52.     {
    53.         Vector3 size = Terrain.activeTerrain.terrainData.size;
    54.         Vector3 NewPosition = new Vector3();
    55.        
    56.         bool done = false;
    57.         while (!done)
    58.             {
    59.                 // calculate new random position
    60.                 NewPosition = Terrain.activeTerrain.transform.position;
    61.                 float w = Random.Range (0.0f, size.x);
    62.                 float h = Random.Range (0.0f, size.z);
    63.                 NewPosition.x += w;
    64.                 NewPosition.y += size.y + Offset; // make sure we are above the terrain
    65.                 NewPosition.z += h;
    66.  
    67.                 done = true;
    68.        
    69.                 if (done)
    70.                 {
    71.                     // verify that position is above terrain/something
    72.                     RaycastHit hit;
    73.                     if (Physics.Raycast (NewPosition, -Vector3.up, out hit))
    74.                     {
    75.                         float distanceToGround = hit.distance;
    76.                         Vector3 slopeOfGround = hit.normal;
    77. //                        Debug.Log (slopeOfGround);
    78.                         if (hit.transform.name != "Terrain")
    79.                         {
    80.                             if (TerrainOnly)
    81.                                 done = false; // there is something else beneath us
    82.                         }
    83.                         //check slope of ground
    84.                         if (slopeOfGround.y <= 0.9f)
    85.                         {
    86.                             done = false;
    87.                         }
    88.                         // all is good
    89.                         NewPosition.y -= (distanceToGround + belowGround);
    90.                     }
    91.                     else
    92.                     {
    93.                         done = false; // there's nothing under us as far as we care to check
    94.                     }
    95.                 }
    96.             }
    97.  
    98.         Vector3 spawnPosition = NewPosition;
    99.         Quaternion spawnRotation = Quaternion.Euler(0, Random.Range (0, 360), 0);
    100.  
    101.         if(tree0Count < numberOfTree0)
    102.         {
    103.             tree0Obj = (GameObject)Instantiate(Tree0, spawnPosition, spawnRotation);
    104.             tree0Obj.transform.parent = tree0.transform;
    105.         }
    106.         else
    107.         {
    108.             tree1Obj =  (GameObject)Instantiate(Tree1, spawnPosition, spawnRotation);
    109.             tree1Obj.transform.parent = tree1.transform;
    110.         }
    111.  
    112.        
    113.     }
    114. }
     
  23. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @MMOERPG Thanks so much for the quick reply. I'll test it out now! I've been using Unity awhile now and there is nothing I have more difficulty with than dynamic tree interaction. This whole thread has been a great help!

    [Edit] Script is working perfectly! Will save me a ton of time. Thanks
     
    Last edited: Jul 4, 2014
  24. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    Here is the Tree Controller Script. This script allows you to start the tree at a size the is not visible (or any size you like) and grow it to any desired size over a time duration of your choice. At the smallest size, the tree's are not submerged underground so the amount of initial offset will need to be adjusted with the Mass Tree Placement script (in inspector.) They will then grow out of the ground and the amount of offset will need to increase as they grow to keep the bottom trunk edges underground (when placed on not so level terrain.) The amount of total offset can be set in the inspector and the tree will slowly sink into the ground as it grows. Lastly, this script chooses a random color for the trees for both spring and fall seasons then lerps between them to simulate the changing of seasons. The speed of change and the colors can be changed in the inspector.

    To initiate it, add the script directly to each tree prefab. I recommend only making size, speed, and color adjustments in the inspector and leaving the script alone unless you have studied it and understand how it works. I use:

    Start Size: 0.001

    Max Size: 10

    Grow Rate: 0.01 (So I can see the change. For real use this number would be much smaller so growth is unnoticeable.

    Off Set: 2.0 (This amount varies by tree prefab. Run the script and if you still see trunk bottoms protruding, increase this number.

    Age Rate: 0.001 (Again, this number is so i can see the change. For real use this number would be much smaller and would likely be triggered when you wish the change of season to start.)

    Spring Color: I use a grey color to create a range between white (true color) and a darker variation.

    Fall Color Range 0: I use a red - brown color.

    Fall Color Range 1: I use a orange - brown color.

    If you would like to disable the season change, delete or comment out the bottom portion of the script from the renderer.materials[1].color lerp down.

    If you would like to disable the season change but keep the random color for spring, Do the above instructions but add the line:
    renderer.materials [1].color = springColor;

    Again, Let me know if you have any trouble and i'll be happy to help.




    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TreeController : MonoBehaviour
    5. {
    6.     public float startSize = 1.0f;
    7.     public float maxSize = 10.0f;
    8.     public float growRate = 2.0f;
    9.     public float OffSet = 2.5f;
    10.     public float ageRate = 1.0f;
    11.     public Color fallColorRange0;
    12.     public Color fallColorRange1;
    13.     public Color springRange;
    14.  
    15.     private float t0 = 0.0f;
    16.     private float t1 = 0.0f;
    17.     private Vector3 offSet;
    18.     private Vector3 targetScale;
    19.     private Vector3 baseScale;
    20.     private Vector3 targetOffSet;
    21.     private Color springColor;
    22.     private Color fallColor;
    23.     private bool change = false;
    24.  
    25.     void Start()
    26.     {
    27.         offSet = new Vector3 (0, OffSet, 0);
    28.         baseScale = transform.localScale;
    29.         transform.localScale = baseScale * startSize;
    30.         targetScale = baseScale * maxSize;
    31.         targetOffSet = transform.position - offSet;
    32.         t0 = Random.Range (0.0f, 1.0f);
    33.         springColor = Color.Lerp (Color.white, springRange, t0);
    34.         fallColor = Color.Lerp (fallColorRange0, fallColorRange1, t0);
    35.     }
    36.  
    37.     void FixedUpdate()
    38.     {
    39.         transform.localScale = Vector3.Lerp (transform.localScale, targetScale, growRate * Time.deltaTime);
    40.         transform.position = Vector3.Lerp (transform.position, targetOffSet, growRate * Time.deltaTime);
    41.  
    42.         renderer.materials [1].color = Color.Lerp (springColor, fallColor, t1);
    43.         if(!change)
    44.         {
    45.             t1 += ageRate;
    46.         }
    47.         else
    48.         {
    49.             t1 -= ageRate;
    50.         }
    51.  
    52.         if(t1 >= 1.0)
    53.         {
    54.             change = true;
    55.         }
    56.  
    57.         if(t1 <= 0.0)
    58.         {
    59.             change = false;
    60.         }
    61.     }
    62. }
     
  25. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @MMOERPG You are too generous. Thank you so much. I have been working on a pretty complex tree system for quite a while now and this helps tremendously.
     
  26. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    Your welcome! Did you get the Tree Controller script working?

    What does your tree system entail?
    When you have a playable version of what your working on I'd love to check it out.
     
  27. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @MMOERPG Yes it worked perfectly as well! The two together are quite amazing!

    Well what I am going for is a tree system that allows for the creation of a dense interactive forest/jungle without slowing down performance too much. I really don't have anything stable enough to call playable as I am still working on combining many different things as i'm sure you can understand! I am still trying to decide whether to use terrain trees and dynamically changing their state based on player proximity or simply using the prefabs from the beginning.

    Currently my two biggest obstacles going prefab route is simply the actual placing of the trees as my main terrain is fairly large and the billboarding issues of using prefabs. As with the other option of dynamically changing the state of terrain trees I have been running into many problems with visual defects like the lighting of the leaves being odd while in the prefab state!
     
  28. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    So it seems like interacting with trees while using unity's built in terrain tree's is too much of a pain. My problem now is when making all of my trees game objects I am getting horrible performance. Has anyone made any real progress using a billboard or lod system for tree prefabs?
     
  29. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
    @Jaqal Hey Jaqal. I was working on billboards for tree game objects for a while and got to the point where to make them look good I was going to need to write a shader that would look as good as the Nature/TreeSoftOcclusionLeaves shader but still be able to fade to transparent through the alpha channel. I looked in to shaders a bit but this is a bit over my head and time consuming so I gave up on it for now. I'm pretty sure it can be done as Lars has written some beautiful shaders for terrain trees. I'm not sure if they will work for game objects. I was thinking of purchasing his shaders and studying them to see if I could tweek them a bit to make them work for gameObject trees. That will be a future project if I can't figure something else out.

    I'll share with you what I have so far if you'd like to set up a working billboard LOD system (Unity Free) but its by no means attractive.
     
  30. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @MMOERPG Actually I have been thinking of trying to set up a LOD system and billboarding while just forgoing unity's tree system. I just keep running into so many problems going either route. It's driving me nutts lol. It just doesn't make sense that it is still such an issue to be able to interact with the tree system in any straightforward way.
     
  31. auroxi

    auroxi

    Joined:
    Dec 31, 2012
    Posts:
    85
    Jaqal/makeshiftwings: Did you guys ever work out how to remove the tree from the dynamic tree script once its gameobject has been destroyed, so you're not left with a standing collider less clone?

    The script works perfect if I can just remove the tree. I have removed trees from the terrain before but the script keeps refreshing them back in.

    Any help would be greatly appreciated.
     
  32. Jaqal

    Jaqal

    Joined:
    Jul 3, 2014
    Posts:
    288
    @auroxi I actually stopped using unity's terrain trees for the most part and started using prefabs and LOD's. Once you get them set up its much easier to interact and still get decent fps. I'm still pretty new though so some of these other guys probably have more to share about the tree system.
     
    Last edited: Jul 24, 2014
  33. auroxi

    auroxi

    Joined:
    Dec 31, 2012
    Posts:
    85
    Ignore the above, I've got it all working perfectly with absolutely 0 frame loss. It's actually performing better as it's only drawing trees within the camera view (plus some distance for prediction and errors). I have it working with 12 different tree prefabs, it chops down perfectly at random directions, it gives me loot and plays a chopping sound. All was placed with the 'Place mass trees' using the terrain object. There is 0 freezes, no lag, no delay, no changing heightmaps, no messing with any custom LOD's, nothing. I don't even need a blank tree cube object! Absolute perfection and confident it would work with near infinite trees providing that the camera doesn't have to draw them all at the same time in the same view (maybe Umbra culling would work in this situation anyway?).

    The only thing it's not doing right now is growing a tree back but that's irrelevant for my game anyway.

    Thanks again
     
  34. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Sweet, glad it's working so well! I've been distracted by a second project but I hope to get back to tree-wrangling soon.
     
  35. Rico21745

    Rico21745

    Joined:
    Apr 25, 2012
    Posts:
    409
    Hey folks dropping in to say that I too have found a deep hatred for Unity's tree/grass system upon seeing how bad my framerate gets in anything resembling a forest and would like to help create something better where I can.

    I think jc_lvngstn was probably onto the right approach with using DrawMesh and then having trees around the player be turned into GameObjects. I can tell you from experience that the Unity editor does not take kindly to having thousands of GameObjects present in the scene and will often crash out of memory.

    Here are my thoughts on this:

    For Rebirth I am splitting the terrain into chunks. Each chunk is approx 225 units big, so relatively small in size. The chunks gets streamed in and out of the scene as the player walks around, loading terrains only when within the camera range (so if my camera far distance is 200, loads up terrains/chunks within 200 units as well).

    I am hitting some walls with performance due to trees/grass and I too have noticed how GO trees seem to perform better than Terrain trees for some reason, but suffers from not being able to place massive number of trees. I think that if we combine the following ideas, we could potentially end up with a solution that works for most people:

    1) Use Billboards for really far trees (can we use draw mesh to make billboards?)
    2) Use DrawMesh to draw the 3d trees far away from player/camera
    3) Based on a script you can attach to any gameobject/npc, swap the DrawMesh trees for GameObjects with colliders whenever they are X distance from the GO with the script

    Now the question is, can we batch trees and vegetation in any way? I have Lars's AFS but I haven't dug into it yet, but to me it seems like if we can somehow take advantage of batching for trees, we could probably get a huge performance boost.
     
  36. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    For distant trees dense where you want dense forests...I honestly don't see a solution other than batching them, and have a shader that billboards the individual polys. This means you probably won't get the fancy tree billboards that show different orientations of the trees. Meh, these are for DISTANT trees. We are talking tens up to hundreds of thousands of trees. These trees are a blip on FPS, because of low fill rate.

    I think for somewhat near trees that don't need colliders...Drawmesh all the way baby!
    Nearby trees with colliders...probably just simpler to use gameobjects. You could drawmesh them...bu then managing the colliders may be a pain, for trees of different sizes, shapes, etc.

    But back to distant trees. I think unity uses graphics.drawmesh for each individual distant tree billboard, personally. The performance is just too bad.

    Here is a screenshot from a test scene I did a long time ago, using Unity's system. I don't recall the exact fps, but from what I recall it was not good enough for the dense forests I wanted, and the distance. The trees in this picture are not NEAR dense enough for my needs.



    Here is what I get from batching distant trees. Basically...trees are just tall grass. That's all. And these are not even billboards. They are quads, so 4 polys, 8 vertices. If I used true billboarding on the polys, half the polys and verts.



    Using distant batching, drawmesh for medium distance, and gameobjects for nearby:




    You get the idea. I couldn't get this kind of density or distance using the built in solution...but I don't know that many people need that much.
     
    Last edited: Aug 1, 2014
  37. Rico21745

    Rico21745

    Joined:
    Apr 25, 2012
    Posts:
    409
    I'd love to pick your brain as to the approach you're using in that last shot. We've decided to ditch the Terrain trees and go with the GameObject/batching approach but as you said, for distant trees it sounds like DrawMesh is the way to go.

    How are you managing your tree objects and deciding when to switch them from Mesh to GO trees? I'm guessing some sort of TreeManager script that cycles through each tree and decides to how to draw them every X seconds?
     
  38. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    Yes, that's pretty much it. When chunks of terrain tree data are sent to the client, the tree's data structures containing their info are added to a list. The "TreeManager" script loops through these.

    Every 150 milliseconds or so, it checks each tree inside the loop to see if it is outside the far range for mesh trees. If so, this means it will be draw by the distant tree batching, which batches all simple distant trees into big meshes. I also remove it from the tree list.

    If it is inside the distant range but outside the high detail range, this means it is a "medium detail" tree and doesn't need to be a gameobject with a collider. I flag its detail level as Medium detail level. If it was a high detail tree before, I ditch the gameobject also and flag it as medium detail.

    If it is now inside the high detail area, and wasn't before, a tree gameobject is created and it is flagged as a High detail tree.

    So medium detail trees are drawn using DrawMesh, high detail trees are gameobjects with colliders.

    I'm using pooling for creating and destroying the trees. The high detail area may be the a 64x64 area around the player, so this technically could be at most 4096 trees but really, that would only happen if a tree were place every 4 meters which is extremely dense, so dense a player really couldn't walk through them and wouldn't enjoy the situation anyway. I typically have much less...easily less than a hundred I would say.

    I've been thinking about how to optimize it. I'm thinking about taking the distance check for trees, and the transition between distant, medium, and high detail trees to a separate thread. It would put them in queues maybe, and the main update would just have one list to process...trees drawn using DrawMesh since high detail trees are a gameobject. I haven't worked out the details, but I think it would save some fps.

    I've also thought about just using all graphics.drawmesh...and maybe do something else with the nearby collider handling. But honestly, I think at that point...really, I'm not losing fps due to physics, or tree gameobjects. It's just pure fill rate drawing the trees and vegetation. At some point, a dense mid to high detail forest just takes a lot of ooooomph no matter how tight your drawing loop is, or your transition algorithm.

    Other thoughts...a level of detail between mid and distant. Not full mesh trees, but not really batched into distant meshes either. Maybe a VERY simplified tree that isn't quite a billboard quality tree. Very simple trunk, a very small number of leaves. Still drawn individually with Drawmesh. Maybe just a high quality billboard. Not sure yet.
     
  39. Ebolinux

    Ebolinux

    Joined:
    Jan 23, 2014
    Posts:
    117
    Hi there, I have been having a lot of problems with FPS slow down from trees & terrains. Do you by chance have a script that can convert terrain trees to the original prefabs? Or have any other information on how to get the FPS up?

    http://forum.unity3d.com/threads/very-low-fps-from-terrains.273643/
     
  40. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Here is a editor script that will do the job, it can also add random rotation and random scale to the trees for a more realistic look.

    Code (CSharp):
    1.  
    2.   private bool randomRotation = true;
    3.    private bool randomScale = true;
    4.    private float scaleMinValue = 0.9f;
    5.    private float scaleMaxValue = 1.1f;
    6.  
    7. void ConvertTerrainTrees()
    8.     {
    9.         TerrainData terrain = Terrain.activeTerrain.terrainData;
    10.         TreeInstance[] treeInstances = terrain.treeInstances;
    11.         List<TreeInstance> TreeInstances = new List<TreeInstance>();
    12.         float treeRot = 0;
    13.         GameObject go = new GameObject("Trees");
    14.         GameObject[] gos = new GameObject[terrain.treePrototypes.Length];
    15.        
    16.         for (int i = 0; i < terrain.treePrototypes.Length ; i++)
    17.         {
    18.             gos[i] = new GameObject(terrain.treePrototypes[i].prefab.name);
    19.             gos[i].transform.parent = go.transform;
    20.         }
    21.        
    22.         for (int i = 0; i < treeInstances.Length; i++)
    23.         {
    24.             TreeInstance myTree = treeInstances[i];
    25.             Vector3 treePos = new Vector3(myTree.position.x * terrain.size.x, myTree.position.y * terrain.size.y, myTree.position.z * terrain.size.z);
    26.            
    27.             if(randomRotation)
    28.                 treeRot = UnityEngine.Random.Range(0.0f, 360.0f);  
    29.  
    30.             GameObject tempTree = (GameObject)Instantiate(terrain.treePrototypes[myTree.prototypeIndex].prefab, treePos, Quaternion.Euler(new Vector3(0, treeRot, 0)));
    31.            
    32.             if(randomScale)
    33.                 tempTree.transform.localScale *= UnityEngine.Random.Range(scaleMinValue, scaleMaxValue);
    34.            
    35.             tempTree.transform.parent = gos[myTree.prototypeIndex].transform;
    36.         }
    37.         terrain.treeInstances = TreeInstances.ToArray();
    38.     }
     
  41. ZenMicro

    ZenMicro

    Joined:
    Aug 9, 2015
    Posts:
    206
    Hi @jt_lvngstn,

    I found this thread and it's been abandoned it seems, can i ask where you guys all ended up with this project?

    I have been trying to find a way to use Xfrog trees in Unity, They are very high poly (just checked the largest of a species - they come in about 9 sizes from young to fully grown) is 187,000 polygons! but i purchased over 300 trees and they are really nice - but not very usable.

    I know SpeedTree is now here, but they do not play nice with others and do not allow for any import of other companies trees.. so they are out of the question.

    Unity trees is limited and even with Assets from @forst it appears there will be issues.

    I am informed that Xfrog will be releasing a pack of trees modified to work as Unity trees, but am not sure they will cover the species i purchased, also not sure on there approach - simple Unity trees i am guessing, It would be better if thre was a plugin that would allow their trees to work with LOD and Wind... no idea.

    Anyone know Xfrog trees and got them to work in Unity?
     
  42. Gua

    Gua

    Joined:
    Oct 29, 2012
    Posts:
    455
    I've discovered another disadvantage of using trees as gameobjects. I'm suing TreeCreatorTrees with billboard made with Amplify Impostor. While gameperformance stays the same, scene view fps get halved.
     
    AntonioModer likes this.