-
Notifications
You must be signed in to change notification settings - Fork 75
Expand file tree
/
Copy pathBillboard.cs
More file actions
137 lines (114 loc) · 4 KB
/
Billboard.cs
File metadata and controls
137 lines (114 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* Implement a basic billboard component.
* Author: Ronen Ness.
* Since: 2017.
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace NesScripts.Graphics
{
/// <summary>
/// Different ways to rotate billboard.
/// </summary>
public enum BillboardRotationType
{
/// <summary>
/// Always face the camera on all axis.
/// </summary>
Absolute,
/// <summary>
/// Rotate horizontally only, based on camera angle.
/// </summary>
HorizontalCameraDirection,
/// <summary>
/// Rotate horizontally only, based on camera position.
/// </summary>
HorizontalCameraPosition,
/// <summary>
/// Rotate horizontally only, based on camera angle and position.
/// This yield the best results, but have the worse performance. Use this on large billboards.
/// </summary>
HorizontalMixed,
}
/// <summary>
/// Make the entity always face camera, either with one axis locked, or with all axis.
/// This basically implements a simple billboard.
/// </summary>
public class Billboard : MonoBehaviour
{
// how to rotate the billboard
public BillboardRotationType RotationType = BillboardRotationType.HorizontalMixed;
// caching the camera object
Camera cam;
/// <summary>
/// Get angle between two points.
/// </summary>
private float Angle(Vector3 from, Vector3 to)
{
Vector2 p1 = new Vector2(from.x, from.z);
Vector2 p2 = new Vector2(to.x, to.z);
float ret = Mathf.Atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Mathf.PI;
return ret;
}
/// <summary>
/// Get the angle needed for rotation to camera position.
/// </summary>
private float AbsAngleToCam(Vector3 camPos)
{
float ret = -Angle(cam.transform.position, transform.position) + 90;
return ret;
}
/// <summary>
/// Get avarage between two angles.
/// </summary>
private float AvgAngles(float a, float b)
{
return Mathf.LerpAngle(a, b, 0.5f);
}
/// <summary>
/// Init the component.
/// </summary>
void Start()
{
cam = Camera.main;
}
/// <summary>
/// Make object face camera.
/// </summary>
void Update()
{
// rotate billboard based on rotation type
switch (RotationType)
{
// absolute rotation
case BillboardRotationType.Absolute:
transform.rotation = cam.transform.rotation;
break;
// horizontal angle-based
case BillboardRotationType.HorizontalCameraDirection:
Vector3 rot = cam.transform.rotation.eulerAngles;
rot.x = 0; rot.z = 0;
transform.rotation = Quaternion.Euler(rot);
break;
// horizontal position-based
case BillboardRotationType.HorizontalCameraPosition:
transform.rotation = Quaternion.Euler(new Vector3(0, AbsAngleToCam(cam.transform.position), 0));
break;
// horizontal mixed (position + rotation)
case BillboardRotationType.HorizontalMixed:
// get camera-based rotation
Vector3 camRot = cam.transform.rotation.eulerAngles;
camRot.x = 0;
camRot.z = 0;
// get angle-based rotation
float angle = AbsAngleToCam(cam.transform.position);
// avarage results
camRot.y = AvgAngles(camRot.y, angle);
// apply rotation
transform.rotation = Quaternion.Euler(camRot);
break;
}
}
}
}