@@ -47,6 +47,14 @@ private enum FrustumPlanes
4747
4848 private GameObject pointer ;
4949
50+ private static int frustumLastUpdated = - 1 ;
51+
52+ private static Plane [ ] indicatorVolume ;
53+ private static Vector3 cameraForward ;
54+ private static Vector3 cameraPosition ;
55+ private static Vector3 cameraRight ;
56+ private static Vector3 cameraUp ;
57+
5058 private void Start ( )
5159 {
5260 Depth = Mathf . Clamp ( Depth , Camera . main . nearClipPlane , Camera . main . farClipPlane ) ;
@@ -76,35 +84,31 @@ private void Update()
7684 }
7785 else
7886 {
79- // The top, bottom and side frustum planes are used to restrict the movement
80- // of the pointer.
81-
82- // Here we adjust the Camera's frustum planes to place the cursor in a smaller
83- // volume, thus creating the effect of a "margin"
84- Plane [ ] indicatorVolume = GeometryUtility . CalculateFrustumPlanes ( Camera . main ) ;
85- for ( int i = 0 ; i < 4 ; ++ i )
87+ int currentFrameCount = UnityEngine . Time . frameCount ;
88+ if ( currentFrameCount != frustumLastUpdated )
8689 {
87- // We can make the frustum smaller by rotating the walls "in" toward the
88- // camera's forward vector.
89-
90- // First find the angle between the Camera's forward and the plane's normal
91- float angle = Mathf . Acos ( Vector3 . Dot ( indicatorVolume [ i ] . normal . normalized , Camera . main . transform . forward ) ) ;
90+ // Collect the updated camera information for the current frame
91+ CacheCameraTransform ( Camera . main ) ;
9292
93- // Then we calculate how much we should rotate the plane in based on the
94- // user's setting. 90 degrees is our maximum as at that point we no longer
95- // have a valid frustum.
96- float angleStep = IndicatorMarginPercent * ( 0.5f * Mathf . PI - angle ) ;
93+ // Use the updated camera information to create the new bounding volume
94+ UpdateIndicatorVolume ( Camera . main ) ;
9795
98- // Because the frustum plane normal's face in must actually rotate away from the forward to vector
99- // to narrow the frustum.
100- Vector3 normal = Vector3 . RotateTowards ( indicatorVolume [ i ] . normal , Camera . main . transform . forward , - angleStep , 0.0f ) ;
101- indicatorVolume [ i ] . normal = normal . normalized ;
96+ frustumLastUpdated = currentFrameCount ;
10297 }
10398
10499 UpdatePointerTransform ( Camera . main , indicatorVolume , TargetObject . transform . position ) ;
105100 }
106101 }
107102
103+ private void CacheCameraTransform ( Camera camera )
104+ {
105+ // Cache the camera transform information for the current frame
106+ cameraForward = camera . transform . forward ;
107+ cameraPosition = camera . transform . position ;
108+ cameraRight = camera . transform . right ;
109+ cameraUp = camera . transform . up ;
110+ }
111+
108112 // Assuming the target object is outside the view which of the four "wall" planes should
109113 // the pointer snap to.
110114 private FrustumPlanes GetExitPlane ( Vector3 targetPosition , Camera camera )
@@ -125,18 +129,18 @@ private FrustumPlanes GetExitPlane(Vector3 targetPosition, Camera camera)
125129
126130 // Calculate the edges of the frustum as world space offsets from the middle of the
127131 // frustum in world space.
128- Vector3 nearTop = near * tanFovy * camera . transform . up ;
129- Vector3 nearRight = near * tanFovx * camera . transform . right ;
132+ Vector3 nearTop = near * tanFovy * cameraUp ;
133+ Vector3 nearRight = near * tanFovx * cameraRight ;
130134 Vector3 nearBottom = - nearTop ;
131135 Vector3 nearLeft = - nearRight ;
132- Vector3 farTop = far * tanFovy * camera . transform . up ;
133- Vector3 farRight = far * tanFovx * camera . transform . right ;
136+ Vector3 farTop = far * tanFovy * cameraUp ;
137+ Vector3 farRight = far * tanFovx * cameraRight ;
134138 Vector3 farLeft = - farRight ;
135139
136140 // Caclulate the center point of the near plane and the far plane as offsets from the
137141 // camera in world space.
138- Vector3 nearBase = near * camera . transform . forward ;
139- Vector3 farBase = far * camera . transform . forward ;
142+ Vector3 nearBase = near * cameraForward ;
143+ Vector3 farBase = far * cameraForward ;
140144
141145 // Calculate the frustum corners needed to create 'd'
142146 Vector3 nearUpperLeft = nearBase + nearTop + nearLeft ;
@@ -215,16 +219,16 @@ private FrustumPlanes GetExitPlane(Vector3 targetPosition, Camera camera)
215219 // given a frustum wall we wish to snap the pointer to, this function returns a ray
216220 // along which the pointer should be placed to appear at the appropiate point along
217221 // the edge of the indicator field.
218- private bool TryGetIndicatorPosition ( Vector3 targetPosition , Camera camera , Plane frustumWall , out Ray r )
222+ private bool TryGetIndicatorPosition ( Vector3 targetPosition , Plane frustumWall , out Ray r )
219223 {
220224 // Think of the pointer as pointing the shortest rotation a user must make to see a
221225 // target. The shortest rotation can be obtained by finding the great circle defined
222226 // be the target, the camera position and the center position of the view. The tangent
223227 // vector of the great circle points the direction of the shortest rotation. This
224228 // great circle and thus any of it's tangent vectors are coplanar with the plane
225229 // defined by these same three points.
226- Vector3 cameraToTarget = targetPosition - camera . transform . position ;
227- Vector3 normal = Vector3 . Cross ( cameraToTarget . normalized , camera . transform . forward ) ;
230+ Vector3 cameraToTarget = targetPosition - cameraPosition ;
231+ Vector3 normal = Vector3 . Cross ( cameraToTarget . normalized , cameraForward ) ;
228232
229233 // In the case that the three points are colinear we cannot form a plane but we'll
230234 // assume the target is directly behind us and we'll use a prechosen plane.
@@ -264,14 +268,14 @@ private bool TryIntersectPlanes(Plane p, Plane q, out Ray intersection)
264268 private void UpdatePointerTransform ( Camera camera , Plane [ ] planes , Vector3 targetPosition )
265269 {
266270 // Start by assuming the pointer should be placed at the target position.
267- Vector3 indicatorPosition = camera . transform . position + Depth * ( targetPosition - camera . transform . position ) . normalized ;
271+ Vector3 indicatorPosition = cameraPosition + Depth * ( targetPosition - cameraPosition ) . normalized ;
268272
269273 // Test the target position with the frustum planes except the "far" plane since
270274 // far away objects should be considered in view.
271275 bool pointNotInsideIndicatorField = false ;
272276 for ( int i = 0 ; i < 5 ; ++ i )
273277 {
274- float dot = Vector3 . Dot ( planes [ i ] . normal , ( targetPosition - camera . transform . position ) . normalized ) ;
278+ float dot = Vector3 . Dot ( planes [ i ] . normal , ( targetPosition - cameraPosition ) . normalized ) ;
275279 if ( dot <= 0.0f )
276280 {
277281 pointNotInsideIndicatorField = true ;
@@ -289,9 +293,9 @@ private void UpdatePointerTransform(Camera camera, Plane[] planes, Vector3 targe
289293 FrustumPlanes exitPlane = GetExitPlane ( targetPosition , camera ) ;
290294
291295 Ray r ;
292- if ( TryGetIndicatorPosition ( targetPosition , camera , planes [ ( int ) exitPlane ] , out r ) )
296+ if ( TryGetIndicatorPosition ( targetPosition , planes [ ( int ) exitPlane ] , out r ) )
293297 {
294- indicatorPosition = camera . transform . position + Depth * r . direction . normalized ;
298+ indicatorPosition = cameraPosition + Depth * r . direction . normalized ;
295299 }
296300 }
297301
@@ -304,14 +308,41 @@ private void UpdatePointerTransform(Camera camera, Plane[] planes, Vector3 targe
304308 // center position of the view that is on the same plane as the pointer position.
305309 // We do this by projecting the vector from the pointer to the camera onto the
306310 // the camera's forward vector.
307- Vector3 indicatorFieldOffset = indicatorPosition - camera . transform . position ;
308- indicatorFieldOffset = Vector3 . Dot ( indicatorFieldOffset , camera . transform . forward ) * camera . transform . forward ;
311+ Vector3 indicatorFieldOffset = indicatorPosition - cameraPosition ;
312+ indicatorFieldOffset = Vector3 . Dot ( indicatorFieldOffset , cameraForward ) * cameraForward ;
309313
310- Vector3 indicatorFieldCenter = camera . transform . position + indicatorFieldOffset ;
314+ Vector3 indicatorFieldCenter = cameraPosition + indicatorFieldOffset ;
311315 Vector3 pointerDirection = ( indicatorPosition - indicatorFieldCenter ) . normalized ;
312316
313317 // allign this object's up vector with the pointerDirection
314- this . transform . rotation = Quaternion . LookRotation ( camera . transform . forward , pointerDirection ) ;
318+ this . transform . rotation = Quaternion . LookRotation ( cameraForward , pointerDirection ) ;
319+ }
320+
321+ // Here we adjust the Camera's frustum planes to place the cursor in a smaller
322+ // volume, thus creating the effect of a "margin"
323+ private void UpdateIndicatorVolume ( Camera camera )
324+ {
325+ // The top, bottom and side frustum planes are used to restrict the movement
326+ // of the pointer. These reside at indices 0-3;
327+ indicatorVolume = GeometryUtility . CalculateFrustumPlanes ( camera ) ;
328+ for ( int i = 0 ; i < 4 ; ++ i )
329+ {
330+ // We can make the frustum smaller by rotating the walls "in" toward the
331+ // camera's forward vector.
332+
333+ // First find the angle between the Camera's forward and the plane's normal
334+ float angle = Mathf . Acos ( Vector3 . Dot ( indicatorVolume [ i ] . normal . normalized , cameraForward ) ) ;
335+
336+ // Then we calculate how much we should rotate the plane in based on the
337+ // user's setting. 90 degrees is our maximum as at that point we no longer
338+ // have a valid frustum.
339+ float angleStep = IndicatorMarginPercent * ( 0.5f * Mathf . PI - angle ) ;
340+
341+ // Because the frustum plane normal's face in must actually rotate away from the forward to vector
342+ // to narrow the frustum.
343+ Vector3 normal = Vector3 . RotateTowards ( indicatorVolume [ i ] . normal , cameraForward , - angleStep , 0.0f ) ;
344+ indicatorVolume [ i ] . normal = normal . normalized ;
345+ }
315346 }
316347 }
317348}
0 commit comments