FrustumDisplay.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /// <summary>
  5. /// Creates lines and meshes to display the frustum of the specified camera.
  6. /// Used to draw the frustum in the MR Calibration scene.
  7. /// </summary>
  8. [RequireComponent(typeof(LineRenderer))]
  9. public class FrustumDisplay : MonoBehaviour
  10. {
  11. /// <summary>
  12. /// ZEDManager instance whose OnZEDReady event we subscribe to to know when to draw the frustum.
  13. /// </summary>
  14. [Tooltip("ZEDManager instance whose OnZEDReady event we subscribe to to know when to draw the frustum. ")]
  15. public ZEDManager zedManager;
  16. /// <summary>
  17. /// Camera whose frustum to draw. Normally the left camera in a ZED_Rig_Mono or ZED_Rig_Stereo prefab.
  18. /// </summary>
  19. [Tooltip("Camera whose frustum to draw. Normally the left camera in a ZED_Rig_Mono or ZED_Rig_Stereo prefab. ")]
  20. public Camera cam;
  21. /// <summary>
  22. /// How far away to draw the camera's near plane. We don't use the real one as it's sometimes not visually helpful.
  23. /// </summary>
  24. [Tooltip("How far away to draw the camera's near plane. We don't use the real one as it's sometimes not visually helpful.")]
  25. public float nearPlaneRendDist = 0.1f;
  26. /// <summary>
  27. /// How far away to draw the camera's far plane. We don't use the real one as it'll usually make the frustum way too big to be helpful.
  28. /// </summary>
  29. [Tooltip("How far away to draw the camera's far plane. We don't use the real one as it'll usually make the frustum way too big to be helpful.")]
  30. public float farPlaneRendDist = 0.75f;
  31. /// <summary>
  32. /// Line renderer object used to draw the near plane. Will also be used as a basis for the edges connecting the near and far plane corners.
  33. /// </summary>
  34. [Tooltip("Line renderer object used to draw the near plane. Will also be used as a basis for the edges connecting the near and far plane corners.")]
  35. public LineRenderer nearPlaneLineRend;
  36. /// <summary>
  37. /// Material used to draw the lines on the sides of the frustum.
  38. /// </summary>
  39. [Tooltip("Material used to draw the lines on the sides of the frustum. ")]
  40. public Material edgeLineMat;
  41. /// <summary>
  42. /// Material used to draw the planes on the sides of the frustum.
  43. /// </summary>
  44. [Tooltip("Material used to draw the planes on the sides of the frustum. ")]
  45. public Material sidePlaneMat;
  46. /// <summary>
  47. /// Color (with alpha) of the edge lines on the sides of the frustum, nearest to the camera.
  48. /// </summary>
  49. [Tooltip("Color (with alpha) of the edge lines on the sides of the frustum, nearest to the camera. ")]
  50. [Space(5)]
  51. public Color edgeLineStartColor = Color.cyan;
  52. /// <summary>
  53. /// Color (with alpha) of the edge lines on the sides of the frustum, furthest to the camera. Used to create fade-out effect.
  54. /// </summary>
  55. [Tooltip("Color (with alpha) of the edge lines on the sides of the frustum, furthest to the camera. Used to create fade-out effect.")]
  56. public Color edgeLineEndColor = new Color(0, 1, 1, 0.2f);
  57. private LineRenderer topLeftLineRend;
  58. private LineRenderer topRightLineRend;
  59. private LineRenderer bottomLeftLineRend;
  60. private LineRenderer bottomRightLineRend;
  61. private MeshFilter topPlaneMF;
  62. private MeshFilter bottomPlaneMF;
  63. private MeshFilter leftPlaneMF;
  64. private MeshFilter rightPlaneMF;
  65. private List<MeshRenderer> planeRenderers = new List<MeshRenderer>();
  66. // Use this for initialization
  67. void Awake ()
  68. {
  69. if (!zedManager) ZEDManager.GetInstance(sl.ZED_CAMERA_ID.CAMERA_ID_01);
  70. if(!cam) cam = zedManager.GetLeftCamera();
  71. zedManager.OnZEDReady += DrawFrustum;
  72. if(!nearPlaneLineRend) nearPlaneLineRend = GetComponent<LineRenderer>();
  73. CreateEdgeLinesAndPlanes();
  74. }
  75. /// <summary>
  76. /// Use the camera's frustum to draw a visualization of it, using line renderers and mesh objects mostly created
  77. /// earlier by CreateEdgeLinesAndPlanes().
  78. /// </summary>
  79. private void DrawFrustum()
  80. {
  81. //Calculate the near plane.
  82. Vector3[] nearplane = new Vector3[4];
  83. //cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), cam.nearClipPlane, Camera.MonoOrStereoscopicEye.Mono, nearplane);
  84. cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), nearPlaneRendDist, Camera.MonoOrStereoscopicEye.Mono, nearplane);
  85. nearPlaneLineRend.positionCount = 4;
  86. nearPlaneLineRend.SetPositions(nearplane);
  87. nearPlaneLineRend.loop = true; //Important to have Loop enabled or else one side will be open.
  88. if (edgeLineMat != null) nearPlaneLineRend.material = edgeLineMat;
  89. //Calculate the far plane that the ends extend to.
  90. Vector3[] farplane = new Vector3[4];
  91. cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), farPlaneRendDist, Camera.MonoOrStereoscopicEye.Mono, farplane);
  92. bottomLeftLineRend.SetPositions(new Vector3[2] { nearplane[0], farplane[0] });
  93. topLeftLineRend.SetPositions(new Vector3[2] { nearplane[1], farplane[1] });
  94. topRightLineRend.SetPositions(new Vector3[2] { nearplane[2], farplane[2] });
  95. bottomRightLineRend.SetPositions(new Vector3[2] { nearplane[3], farplane[3] });
  96. //Set colors on edge lines.
  97. bottomLeftLineRend.startColor = edgeLineStartColor;
  98. topLeftLineRend.startColor = edgeLineStartColor;
  99. topRightLineRend.startColor = edgeLineStartColor;
  100. bottomRightLineRend.startColor = edgeLineStartColor;
  101. bottomLeftLineRend.endColor = edgeLineEndColor;
  102. topLeftLineRend.endColor = edgeLineEndColor;
  103. topRightLineRend.endColor = edgeLineEndColor;
  104. bottomRightLineRend.endColor = edgeLineEndColor;
  105. //Force the near plane box to have the same colors, but in this case without the fade that comes from the end color.
  106. nearPlaneLineRend.startColor = edgeLineStartColor;
  107. nearPlaneLineRend.endColor = edgeLineStartColor; //Not a typo. We don't want the fade.
  108. //Create the plane meshes on the sides and assign them.
  109. topPlaneMF.mesh = CreatePlaneMesh(nearplane[1], nearplane[2], farplane[1], farplane[2]);
  110. bottomPlaneMF.mesh = CreatePlaneMesh(nearplane[0], nearplane[3], farplane[0], farplane[3]);
  111. leftPlaneMF.mesh = CreatePlaneMesh(nearplane[0], nearplane[1], farplane[0], farplane[1]);
  112. rightPlaneMF.mesh = CreatePlaneMesh(nearplane[2], nearplane[3], farplane[2], farplane[3]);
  113. }
  114. /// <summary>
  115. /// Creates necessary objects for drawing the edge lines and planes, and applies basic settings.
  116. /// </summary>
  117. private void CreateEdgeLinesAndPlanes()
  118. {
  119. GameObject blgo = new GameObject("Bottom Left Edge");
  120. GameObject tlgo = new GameObject("Top Left Edge");
  121. GameObject trgo = new GameObject("Top Right Edge");
  122. GameObject brgo = new GameObject("Bottom Right Edge");
  123. blgo.transform.parent = transform;
  124. tlgo.transform.parent = transform;
  125. trgo.transform.parent = transform;
  126. brgo.transform.parent = transform;
  127. blgo.layer = gameObject.layer;
  128. tlgo.layer = gameObject.layer;
  129. trgo.layer = gameObject.layer;
  130. brgo.layer = gameObject.layer;
  131. blgo.transform.localPosition = Vector3.zero;
  132. tlgo.transform.localPosition = Vector3.zero;
  133. trgo.transform.localPosition = Vector3.zero;
  134. brgo.transform.localPosition = Vector3.zero;
  135. blgo.transform.localRotation = Quaternion.identity;
  136. tlgo.transform.localRotation = Quaternion.identity;
  137. trgo.transform.localRotation = Quaternion.identity;
  138. brgo.transform.localRotation = Quaternion.identity;
  139. bottomLeftLineRend = blgo.AddComponent<LineRenderer>();
  140. topLeftLineRend = tlgo.AddComponent<LineRenderer>();
  141. topRightLineRend = trgo.AddComponent<LineRenderer>();
  142. bottomRightLineRend = brgo.AddComponent<LineRenderer>();
  143. bottomLeftLineRend.widthMultiplier = nearPlaneLineRend.widthMultiplier;
  144. topLeftLineRend.widthMultiplier = nearPlaneLineRend.widthMultiplier;
  145. topRightLineRend.widthMultiplier = nearPlaneLineRend.widthMultiplier;
  146. bottomRightLineRend.widthMultiplier = nearPlaneLineRend.widthMultiplier;
  147. bottomLeftLineRend.useWorldSpace = false;
  148. topLeftLineRend.useWorldSpace = false;
  149. topRightLineRend.useWorldSpace = false;
  150. bottomRightLineRend.useWorldSpace = false;
  151. if(edgeLineMat != null)
  152. {
  153. bottomLeftLineRend.material = edgeLineMat;
  154. topLeftLineRend.material = edgeLineMat;
  155. topRightLineRend.material = edgeLineMat;
  156. bottomRightLineRend.material = edgeLineMat;
  157. }
  158. //Create MeshFilters and cache them.
  159. //We add them to the corner GameObjects such that it's clockwise one place of each corner, though it doesn't technically matter.
  160. topPlaneMF = tlgo.AddComponent<MeshFilter>();
  161. bottomPlaneMF = brgo.AddComponent<MeshFilter>();
  162. leftPlaneMF = blgo.AddComponent<MeshFilter>();
  163. rightPlaneMF = trgo.AddComponent<MeshFilter>();
  164. //Create MeshRenderers, but they'll all have the same mat so their position doesn't MATter (lol) either.
  165. planeRenderers.Clear(); //In case this got called twice somehow.
  166. planeRenderers.Add(tlgo.AddComponent<MeshRenderer>());
  167. planeRenderers.Add(brgo.AddComponent<MeshRenderer>());
  168. planeRenderers.Add(blgo.AddComponent<MeshRenderer>());
  169. planeRenderers.Add(trgo.AddComponent<MeshRenderer>());
  170. //Assign the plane materials.
  171. if (sidePlaneMat != null)
  172. {
  173. foreach (MeshRenderer rend in planeRenderers)
  174. {
  175. rend.material = sidePlaneMat;
  176. }
  177. }
  178. }
  179. /// <summary>
  180. /// Creates a single plane mesh with the specified corners.
  181. /// </summary>
  182. private Mesh CreatePlaneMesh(Vector3 botleft, Vector3 botright, Vector3 topleft, Vector3 topright)
  183. {
  184. Vector3[] verts = new Vector3[] { botleft, botright, topleft, topright };
  185. int[] tris = new int[] { 0, 2, 1, 2, 3, 1 };
  186. //Vector2[] uvs = new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 0), new Vector2(1, 1) };
  187. float width = botright.x - botleft.x;
  188. float ydif = topleft.y - botleft.y;
  189. float zdif = topleft.z - botleft.z;
  190. //float height = topleft.z - botleft.z;
  191. float height = Mathf.Sqrt((ydif * ydif) + (zdif * zdif));
  192. Vector2[] uvs = new Vector2[] { new Vector2(0, 0), new Vector2(width, 0), new Vector2(0, height), new Vector2(width, height) };
  193. Mesh returnmesh = new Mesh();
  194. returnmesh.vertices = verts;
  195. returnmesh.triangles = tris;
  196. returnmesh.uv = uvs;
  197. return returnmesh;
  198. }
  199. }