Using Tree gameobjects vs Unity's built in system

I accidentally started a thread on this, but in the support forum. I meant for it to be here.

In tests where I am mostly displaying full meshes (not billboards), the Unity tree system appears to be slower than just using tree gameobjects. This is very interesting to me personally, as my project makes heavy use of trees.

I’m going to create a demo project, that allows comparison between the built in tree system vs just using gameobjects, so there can be hard numbers. I may end up providing an asset that packages helpful features, like billboard creation and such. Your assistance would be helpful :slight_smile:

Using trees from prefabs:

Pros:
You get rotation.
You get individual tree colliders, instead of the tree colliders being combined with the terrain. You know exactly which tree you are interacting with.
You can use the LOD system, to have more control over tree detail. High detail trees, then lower ones.
Unity created trees can be used also.
Much easier to work with if your project modifies trees or terrain. Modifying trees has doesn’t require unity to recreate the terrain and its collider.
Supports batching for very low detail trees.

Cons:
Have to have some way to create a billboard of the tree (if you want them).
You see each individual tree instance in the hierarchy…you’d want to parent them to a “Tree” parent so they don’t clutter everything.
Creating them all doesn’t seem as fast as Unity’s (need to verify)
Non-unity trees can have shadows and bumps. But if you want wind ALSO, you will need special shaders.

Using Unity’s system:

Pros:
You don’t have to manage LODs or anything…it automatically creates the billboard, at the correct angle of view.
Built in placement/painting tools.
You don’t actually see all of the individual tree instances.
Appears to create the trees very quickly.

Cons:
No rotation. If you want a large number of trees, this looks bad or it requires you to create multiple models.
The billboards get badly tilted when the camera tilts up and down, looks pretty bad if the billboards are somewhat close.
Only two levels of detail…full mesh and billboard.
Trees and their colliders are merged with the terrain. So you need hackish code if you want to interact with the trees, and it’s not always possible to know exactly which tree you are interacting with.
If your project modifies terrain or trees, unity has to update the whole batch. This causes hitches in gameplay for somewhat complex terrains.

Other thoughts:

I’m not sure if the Unity tree system batches low detail trees, need to see if I can verify this.
I need to see if I can get a shader that allows bumping, shadows, AND wind. This works for Unity created trees, but I’m not having luck getting this on “homemade” trees.
I have a very simple script to create individual trees from the trees painted on a terrain. So you use Unity’s built in tools to place them, then run the script and there are your individual ones.
If it is slower to create the trees from prefabs than Unity’s system, I’m curious to see how much.

I need a script that can automatically create a billboard from a tree. We might even get fancy and get one that can do a tree from different angles, but that’s going to be a little more complicated. Storing different tree billboards in an atlas, which means a tradeoff for billboard quality. It might not really be worth it when billboards are pretty far off.

I don’t see how to set LOD distances in the Unity scripting guide. I would have thought you could set the distance for each LOD stage, but I’ve done some quick searching and it looks somewhat complicated and confusing to setup via scripts. If anyone could shed some light on this…

Anyway…any thoughts or suggestions, corrections are welcome.

1 Like

You dont set LOD distance for the lod group, you set a relative screen hight instead, just look at the reference guide on how its done.

LOD constructor: static function LOD (screenRelativeTransitionHeight : float, renderers : Renderer[ ]) : LOD
And in the example you can see how they use it: lods = new LOD(1.0F / (i + 1), renderers);
They set the relative screen hight using the formula “1.0F / (i + 1)” were i is the current LOD, so a low LOD gets a higher number and will switch closer to the screen than a higher LOD.
Maybe this was not what you asked for, but anyways : D
Edit: Btw, if there was some external software that can make LODs and/or billboards that would also help.

Thanks, Virror. That seems very confusing to me. It’s easier for me to think of it in terms of distance…50 meters for LOD 2, 150 meters for LOD3, etc. I’m not sure how to “translate” that into their system.

As far as the billboards…I wonder if a script could do this, with by just rendering the tree to a texture with a transparent background and saving it as a prefab.

