Search Unity

batching trees – and speed up rendering

Discussion in 'Made With Unity' started by larsbertram1, Jun 7, 2012.

  1. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    bad news first:
    * the method described below only works with trees not placed within unity’s built in terrain engine
    * it only works with trees made with the built in tree creator but not with imported models using the soft occlusion shaders
    * it will let you set up directional wind but no radial wind zone
    * some advantages you will only get if you own unity pro

    good news later:
    * in case you have any manually placed tree models – be it completely manually as single game objects or via a tool like t4m this workaround might save you a lot of draw calls by enabling batching and occlusion culling on trees modeled with the tree creator giving you nicely lightened trees bending in the wind.


    12 ordinary trees created with the tree creator (taken from the standard assets): 89 draw calls, batched: 0, 1.9ms rendering time:

    $01_trees_standard.jpg


    12 trees using the method described below and static batching (unity pro only): 74 draw calls, batched: 21, 1.7ms rendering time:

    $02_trees_batched.jpg


    12 trees using the advanced "combine children" script (unity indy and unity pro): 13 draw calls, batched: 0, 0.8ms rendering time:

    $03_trees_combined.jpg


    but now let’s get started

    why don’t trees created with the tree creator get batched?
    to be honest: i don’t really know. but something in the tree-script seems to keep them from being batched. my personal opinion: it’s the wind. but we will come to this later.

    so the most important part of this workaround is to get rid of the tree script, which turned out to be pretty easy by just applying the the generated tree mesh to another game object. these are the steps:


    workaround:

    1. import your tree asset or create one using the built in tree creator.

    2. create an empty game object in your scene
    3. attach a mesh filter
    4. attach a mesh renderer

    5. now drag the mesh from your tree prefab in the "project" tab to the new gameobject in the "hierarchy" tab.

    5. go to its mesh renderer component and set its number of materials -> size: 2
    6. drag the materials "optimized bark material" and "optimized leave material" from the original tree to the 2 slots "element 0" and "element1"

    7. now you should already see your tree in the scene / game tab. but although you might already have set up a wind zone there will be no bending when hitting "run".
    as i mentioned before wind and wind zones seem to be connected to the tree script and as this is missing on our new gameobject we will see no bending at all. for this reason we will have to pass our own wind parameters to the shader.
    do so using a simple js script also used on the afs and ats mobile foliage shaders and attach it to any game object within your hierarchy.

    Code (csharp):
    1.  
    2. var Wind : Vector4 = Vector4(0.85,0.075,0.4,0.5);
    3. var WindFrequency = 0.75;
    4.  
    5. function Start ()
    6. {
    7.     Shader.SetGlobalColor("_Wind", Wind);
    8. }
    9. function Update () {
    10.     // simple wind animation
    11.     var WindRGBA : Color = Wind *  ( (Mathf.Sin(Time.realtimeSinceStartup * WindFrequency)));
    12.     WindRGBA.a = Wind.w;
    13.     Shader.SetGlobalColor("_Wind", WindRGBA);
    14. }
    15.  
    7. hitting "play" now gives us a bending tree, wow.
    8. add a capsule collider and adjust it, mark the game object as "static", create a new prefab in the "project" tag a drag your "gameObject" or tree from the "hierarchy" to the prefab in the "project" tab. now you have a new prefab of your tree that will be batched!


    setup static batching (pro only):
    just make sure that all instances of your prefab as marked as "static" – that’s all.


    speeding it up even more (indy and pro):
    in case you have small clusters of trees all sharing the same material you can even optimize performance more by combining the tree’s meshes into one within the editor. for this you will need the "advanced combine children" script written by neodrop which combines meshes not only at runtime but even right within the editor.
    you can find the script here:
    http://forum.unity3d.com/threads/37721-Combine-Children-Extented-(sources-to-share)

    do so by adding a game object right to the center of your cluster.
    make all models within a radius of 10-20 m to children of the new game object and assign the script to it. check all the boxes you want, then choose "combine now" from the dropdown in the upper right corner of the script component (where you usually find the "remove component" command).
    remove the script afterwards, set the gamobject to "static" and assign it to an appropriate layer in case you work use different culling distances.

    tip: keep a (deactivated) copy of you not combined gameobject. doing so will enable to edit and recombine it later in case you have to.

    in case you own unity pro you might set the created meshes to "static" and unity will automatically batch all visible clusters to gain performance even more.


    why does static batching only save so few draw calls?
    when using real time shadows like in the images above each tree usually would force 6 draw calls:
    1 diffuse for the bark, 1 diffuse for leaves, 1 for the bark rendered as shadow caster, 1 for the leaves rendered as shadow caster, 1 for the bark rendered as shadow receiver, 1 for the leaves rendered as shadow receiver

    having a look at the images above you will see that our 12 modified trees will give us 21 batches – which should be 24 to make any sense (thumbs up: stat window!). i would think that those are just the both diffuse passes: bark and leaves. shadow casters and shadow receivers do not seem to be batched if you use any kind of vertex animation within your shader – what we do – called bending.

    using combined meshes seems to completely solve this problem – but of course i would never suggest to combine all your trees into one single mesh: the cheapest tree is the one which is completely outside view frustrum! so just try to combine trees which are near to each other creating serveral small clusters.

    but apart from that to that "combining children" seems to increase the number of vertices in an inapproriate way: instead of 192k we get 420k – something for neodrop i guess.
     
    Last edited: Jun 7, 2012
    MatosEncoreMatos likes this.
  2. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Is it worth doing this if we are targeting PC and using Unity's built in Terrain? Changing to GameObjects would mean you'd lose the billboarding of Unity trees, so would the performance gain of batching be worth more than the gain from having billboards?
     
  3. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    given that unitys own foliage system batches and is additionally autooptimized through the terrain visibility logic too, I would doubt it faster.

    But depending on what you want to achieve you can not use the foliage system (as it does not support real game objects and even less prefabs, it only accepts mesh prefabs basically) and then its relevant
     
  4. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I thought larsbertram was saying that Unity doesn't batch trees made with the tree creator if there is wind?
     
  5. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Do we talk about them on terrain or not?
    Cause that makes a major difference, the terrain has a whole different way of handlign it than normal batching which has various requirements.

    Tree Creator trees are a very special case for different reasons and I wouldn't consider them to be targeted at optimized usage in any use case. They are nice cause you can easily create them but that comes at the price of their troublesome nature.

    For batching they are in general far less optimal than the Unity 2 / Unity Terrain Foliage system trees that comply to the nature soft occlusion requirements (2 meshes on the tree, one for bark, one for leaves)

    Also mesh combining is no holy grail for 'batching', its not batching as it would be required for trees where it has to happen dynamically basing on different things.
    Aboves suggestion with combine children is great for drawcalls but has some problems caused by it.
    Because on the other hand the effort to update the mesh will grow massively due to the sheer size of the mesh index buffers. Take an OSX 10.6 machine with one of the non 2011 ATI gpus and you will see how the whole performance goes down, potentially significantly worse than the drawcalls could have caused it at any time due to a pretty beefy driver bug with high poly models which slows down the rendering over proportionally, worse than you could do it with reasonable drawcall numbers.

    And worst of all the combine children approach prevents reasonable LoD (like the billboarding on terrains) so you need to invest a lot of time to only combine locally close trees so you can replace the whole block for a lower lod level without serious visual popup
     
  6. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    i am really sorry dreamora as i usually appreciate all your comments,

    but this time i really do not get you.

    as i have said very clearly: the method i describe does not work with trees placed within the terrain engine – but with any manually placed tree.

    what kind of troublesome nature are you talking about?
    tree creator trees give you the most advanced bending and lighting within unity, and yes: they are expensive to render, but this is caused by advanced lighting including translucency, bum mapping and specular lighting and the implementation of crytek’s bending functions…
    you really can’t compare old style trees using the soft occlusion shaders with those using the tree creator ones.

    they do not batch at all if you are not using my method… so what are you talking about?
    anyway: trees using the soft occlusion shaders and placed manually in your scene, marked as static will automatically batch right out of the box – but you will never see any bending on them … besides the fact that even if you place them using the terrian engine their bending is more or less some kind of shivering.

    which things?

    i am running os x 10.6.8 on a mc book pro just with the nvidia 9400m gpu enabled – and as you can see on the screenshots above: not even the number of draw calls goes down but even the time the rendering takes – so performance get’s a big boost! the only problem i see is the number of vertices as i have written in my first post.

    as the advanced combine children script runs in the editor you can easily set up your own lod group for combined trees.
    please study my first thread carefully and ask for a package to test it yourself in case you have any doubts.

    lars
     
    Last edited: Jun 8, 2012
  7. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    hi makeshiftwings,

    unity will never batch trees made with the tree creator – if you have a wind zone or not. you will have to get rid of the tree-script in order to have them batched – just like i have described.

    usually: no. i have tried several approaches [like built in LOD] but haven’t found any way to render a huge number of trees faster than the terrain engine does: you just can not compensate the performance gain you get from billboarding unless you write your own billboard function: all mesh trees drawn by the terrain engine will be much more expensive than manually placed trees using my method but the billboards of the terrain engine will do the boost.

    but: think of bushes. having a look at the most successful foliage packages at the asset store even bushes as modeled as "trees". but as they are usually not as high as trees you do not have have them to be rendered in far distances as billboards and might cull them at a distance of – let’s say – 60 meters, which might fit your billboard distance: so all bushes drawn as meshes placed at a layer which gets culled at around your billboard distance will be drawn much faster than bushes placed within the terrain engine.

    another example would be trees placed on manually modeled geometry like cliffs and overhangs. as you can’t use terrain engine trees here you will have to place manually models anyway. doing it using the method described above will give you a massive boost on performace.

    let’s take a real world example: After (Fantasy world 2)http://forum.unity3d.com/threads/122146-After-(Fantasy-world-2)

    botumys uses the tree creator to add vegetaion to the bridge in his scene:http://forum.unity3d.com/threads/122146-After-(Fantasy-world-2)/page6



    pretty clever i think. but as those "trees" are not placed within the terrain engine they would get rendered much faster using the my method then they do now.

    a third example would be "additional trees": imagine you have a forest. of course you want to see it from far away -> billboards -> terrain engine. but you only need a few trees from far away to show the forest to the player. only when entering the forest more trees might become necessary to create the vision of a very dense forest. so just fade in [using a special layer and culling distances] the "additional" trees you need to create a very dense forest and place them as game objects that are batched and/or combined.



    lars
     
    Last edited: Jun 8, 2012
  8. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Thanks for the in-depth explanation! It makes much more sense to me now.
     
  9. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    you are welcome ;-)
     
  10. I am da bawss

    I am da bawss

    Joined:
    Jun 2, 2011
    Posts:
    2,574
    Thanks so much for sharing with us the techniques and models and extensions Lars. You are the best!
     
  11. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900

    thanks for the flowers…
     
  12. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,526
    I guess there is no way to automate this with a script?
    To select all the trees you placed and then place a optimise script?
     
  13. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    manually placed trees or trees within the terrain engine?
    well, within the terrain engine it won’t work at all, but on manually placed trees it should be enough to just change/edit your prefab:
    1. duplicate the original tree prefab (containing the tree script) so you will still keep a version of your original tree
    2. then edit the original prefab and delete all components, which makes all your trees disappear.

    3. follow steps 2. – 6. from the first post, then drag the game object to the original prefab.

    4. now all your manually placed trees should use the new prefab.

    lars
     
  14. kaz2057

    kaz2057

    Joined:
    Jan 18, 2011
    Posts:
    326


    I don't understand the vertex problem when combine children.
    I have this problem when I load a mesh created with tree creator like BigTree. Can you confirm this?
    And have you any solution for this?

    Thanks
     
  15. kaz2057

    kaz2057

    Joined:
    Jan 18, 2011
    Posts:
    326
    OK
    I found the problem.
    Combine Mesh has problem whit tree creator leaves. Can you confirm? There is any solution?
     
  16. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    might be fixed with unity 3.5.3 as the changelog says:
    Graphics: Fixed CombineMeshes() outputting wrong vertex count. This fixes a bug with combined meshes not drawing on some graphics cards.

    i haven’t tested it though.

    lars
     
  17. kaz2057

    kaz2057

    Joined:
    Jan 18, 2011
    Posts:
    326
    Thanks I don't know new unity release.

    Then just another question in tree creator settings.
    a) the LOD quality setting is used just combined with terrain engine? If i place with move tool tree prefab it don't create lod. is right?
    b) With combine mesh how can I create LOD? I need to create many group and apply combine and settings LOD with script using camera distance?

    Thanks
     
  18. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    a) the LOD quality settings of the tree creator directly effects the generated tree mesh – be it placed within the terrain engine or manually.

    b) in case you want to have 2 LODs you would have to create 2 groups of trees: first one containing the high poly meshes, second one containing the low poly trees. next you would combine group 1 and group 2 – then assign them to an empty game model and set up the built in LOD group according to unity requirements.

    lars
     
  19. kaz2057

    kaz2057

    Joined:
    Jan 18, 2011
    Posts:
    326
    a) OK i Tested it. I think that "Lod quality" si referred to some distance or similar values, insted it simply "optimize" the final mesh created.
    b) thanks for the trick :p

    However I suppose to use t4m terrain editor. What do you think about it? It is quite slow as pipeline, because everything is "handmade" like lod, ecc... and not support batch I believe ... but it is more slight ...

    Thanks
     
  20. wangzy_88

    wangzy_88

    Joined:
    Sep 12, 2012
    Posts:
    14
    why those trees don't batched when i use them in unity terrain system as a custom tree?
     
  21. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    the terrain engine does not allow batching of trees – i guess it supposes to work with tree having the tree scripted assigned using the built in wind zones in order to make them bending.

    lars
     
  22. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    I always thought the terrain engine didn't batch trees in the traditional way because of their needing to swap out for billboards on the fly.
     
    twobob likes this.
  23. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    may be you are right – we don’t know as it is undocumented…

    lars
     
  24. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    actually the status screen shows pretty well how it operates under the hood out of my view: Unitys own foliage lod relies on imposters (texture rendered replacements for geometry) that render large amounts of the stuff into dynamic render textures (the number explodes as you raise the foliage density or its view range) and drop the original content completely from the scene. At times this goes even a step further and does not even use the orientational data of the foliage to reduce the number of real imposters required.

    These textures are updated as the camera changes beyond a given threshhold (-> non smooth lod level change between the billboard lod level and the geometry one) which happens along the regular terrain update calculations for the various chunks, their LoD, basetexture etc calcs.

    Thats the reason why its impossible to really compete with this system unless you completely recreate an own terrain system etc, cause the overhead from running the terrain + an own system is pretty heavy as you have to redo the same calc multiple times where the terrain foliage system 'gets it for free'
     
    twobob likes this.
  25. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    hi dreamorea,

    thanks for your explanations – i really agree with all of them.
    but you haven’t given any answer to wangzy_88’s question why (mesh) trees do not get batched within the terrian engine, have you?
    i still believe it is the tree script and the wind/bending-function as those also keep manually placed trees from beeing batched.

    lars
     
  26. Phong

    Phong

    Joined:
    Apr 12, 2010
    Posts:
    2,085
    Hi Lars,

    Thanks for this very informative post and thread. Do you have any more information about how the _Wind property works? I have been playing with your script and it appears that the r,g,b values appear to be some sort of combined displacement scaling value. The alpha value appears to be some sort of pulse frequency. I am curious how these values correspond to the parameters in the wind zone?

    Thanks.
     
  27. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    hi phong,

    you have to study the tree creator shaders to find out how they work: it is a combination of vertex colors (red, green) and 2nd uv set.

    lars
     
  28. Phong

    Phong

    Joined:
    Apr 12, 2010
    Posts:
    2,085
    Thanks!