-
Notifications
You must be signed in to change notification settings - Fork 162
/
LightShafts.Utils.cs
201 lines (173 loc) · 5.24 KB
/
LightShafts.Utils.cs
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
using UnityEngine;
using System.Collections;
public enum LightShaftsShadowmapMode
{
Dynamic = 0,
Static = 1
}
public partial class LightShafts : MonoBehaviour
{
public bool directional {get{return m_LightType == LightType.Directional;}}
public bool spot {get{return m_LightType == LightType.Spot;}}
Bounds GetBoundsLocal()
{
if (directional)
return new Bounds(new Vector3(0, 0, m_Size.z*0.5f), m_Size);
Light l = m_Light;
Vector3 offset = new Vector3(0, 0, l.range * (m_SpotFar + m_SpotNear) * 0.5f);
float height = (m_SpotFar - m_SpotNear) * l.range;
float baseSize = Mathf.Tan(l.spotAngle * Mathf.Deg2Rad * 0.5f) * m_SpotFar * l.range * 2.0f;
return new Bounds(offset, new Vector3(baseSize, baseSize, height));
}
Matrix4x4 GetBoundsMatrix()
{
Bounds bounds = GetBoundsLocal();
Transform t = transform;
return Matrix4x4.TRS(t.position + t.forward * bounds.center.z, t.rotation, bounds.size);
}
float GetFrustumApex()
{
// Assuming the frustum is inscribed in a unit cube centered at 0
return - m_SpotNear/(m_SpotFar - m_SpotNear) - 0.5f;
}
void OnDrawGizmosSelected()
{
UpdateLightType();
Gizmos.color = Color.yellow;
if (directional)
{
Gizmos.matrix = GetBoundsMatrix();
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
}
else if (spot)
{
Transform t = transform;
Light l = m_Light;
Gizmos.matrix = Matrix4x4.TRS(t.position, t.rotation, Vector3.one);
Gizmos.DrawFrustum(t.position, l.spotAngle, l.range * m_SpotFar, l.range * m_SpotNear, 1);
}
}
void RenderQuadSections(Vector4 lightPos)
{
for (int i = 0; i < 4; i++)
{
// Skip one or two quarters, if the light is off screen
if (i == 0 && lightPos.y > 1 ||
i == 1 && lightPos.x > 1 ||
i == 2 && lightPos.y < -1 ||
i == 3 && lightPos.x < -1)
continue;
// index denotes which quarter of the screen to take up,
// so start at -1, -0.5, 0 or 0.5
float top = i / 2.0f - 1.0f;
float bottom = top + 0.5f;
GL.Begin(GL.QUADS);
GL.Vertex3(-1, top, 0);
GL.Vertex3(1, top, 0);
GL.Vertex3(1, bottom, 0);
GL.Vertex3(-1, bottom, 0);
GL.End();
}
}
void RenderQuad()
{
GL.Begin(GL.QUADS);
GL.TexCoord2( 0, 0);
GL.Vertex3 (-1,-1, 0);
GL.TexCoord2( 0, 1);
GL.Vertex3 (-1, 1, 0);
GL.TexCoord2( 1, 1);
GL.Vertex3 ( 1, 1, 0);
GL.TexCoord2( 1, 0);
GL.Vertex3 ( 1,-1, 0);
GL.End();
}
void RenderSpotFrustum()
{
Graphics.DrawMeshNow(m_SpotMesh, transform.position, transform.rotation);
}
Vector4 GetLightViewportPos()
{
Vector3 lightPos = transform.position;
if (directional)
lightPos = m_CurrentCamera.transform.position + transform.forward;
Vector3 lightViewportPos3 = m_CurrentCamera.WorldToViewportPoint(lightPos);
return new Vector4(lightViewportPos3.x*2.0f - 1.0f, lightViewportPos3.y*2.0f - 1.0f, 0, 0);
}
bool IsVisible()
{
// Intersect against spot light's OBB (or light frustum's OBB), so AABB in it's space
Matrix4x4 lightToCameraProjection = m_CurrentCamera.projectionMatrix * m_CurrentCamera.worldToCameraMatrix * transform.localToWorldMatrix;
return GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(lightToCameraProjection), GetBoundsLocal());
}
bool IntersectsNearPlane()
{
// Lazy for now:
// Just check if any vertex is behind the near plane.
// TODO: same for directional
Vector3[] vertices = m_SpotMesh.vertices;
float nearPlaneFudged = m_CurrentCamera.nearClipPlane - 0.001f;
Transform t = transform;
for (int i = 0; i < vertices.Length; i++)
{
float z = m_CurrentCamera.WorldToViewportPoint(t.TransformPoint(vertices[i])).z;
if (z < nearPlaneFudged)
return true;
}
return false;
}
void SetKeyword(bool firstOn, string firstKeyword, string secondKeyword)
{
Shader.EnableKeyword(firstOn ? firstKeyword : secondKeyword);
Shader.DisableKeyword(firstOn ? secondKeyword : firstKeyword);
}
public void SetShadowmapDirty()
{
m_ShadowmapDirty = true;
}
void GetFrustumRays(out Matrix4x4 frustumRays, out Vector3 cameraPosLocal)
{
float far = m_CurrentCamera.farClipPlane;
Vector3 cameraPos = m_CurrentCamera.transform.position;
Matrix4x4 m = GetBoundsMatrix().inverse;
Vector2[] uvs = new Vector2[] {new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1)};
frustumRays = new Matrix4x4();
for (int i = 0; i < 4; i++)
{
Vector3 ray = m_CurrentCamera.ViewportToWorldPoint(new Vector3(uvs[i].x, uvs[i].y, far)) - cameraPos;
ray = m.MultiplyVector(ray);
frustumRays.SetRow(i, ray);
}
cameraPosLocal = m.MultiplyPoint3x4(cameraPos);
}
void SetFrustumRays(Material material)
{
Matrix4x4 frustumRays;
Vector3 cameraPosLocal;
GetFrustumRays(out frustumRays, out cameraPosLocal);
material.SetVector("_CameraPosLocal", cameraPosLocal);
material.SetMatrix("_FrustumRays", frustumRays);
material.SetFloat("_FrustumApex", GetFrustumApex());
}
float GetDepthThresholdAdjusted()
{
return m_DepthThreshold/m_CurrentCamera.farClipPlane;
}
bool CheckCamera()
{
if (m_Cameras == null)
return false;
foreach (Camera cam in m_Cameras)
if (cam == m_CurrentCamera)
return true;
return false;
}
public void UpdateCameraDepthMode()
{
if (m_Cameras == null)
return;
foreach(Camera cam in m_Cameras)
if (cam)
cam.depthTextureMode |= DepthTextureMode.Depth;
}
}