Well, i think its better to use screen size as you can use pretty much the same values even if the models are of different sizes since smaller objects usually can be closer before they switch, but i agree its a bit confusing to think about it that way, hope it help you a bit at least : p I think its easier to scrap thinking about distances and just trying to imagine the object on the screen and think about how big it should be before it should switch. Also trial and error will probably help a lot : D

Also, i found this model to billboard script that seems to be just what we need for this: http://forum.unity3d.com/threads/68644-LOD-change-to-billboard-at-a-distance-billboard-generation
Should be easy enough to run that from the editor once for each model or something, if it works that is, have not tested it.

Edit: Working on a C# conversion now so i can test it out : )

Enjoy!

Edit: Cant get the c# one to work, but the js script works kind of. Just place the mesh in the scene, set the reference and add a light. Problem is that only trunk shows in image for some reason. Have to go home now, will look more on this when i get home : )

using UnityEngine;
using System.Collections;

public class TreeToBillboard : MonoBehaviour 
{
	/*
	Make a billboard out of an object in the scene
	The camera will auto-place to get the best view of the object so no need for camera adjustment
	
	To use - place an object in an empty scene with just camera and any lighting you want.
	Add this script to your scene camera and link to the object you want to render.
	Press play and you will get a snapshot of the object (looking down the +Z-axis at it) saved out to billboard.png in your project folder
	Any pixels colored the same as the camera background color will be transparent
	*/

	public GameObject objectToRender;
	public int imageWidth = 128;
	public int imageHeight = 128;
	
	void Start()
	{
		if(objectToRender)
			ConvertToImage();
	}
	
	IEnumerator ConvertToImage()
	{
	    //grab the main camera and mess with it for rendering the object - make sure orthographic
	    Camera cam = Camera.main;
	    cam.orthographic = true;
	    
	    //render to screen rect area equal to out image size
	    float rw  = imageWidth; 
		rw /= Screen.width;
	    float rh = imageHeight; 
		rh /= Screen.height;
	    cam.rect = new Rect(0,0,rw,rh);
	    
	    //grab size of object to render - place/size camera to fit
	    Bounds bb = objectToRender.GetComponent<Renderer>().bounds;
	    
	    //place camera looking at centre of object - and backwards down the z-axis from it
	    cam.transform.position = bb.center;
	    cam.transform.position.Set(cam.transform.position.x, cam.transform.position.y, -1.0f + (bb.min.z * 2.0f));
	    //make clip planes fairly optimal and enclose whole mesh
	    cam.nearClipPlane = 0.5f;
	    cam.farClipPlane = -cam.transform.position.z + 10.0f + bb.max.z;
	    //set camera size to just cover entire mesh
	    cam.orthographicSize = 1.01f * Mathf.Max( (bb.max.y - bb.min.y)/2.0f, (bb.max.x - bb.min.x)/2.0f);
	    cam.transform.position.Set(cam.transform.position.x, cam.orthographicSize * 0.05f, cam.transform.position.y);
	
	    //render
	   	yield return new WaitForEndOfFrame();
	    
	    var tex = new Texture2D( imageWidth, imageHeight, TextureFormat.ARGB32, false );
	    // Read screen contents into the texture
	    tex.ReadPixels(new Rect(0, 0, imageWidth, imageHeight), 0, 0 );
	    tex.Apply();
	
	    //turn all pixels == background-color to transparent
	    Color bCol = cam.backgroundColor;
	    Color alpha = bCol;
	    alpha.a = 0.0f;
	    for(int y = 0; y < imageHeight; y++)
	    {
	        for(int x = 0; x < imageWidth; x++)
	        {
	            Color c = tex.GetPixel(x,y);
	            if (c.r == bCol.r)
	                tex.SetPixel(x,y,alpha);
	        }
	    }
	    tex.Apply();
	
	    // Encode texture into PNG
	    byte[] bytes = tex.EncodeToPNG();
	    Destroy( tex );
	    System.IO.File.WriteAllBytes(Application.dataPath + "/../billboard.png", bytes);
	}
}
1 Like

I was thinking to this since ever. First of all because the tree system in Unity is odd to use.

