- Home /
How to create billboard version of a tree?
I want to create a billboard version (for LOD) of my trees programmatically.
Unity does that automatically when trees are placed on a terrain, but I don't use Unity's terrains, that's why I need to make it by myself.
So, what would be the best way to create a billboard version of a tree?
Thanks!
Answer by Casto · Aug 14, 2013 at 02:41 PM
I think I found what I need. In case someone else is interested, I found a script showing how to generate a billboard from any object:
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);
}
}
Hi Castro, I'm working on the same issue, I found the same script. I got the 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?
If you've progressed further than this with your work on tree billboards, I would love to see what you've accomplished and work with you in progression.
I overcame the issue by simply changing the shader to transparent/diffuse.
Answer by Twobitboolean · Mar 16, 2017 at 08:27 PM
I've modified the first c# codes and is currently working with Unity 5.5.0f3. My changes are commented with //**. Important: For this to work you must not have any skybox. Go to Window>>Lighting>>Scene>>Skybox and set it to none!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Script_Billboard_Create : 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;
//**bool to only conver once
private bool grab = false;
void Start()
{
CameraSetup();
}
void OnPostRender()
{
if (!grab) { ConvertToImage(); grab = true; }
}
//**split into two methods
void CameraSetup()
{
//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);
//**manually set the background color
cam.backgroundColor = new Vector4(0,0,0,0);
//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);
}
void ConvertToImage()
{
var tex = new Texture2D(imageWidth, imageHeight);
// 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
Camera cam = Camera.main;
Color bCol = cam.backgroundColor;
Color alpha = new Vector4(0,0,0,0);
alpha.a = 0.0f;
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++)
{
Color c = tex.GetPixel(x, y);
//**check for difference
if (c.r != bCol.r)
tex.SetPixel(x, y, new Vector4(c.r, c.g, c.b, 1));
}
}
tex.Apply();
// Encode texture into PNG
byte[] bytes = tex.EncodeToPNG();
Destroy(tex);
//**path is in Assets, you must refresh Unity to see the file (can be done by clicking away then click on Unity window again, etc)
System.IO.File.WriteAllBytes(Application.dataPath + "/billboard.png", bytes);
}
}
Answer by thieum · Feb 18, 2016 at 02:03 PM
Interesting script, but not working for me in Unity 5 or 4.6 neither. The .js version found in another thread works... but with plain textures only (alpha is discarded, which makes it useless when you apply this to meshes using transparent textures.
But I found a workaround : change this single line as below :
if (c.r == bCol.r || c.a != 1)
(Last be sure to set up a camera looking in world z axis, and you'll find your png at the very root of your project folder)
#pragma strict
/*
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
*/
var objectToRender : GameObject;
var imageWidth : int = 128;
var imageHeight : int = 128;
function Start()
{
if (!objectToRender) return;
//grab the main camera and mess with it for rendering the object - make sure orthographic
var cam : Camera = Camera.main;
cam.orthographic = true;
//render to screen rect area equal to out image size
var rw : float = imageWidth; rw /= Screen.width;
var rh : float = imageHeight; rh /= Screen.height;
cam.rect = Rect(0,0,rw,rh);
//grab size of object to render - place/size camera to fit
var bb : Bounds = 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.z = -1.0 + (bb.min.z * 2.0);
//make clip planes fairly optimal and enclose whole mesh
cam.nearClipPlane = 0.5;
cam.farClipPlane = -cam.transform.position.z + 10.0 + bb.max.z;
//set camera size to just cover entire mesh
cam.orthographicSize = 1.01 * Mathf.Max( (bb.max.y - bb.min.y)/2.0, (bb.max.x - bb.min.x)/2.0);
cam.transform.position.y += cam.orthographicSize * 0.05;
//render
yield new WaitForEndOfFrame();
var tex = new Texture2D( imageWidth, imageHeight, TextureFormat.ARGB32, false );
// Read screen contents into the texture
tex.ReadPixels( Rect(0, 0, imageWidth, imageHeight), 0, 0 );
tex.Apply();
//turn all pixels == background-color to transparent
var bCol : Color = cam.backgroundColor;
var alpha = bCol;
alpha.a = 0.0;
for(var y : int = 0; y < imageHeight; y++)
{
for(var x : int = 0; x < imageWidth; x++)
{
var c : Color = tex.GetPixel(x,y);
// if (c.r == bCol.r)
if (c.r == bCol.r || c.a != 1)
tex.SetPixel(x,y,alpha);
}
}
tex.Apply();
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
Destroy( tex );
System.IO.File.WriteAllBytes(Application.dataPath + "/../billboard.png", bytes);
Debug.Log("tex saved!");
}
Your answer
Follow this Question
Related Questions
custom tree shading issue 1 Answer
Unity LOD billboard asset example? 3 Answers
Leaf Billboard light issues 0 Answers
Invisible Tree Billboards....???? 1 Answer
Tree shadow problem / billboard trees 3 Answers