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:
-
import your tree asset or create one using the built in tree creator.
-
create an empty game object in your scene
-
attach a mesh filter
-
attach a mesh renderer
-
now drag the mesh from your tree prefab in the “project” tab to the new gameobject in the “hierarchy” tab.
-
go to its mesh renderer component and set its number of materials → size: 2
-
drag the materials “optimized bark material” and “optimized leave material” from the original tree to the 2 slots “element 0” and “element1”
-
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);
}
- hitting “play” now gives us a bending tree, wow.
- 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.