Just tried recently again and guess what, even a simple thing like the texture for some leaves is messed up. Can’t set up UV properly and I’m not the last noob working with meshes, I’m a modeler trying to use the built in system. It’s simply that there seems to be no documentation about the features or oddities.
Asked for info in the forums, nobody seems to know anything about this. And it’s fun, because I just set up a bunch of leaves in the center of a texture and they look offset by .5 or something for some reason. Tried to move them into half texture, no way.

Then there are more problems with the shaders. Like the translucency that remains active even when there are no lights in the scene. This was posted by a guy in the forum, I didn’t test it, but I noticed that the shader is also very difficult to use or plain bugged, always giving too light or too dark trees.

Then there are the billboards: they distort the mesh if they are near, because of course they have to adapt to perspective from being flat, so you can’t use billboards from near, and in fact they were never conceived for this type of use.
On the other side, when the trees in Unity are far, they SHRINK the damn leaves if you use billboards or some types of leaves.
BUT the billboard is calculated on the FULL foliage! So when the billboard comes it totally POPS out in the full glory of the tree, wasting half of the reason to be in existence: smooth transition from full detail to low detail.
So you cannot even use some type of foliages.

Another reason: you CAN’T close the bottom of the trees.
So you put collider in trees, but if you make them fall you will see the culled inner of the mesh, which destroys the reality immersion.
A stupid feature that is missing for some stupid reason.

LOD. You can very easily create LODs of the trees you generate inside Unity, BUT you can’t use them in the trees system! That’s so dumb too.

You have also put up a good list of pro and vs.

Maybe it’s missing that, I’ve read somewhere, Unity terrain and trees are optimized in a way that terrain HIDES trees behind hills, which is pretty useful in some cases.

And one thing I don’t know is if Unity batches all the trees of one type before and send them in a single drawcall, that would also save a huge number of drawcalls. But it would eat some CPU on the other side.

Now, the thing is, I didn’t tested this stuff properly BUT:

  • if I can’t use the billboard leaves
  • if I can’t use LODs
  • if I can’t use billboard impostors
  • if I can’t use colliders

Then what the heck would I use Unity trees for?
Only for the terrain culling system?
No, because with something like InstantOC I can help myself by placing some occluders under the hills as well.
A bit more work, that’s sure, but I can overcome that within one day.

So now a little examination about my game.
I need the leaves to NOT shrink in distance because the players can hide in bushes and they CAN’T change their coverage.
I need to see the bottom of trunks of fallen trees because in my game they will easily fall down.
And after all I don’t need thousands of trees, I am more on the order of 100-200 trees on the whole map.

Now, I really think I’m going to test Unity trees vs mesh trees very soon because I need to decide what to use finally.

What I was looking for, was also a well done impostor script.
The impostor in Unity looks like it’s projected on a grey background 128,128,128 and has some 1 px line of grey all around, another reason that makes the Unity system impostors practically unusable if you want a clean professional visual.

If you can get that impostor script to work, that would be really great :slight_smile:

1 Like

Working on it! : p
Some really strange issues with the alpha it seems, even when just grabbing the texture from the screen without doing the for loop that sets alpha i get strange stuff going on. Any help would be great : )

Strange things mentioned here I didnt know of,

Also, don’t forget that the lighting of the billboard won’t be updated if your lighting setup changes (day/night cycle), or has that been fixed lately? That was enough reason for me to switch over to gameObject trees (well, maybe also the hassle of determining which tree to interact with in the Unity terrain), not to mention all the other problems and “features” which fail in doing their thing properly… Personally, I wouldn’t even bother doing these tests, since meshes will be way better if you can get the draw call amount to an acceptable level and have a decent LOD system

Lightning issue is simple to solve, just use the billboard shader from the free ats package on the asset store : )
We need to do a bunch of tests, if not just because its very interesting : p

So, 2000 trees visible, 3.3 Mil triangles, for a total of 4000 drawcalls get batched to 6 drawcalls, and I am on 75 fps, and this is cool.
I didn’t even put in any LOD, and I used a single shader for the tree.

