batching trees – and speed up rendering

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:

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

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

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.

  6. go to its mesh renderer component and set its number of materials → size: 2

  7. drag the materials “optimized bark material” and “optimized leave material” from the original tree to the 2 slots “element 0” and “element1”

  8. 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.

var Wind : Vector4 = Vector4(0.85,0.075,0.4,0.5);
var WindFrequency = 0.75;

function Start ()
{
	Shader.SetGlobalColor("_Wind", Wind);
}
function Update () {
	// simple wind animation
	var WindRGBA : Color = Wind *  ( (Mathf.Sin(Time.realtimeSinceStartup * WindFrequency)));
	WindRGBA.a = Wind.w;
	Shader.SetGlobalColor("_Wind", WindRGBA);
}
  1. hitting “play” now gives us a bending tree, wow.
  2. 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.

1 Like

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?

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

I thought larsbertram was saying that Unity doesn’t batch trees made with the tree creator if there is wind?

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

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

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

Thanks for the in-depth explanation! It makes much more sense to me now.

you are welcome :wink:

Thanks so much for sharing with us the techniques and models and extensions Lars. You are the best!

thanks for the flowers…

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?

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

OK
I found the problem.
Combine Mesh has problem whit tree creator leaves. Can you confirm? There is any solution?

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

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

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

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 :stuck_out_tongue:

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

why those trees don’t batched when i use them in unity terrain system as a custom tree?