@username Bit of a necrobump but for a good answer:
//*****************************************************
// <<<Class Purpose>>>
// Enable the creation of billboards for 2D graphics
// in 3D space. Choice of flat, spherical or arbitrary
// axis aligned billboards. Corrects for camera roll.
//*****************************************************
// Using namespaces
using UnityEngine;
public class A3DBillboard : MonoBehaviour {
//*** CONSTANTS ***
public enum A3DBillboardType
{
Flat, // Inverse camera rotation
Sphere, // Looks directly at camera
Axial // Swivels around defined axis
}
//*** INSPECTOR FIELDS ***
[SerializeField] private Vector3 _vAxis = Vector3.up; // Axis for arbitrary rotation
[SerializeField] private A3DBillboardType _billboard = A3DBillboardType.Sphere; // Test if pitch control is clamped
[SerializeField] private bool _correctRoll = true; // Correct for camera roll
//*** LOCAL VARIABLES ***
private Vector3 vLook; // constructed billboard forward vector
private Vector3 vRight; // constructed billboard right vector
private Vector3 vUp; // constructed billboard up vector
private Transform billboardTransform; // link to billboard object transform
private Transform cameraTransform; // link to camera object transform
// Use this for initialization
void Start()
{
billboardTransform = this.transform;
cameraTransform = Camera.main.transform;
}
// Update is called once per frame
void LateUpdate()
{
if (_billboard == A3DBillboardType.Flat)
{
// Flat billboards opposite rotation to camera
billboardTransform.rotation = Quaternion.LookRotation(cameraTransform.forward, cameraTransform.up);
// Check if correct for camera roll
if (_correctRoll)
{
Vector3 CameraRotation = cameraTransform.eulerAngles;
if (CameraRotation.z != 0) { billboardTransform.Rotate(0f, 0f, -CameraRotation.z); }
}
}
else if (_billboard == A3DBillboardType.Sphere)
{
// Spherical billboards look at camera position
//MyTransform.LookAt(MyCameraTransform.position, MyCameraTransform.up);
//MyTransform.Rotate(new Vector3(0f, 180f, 0f));
// create billboard look vector
vLook = billboardTransform.position - cameraTransform.position;
vLook.Normalize();
// create billboard right vector
vRight = Vector3.Cross(cameraTransform.up, vLook);
// create billboard up vector
vUp = Vector3.Cross(vLook, vRight);
// spherical billboard with look direction towards camera
billboardTransform.rotation = Quaternion.LookRotation(vLook, vUp);
// Check if correct for camera roll
if (_correctRoll)
{
Vector3 CameraRotation = cameraTransform.eulerAngles;
if (CameraRotation.z != 0) { billboardTransform.Rotate(0f, 0f, -CameraRotation.z); }
}
// create the billboard matrix
// M = D3DIdentityMatrix()
// M.rc11 = vRight.X: M.rc12 = vRight.Y: M.rc13 = vRight.z
// M.rc21 = vUp.X: M.rc22 = vUp.Y: M.rc23 = vUp.z
// M.rc31 = vLook.X: M.rc32 = vLook.Y: M.rc33 = vLook.z
}
else if (_billboard == A3DBillboardType.Axial)
{
//create temporary billboard look vector
vLook = billboardTransform.position - cameraTransform.position;
vLook.Normalize();
//create billboard right vector
float visible = Mathf.Abs(Vector3.Dot(_vAxis, vLook));
if (visible >= 1)
{
// look vector is parallel to axis
vLook = _vAxis;
}
else
{
// create and normalize right vector
vRight = Vector3.Cross(_vAxis, vLook);
vRight.Normalize();
// create final billboard look vector
vLook = Vector3.Cross(vRight, _vAxis);
// create billboard up vector
vUp = Vector3.Cross(vLook, vRight);
// axial billboard with look rotation axis aligned
billboardTransform.rotation = Quaternion.LookRotation(vLook, vUp);
}
// create the billboard matrix
// M = D3DIdentityMatrix()
// M.rc11 = vRight.X: M.rc12 = vRight.Y: M.rc13 = vRight.z
// M.rc21 = vAxis.X: M.rc22 = vAxis.Y: M.rc23 = vAxis.z
// M.rc31 = vLook.X: M.rc32 = vLook.Y: M.rc33 = vLook.z
}
}