The problems come when you get IN the forest, fps get down to 25 because of the huge overdraw, but with some LODs and the impostors that should also get a hit.

And anyway, at least for me this is not a problem, since I don’t need to build dense forests.

BTW I am on a laptop. And even if, yes, this is not a low level laptop, because it’s a i7, the graphic board is still not comparable to the ones of desktop PCs.

First: Sorry jc for stealing your thread : p
Second: Thanx jc for all the inspiration, still interested in a cooperation : )

megmaltese: Nice! Not that surprising though really, unitys terrain system is no magic, its mostly for making it easy to set up.
I have a nice system in mind, this is what i can thought of now:

-Automatic billboard creation.
-Automatic LOD group creation. Click a button and your LOD groups will be created for you with dynamic amount of stages by searching for tree names with fixed endings. Also make billboard here.
-Easy placing. Place your trees as usual with unitys tree creator and press a button and it will be converted to mesh trees based on tree names

Something like that, sounds nice?

1 Like

I share your frustration, megmaltese. I haven’t experienced all of the issues you have, but a lot of them. Bad billboarding perspective. Open bottom of trees.

As far as terrain occlusion is concerned…seems like you could cast two rays, one at the top left “corner” of the tree and one at the top right corner. If both of this hit terrain…the tree is probably behind the landscape.

So…initial feature set would be something like:

An inspector UI, that allows you to convert built in terrain trees to gameobjects, placing them under children of a “TreeParent” gameobject.
With the option to apply random rotation on the Y axis.

A UI option to create a billboard from a tree prefab.

Nice to have’s:
Be able to have a list of prefabs to create from the list of trees assigned to the terrain. Currently, if you try to use a LOD group to paint on the terrain, you won’t see anything painted. This way, you could use say a pine tree, but in the matching list would be the prefab for correct LOD group prefab.

A script to close the bottom of trees created from Unity trees. You could supply a texture for the bottom, and it would just add a submesh to close the vertices and use that texture. Not ideal, but better than a gaping hole.

How is your performance for this, megmaltese:

https://dl.dropboxusercontent.com/u/174731243/WebPlayer/WebPlayer.html

Uh I don’t know, for my personal point of view I’ll go with Unity LOD, which should be quite efficient, and it already has built in name based system.
The addition could be that the last LOD level is the billboard and make it work seamlessly with in the Unity LOD system.

Transforming Unity terrain trees to mesh trees is maybe a good idea but may reveal somewhat cumbersome, but still better than placing all trees one by one by hand.

The most important thing anyway is an impostor script that does a GOOD rendering, without that grey silhouette line.
I know it’s probably not trivial to realize, but that’s what’s most needed.

Im talking about the built in unity LOD groups here, just the thing that you dont have to do the dragging, just follow a naming conversion and it will be taken care of.

The terrain trees to mesh tress thing should be trivial, most ppl are used to that and making the conversion is easy, user just have to press a button or something similar.

Imposters should also be pretty easy if i just could figure out whats wrong with the alpha…
jc, maybe you could take a look at that script as well? : p

Eh, 3-5 fps… but that’s normal with webplayer. Webplayer is not comparable to stand alone build.

Solid 50, with some drops to 40 seldom : )

Working on a simple Benchmark scene, will make 4 different:
Terrain trees, all full mesh
Terrain trees, half mesh, half billboard
Mesh trees, all full mesh
Mesh trees, half full mesh, half billboard

Why wont i get any batching at all when using the built in Unity trees?
4096 trees gives me 30000 drawcalls O.O

The script looks interesting, I’ll have to do testing when I get home. I’m not able to do anything with it for a few hours.

The script to swap out terrain trees with the original prefabs is pretty simple, I can post it tonight. From memory (pseudocode):

function CreateTrees(Terrain terrain)
{

foreach (TreeInstance tree in terrain.TerrainData.TreeInstances)

  {

    Vector3 treeWorldPosition = tree.Position * terrain.TerrainData.Size + terrain.transform.Position;
     Instantiate(tree.Prototype.Prefab, treeWorldPosition, Quaternion.Identity);

  }


}

Or something pretty similar. I can put something more accurate on tonight!