OSDN Git Service

Added Assets for main menu
[mindgames/Mindgames_main.git] / Mindgames / Assets / Aura 2 / Core / Code / Extensions / CameraExtensions.cs
1 
2 /***************************************************************************
3 *                                                                          *
4 *  Copyright (c) Raphaël Ernaelsten (@RaphErnaelsten)                      *
5 *  All Rights Reserved.                                                    *
6 *                                                                          *
7 *  NOTICE: Aura 2 is a commercial project.                                 * 
8 *  All information contained herein is, and remains the property of        *
9 *  Raphaël Ernaelsten.                                                     *
10 *  The intellectual and technical concepts contained herein are            *
11 *  proprietary to Raphaël Ernaelsten and are protected by copyright laws.  *
12 *  Dissemination of this information or reproduction of this material      *
13 *  is strictly forbidden.                                                  *
14 *                                                                          *
15 ***************************************************************************/
16
17 using UnityEngine;
18
19 namespace Aura2API
20 {
21     /// <summary>
22     /// Static class containing extension for Camera type
23     /// </summary>
24     public static class CameraExtensions
25     {
26         #region Private Members
27         /// <summary>
28         /// Clip space corners' position
29         /// </summary>
30         private static readonly Vector3[] _frustumClipPos =         //                     E_______________F
31         {                                                           //                    /|                _/ |
32                 new Vector3(-1, 1, -1), // A                        //                   / |              _/   |
33                 new Vector3(1, 1, -1), // B                         //                  /  |        _/     |    FAR
34                 new Vector3(1, -1, -1), // C                        //                 /   |     _/            |
35                 new Vector3(-1, -1, -1), // D                       //                /    H____/__________G
36                 new Vector3(-1, 1, 1), // E                         //               A____/__B        __/
37                 new Vector3(1, 1, 1), // F                          //               |  _/   |     __/
38                 new Vector3(1, -1, 1), // G                         //        NEAR   |_/         |  __/
39                 new Vector3(-1, -1, 1) // H                         //               D_______C_/
40         };
41         
42         /// <summary>
43         /// The automatic spawn distance from the camera for gameObjects creation
44         /// </summary>
45         private static readonly float _spawnDistanceFromCamera = 50.0f;
46         /// <summary>
47         /// The automatic spawn downwards search distance if there is no surface to spawn onto at _spawnDistanceFromCamera
48         /// </summary>
49         private static readonly float _spawnHeightTolerance = 25.0f;
50         /// <summary>
51         /// Temporary object to avoid allocation
52         /// </summary>
53         private static Vector3[] _tmpRetrievedFrustumPlaneCornersArray = new Vector3[4];
54         /// <summary>
55         /// Temporary object to avoid allocation
56         /// </summary>
57         private static Vector4[] _tmpNearPlaneCornersArray = new Vector4[4];
58         /// <summary>
59         /// Temporary object to avoid allocation
60         /// </summary>
61         private static Vector4[] _tmpFarPlaneCornersArray = new Vector4[4];
62         #endregion
63
64         #region Functions
65         /// <summary>
66         /// Tells if the current camera is the sceneView camera
67         /// </summary>
68         public static bool IsCurrentSceneViewCamera
69         {
70             get
71             {
72                 return Camera.current != null && Camera.current.IsSceneViewCamera();
73             }
74         }
75
76         /// <summary>
77         /// Tells if the reference camera is the SceneView camera
78         /// </summary>
79         /// <returns>True if the reference camera is the current SceneView camera</returns>
80         public static bool IsSceneViewCamera(this Camera camera)
81         {
82             #if UNITY_EDITOR
83             return camera.cameraType == CameraType.SceneView;
84             #else
85             return false;
86             #endif
87         }
88
89         /// <summary>
90         /// Computes the planes corresponding to the sides of frustum (a tapered box) of the camera
91         /// </summary>
92         /// <param name="nearClipPlaneDistance">The near clip distance</param>
93         /// <param name="farClipPlaneDistance">The far clip distance</param>
94         /// <returns>An array with the planes corresponding to the sides of frustum, in the following order : left, right, top, bottomm, near, far</returns>
95         public static Plane[] GetFrustumPlanes(this Camera camera, float nearClipPlaneDistance, float farClipPlaneDistance)
96         {
97             Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(camera);            
98             // Overwrite near and far planes
99             frustumPlanes[4] = new Plane(camera.transform.forward, camera.transform.position + camera.transform.forward * nearClipPlaneDistance);     // near
100             frustumPlanes[5] = new Plane(-camera.transform.forward, camera.transform.position + camera.transform.forward * farClipPlaneDistance);     // far
101
102             return frustumPlanes;
103         }
104
105         /// <summary>
106         /// Computes the size of the frustum at given distance
107         /// </summary>
108         /// <param name="distance">The distance at which we want to know the size of the frustum</param>
109         /// <returns>The size of the frustum at given distance</returns>
110         public static Vector2 GetFrustumSizeAtDistance(this Camera camera, float distance)
111         {
112             float height =  Mathf.Tan(camera.fieldOfView * Mathf.Deg2Rad * 0.5f) * 2.0f * distance;
113             float width = height * camera.aspect;
114
115             return new Vector2(width, height);
116         }
117
118         /// <summary>
119         /// Returns the viewing eye for Stereo rendering (if not stereo or not in a render loop, returns Left)
120         /// </summary>
121         /// <returns>The current eye (left if not stereo or not in a render loop)</returns>
122         public static Camera.StereoscopicEye GetStereoscopicEye(this Camera camera)
123         {
124             return (Camera.StereoscopicEye)((int)camera.stereoActiveEye % 2);
125         }
126
127         /// <summary>
128         /// Computes the corners of the plane parallel to the camera at given distance
129         /// </summary>
130         /// <param name="eye">The stereoscopic eye</param>
131         /// <param name="planeDistance">The reference distance</param>
132         /// <param name="planeCornersArray">The array to fill with the four corners of the intersecting plane</param>
133         public static void GetFrustumPlaneCorners(this Camera camera, Camera.MonoOrStereoscopicEye eye, float planeDistance, ref Vector4[] planeCornersArray)
134         {
135             if (camera.orthographic)
136             {
137                 _tmpRetrievedFrustumPlaneCornersArray[0].x = 0.0f;
138                 _tmpRetrievedFrustumPlaneCornersArray[0].y = 1.0f;
139                 _tmpRetrievedFrustumPlaneCornersArray[0].z = planeDistance;
140                 _tmpRetrievedFrustumPlaneCornersArray[1].x = 1.0f;
141                 _tmpRetrievedFrustumPlaneCornersArray[1].y = 1.0f;
142                 _tmpRetrievedFrustumPlaneCornersArray[1].z = planeDistance;
143                 _tmpRetrievedFrustumPlaneCornersArray[2].x = 1.0f;
144                 _tmpRetrievedFrustumPlaneCornersArray[2].y = 0.0f;
145                 _tmpRetrievedFrustumPlaneCornersArray[2].z = planeDistance;
146                 _tmpRetrievedFrustumPlaneCornersArray[3].x = 0.0f;
147                 _tmpRetrievedFrustumPlaneCornersArray[3].y = 0.0f;
148                 _tmpRetrievedFrustumPlaneCornersArray[3].z = planeDistance;
149
150                 for (int i = 0; i < 4; ++i)
151                 {
152                     planeCornersArray[i] = camera.ViewportToWorldPoint(_tmpRetrievedFrustumPlaneCornersArray[i]);
153                 }
154             }
155             else
156             {
157                 camera.CalculateFrustumCorners(new Rect(0,0,1,1), planeDistance, eye, _tmpRetrievedFrustumPlaneCornersArray);
158                 for (int i = 0; i < 4; ++i)
159                 {
160                     _tmpRetrievedFrustumPlaneCornersArray[i] = camera.transform.localToWorldMatrix.MultiplyPoint(_tmpRetrievedFrustumPlaneCornersArray[i]);
161                 }
162             
163                 Vector3 tmp = _tmpRetrievedFrustumPlaneCornersArray[0];
164                 planeCornersArray[0] = new Vector4(_tmpRetrievedFrustumPlaneCornersArray[1].x, _tmpRetrievedFrustumPlaneCornersArray[1].y, _tmpRetrievedFrustumPlaneCornersArray[1].z, 1.0f);
165                 planeCornersArray[1] = new Vector4(_tmpRetrievedFrustumPlaneCornersArray[2].x, _tmpRetrievedFrustumPlaneCornersArray[2].y, _tmpRetrievedFrustumPlaneCornersArray[2].z, 1.0f);
166                 planeCornersArray[2] = new Vector4(_tmpRetrievedFrustumPlaneCornersArray[3].x, _tmpRetrievedFrustumPlaneCornersArray[3].y, _tmpRetrievedFrustumPlaneCornersArray[3].z, 1.0f);
167                 planeCornersArray[3] = new Vector4(tmp.x, tmp.y, tmp.z, 1.0f);
168             }
169         }
170
171         /// <summary>
172         /// Computes the world space frustum's corners' position
173         /// </summary>
174         /// <param name="nearClipDistance">The desired near plane</param>
175         /// <param name="farClipDistance">The desired far plane</param>
176         /// <param name="floatsArrayToFill">The floats array to fill with the the positions</param>
177         public static void GetFrustumCorners(this Camera camera, Camera.MonoOrStereoscopicEye eye, float nearClipDistance, float farClipDistance, ref float[] floatsArrayToFill)
178         {
179             camera.GetFrustumPlaneCorners(eye, nearClipDistance, ref _tmpNearPlaneCornersArray);
180             for (int i = 0; i < 4; ++i)
181             {
182                 floatsArrayToFill[i * 4] = _tmpNearPlaneCornersArray[i].x;
183                 floatsArrayToFill[i * 4 + 1] = _tmpNearPlaneCornersArray[i].y;
184                 floatsArrayToFill[i * 4 + 2] = _tmpNearPlaneCornersArray[i].z;
185                 floatsArrayToFill[i * 4 + 3] = _tmpNearPlaneCornersArray[i].w;
186             }
187
188             camera.GetFrustumPlaneCorners(eye, farClipDistance, ref _tmpFarPlaneCornersArray);
189             for (int i = 0; i < 4; ++i)
190             {
191                 floatsArrayToFill[16 + i * 4] = _tmpFarPlaneCornersArray[i].x;
192                 floatsArrayToFill[16 + i * 4 + 1] = _tmpFarPlaneCornersArray[i].y;
193                 floatsArrayToFill[16 + i * 4 + 2] = _tmpFarPlaneCornersArray[i].z;
194                 floatsArrayToFill[16 + i * 4 + 3] = _tmpFarPlaneCornersArray[i].w;
195             }
196         }
197
198         /// <summary>
199         /// Computes a default spawn position in front of the camera. The position will be in this order : a) on the surface in front of the camera (if within 50m). b) if not, 50m in front of the camera, on a surface which would be within 25m under. c) if not, 50m in front of the camera.
200         /// </summary>
201         /// <returns>The computed spawn position</returns>
202         public static Vector3 GetSpawnPosition(this Camera camera)
203         {
204             Vector3 spawnPosition;
205
206             RaycastHit hitInfo = new RaycastHit();
207             if (Physics.Raycast(camera.transform.position, camera.transform.forward, out hitInfo, _spawnDistanceFromCamera))
208             {
209                 spawnPosition = hitInfo.point;
210             }
211             else
212             {
213                 spawnPosition = camera.transform.position + camera.transform.forward * _spawnDistanceFromCamera;
214
215                 if (Physics.Raycast(spawnPosition, Vector3.down, out hitInfo, _spawnHeightTolerance))
216                 {
217                     spawnPosition = hitInfo.point;
218                 }
219             }
220             
221             return spawnPosition;
222         }
223
224         /// <summary>
225         /// Computes the world position of the frustum corners with custom near/far clip distances
226         /// </summary>
227         /// <param name="camera">The queried camera</param>
228         /// <param name="nearClipPlaneDistance">The near clip distance</param>
229         /// <param name="farClipPlaneDistance">The far clip distance</param>
230         /// <returns>An array with the world position of the corners in the following order : nearTopLeft, nearTopRight, nearBottomRight, nearBottomLeft, farTopLeft, farTopRight, farBottomRight, farBottomLeft</returns>
231         public static Vector4[] GetViewportFrustumCornersWorldPosition(this Camera camera, float nearClipPlaneDistance, float farClipPlaneDistance)
232         {
233             return new Vector4[]
234                    {
235                        camera.ViewportToWorldPoint(new Vector3(0, 1, nearClipPlaneDistance)),
236                        camera.ViewportToWorldPoint(new Vector3(1, 1, nearClipPlaneDistance)),
237                        camera.ViewportToWorldPoint(new Vector3(1, 0, nearClipPlaneDistance)),
238                        camera.ViewportToWorldPoint(new Vector3(0, 0, nearClipPlaneDistance)),
239                        camera.ViewportToWorldPoint(new Vector3(0, 1, farClipPlaneDistance)),
240                        camera.ViewportToWorldPoint(new Vector3(1, 1, farClipPlaneDistance)),
241                        camera.ViewportToWorldPoint(new Vector3(1, 0, farClipPlaneDistance)),
242                        camera.ViewportToWorldPoint(new Vector3(0, 0, farClipPlaneDistance))
243                    };
244         }
245
246         /// <summary>
247         /// Computes the world position of the corners of the frustum
248         /// </summary>
249         /// <param name="frustumClipToCameraInverseProjMatrix">The clip to camera inverse projection matrix</param>
250         /// <returns>An array containing the world position of the corners of the frustum</returns>
251         public static Vector4[] GetFrustumCornersWorldPosition(this Camera camera, Matrix4x4 frustumClipToCameraInverseProjMatrix)
252         {
253             Vector4[] frustumWorldPos = new Vector4[8];
254
255             for (int i = 0; i < 8; ++i)
256             {
257                 frustumWorldPos[i] = frustumClipToCameraInverseProjMatrix.MultiplyPoint(_frustumClipPos[i]);
258             }
259
260             return frustumWorldPos;
261         }
262
263         /// <summary>
264         /// Computes the world position of the corners of the frustum
265         /// </summary>
266         /// <param name="camera">The camera</param>
267         /// <param name="nearClipPlaneDistance">The near plane</param>
268         /// <param name="farClipPlaneDistance">The far plane</param>
269         /// <returns>An array containing the world position of the corners of the frustum</returns>
270         public static Vector3[] GetFrustumCornersWorldPosition(this Camera camera, float nearClipPlaneDistance, float farClipPlaneDistance)
271         {
272             Vector3[] frustumWorldPos = new Vector3[8];
273
274             Vector2 near = camera.GetFrustumSizeAtDistance(nearClipPlaneDistance);
275             Vector2 far = camera.GetFrustumSizeAtDistance(farClipPlaneDistance);
276
277             Matrix4x4 matrix = Matrix4x4.TRS(camera.transform.position, camera.transform.rotation, Vector3.one);
278
279             for (int i = 0; i < 8; ++i)
280             {
281                 Vector3 pos = _frustumClipPos[i];
282                 if (pos.z < 0)
283                 {
284                     pos.x *= near.x;
285                     pos.y *= near.y;
286                     pos.z = nearClipPlaneDistance;
287                 }
288                 else
289                 {
290                     pos.x *= far.x;
291                     pos.y *= far.y;
292                     pos.z = farClipPlaneDistance;
293                 }
294
295                 frustumWorldPos[i] = matrix.MultiplyPoint3x4(pos);
296             }
297
298             return frustumWorldPos;
299         }
300
301         /// <summary>
302         /// Gets the projection matrix of the camera
303         /// </summary>
304         /// <param name="eye">The stereoscopic eye</param>
305         /// <returns></returns>
306         public static Matrix4x4 GetProjectionMatrix(this Camera camera, Camera.MonoOrStereoscopicEye eye)
307         {
308             if (eye == Camera.MonoOrStereoscopicEye.Mono)
309             {
310                 return camera.projectionMatrix;
311             }
312             else
313             {
314                 return camera.GetStereoProjectionMatrix((Camera.StereoscopicEye)eye);
315             }
316         }
317
318         /// <summary>
319         /// Returns the camera's World space to Clip space matrix
320         /// </summary>
321         /// <param name="nearClipPlane">The near clip plane</param>
322         /// <param name="farClipPlane">The far clip plane</param>
323         /// <param name="matrixToFill">The allocated matrix object to write into</param>
324         public static void GetWorldToClipMatrix(this Camera cameraComponent, Camera.MonoOrStereoscopicEye eye, float nearClipPlane, float farClipPlane, ref Matrix4x4 matrixToFill)
325         {
326             float tmpNear = cameraComponent.nearClipPlane;
327             cameraComponent.nearClipPlane = nearClipPlane;
328             float tmpFar = cameraComponent.farClipPlane;
329             cameraComponent.farClipPlane = farClipPlane;
330
331             Matrix4x4 worldToCameraMatrix = cameraComponent.worldToCameraMatrix;
332             Matrix4x4 projectionMatrix = cameraComponent.GetProjectionMatrix(eye);
333             matrixToFill = projectionMatrix * worldToCameraMatrix; // worldToClipMatrix
334
335             cameraComponent.nearClipPlane = tmpNear;
336             cameraComponent.farClipPlane = tmpFar;
337         }
338         
339         /// <summary>
340         /// Returns the stereo mode of the camera
341         /// </summary>
342         /// <returns>What stereo mode the camera is running on</returns>
343         public static StereoMode GetCameraStereoMode(this Camera camera)
344         {
345             if (camera.stereoEnabled)
346             {
347                 if(XrHelpers.IsSinglePassStereo)
348                 {
349                     return StereoMode.SinglePass;
350                 } 
351                 else
352                 {
353                     return StereoMode.MultiPass;
354                 }
355             }
356             else
357             {
358                 return StereoMode.Mono;
359             }
360         }
361         #endregion
362     }
363 }