SteamVR_PlayArea.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Draws different sized room-scale play areas for targeting content
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using UnityEngine.Rendering;
  8. using System.Collections;
  9. using Valve.VR;
  10. [ExecuteInEditMode, RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
  11. public class SteamVR_PlayArea : MonoBehaviour
  12. {
  13. public float borderThickness = 0.15f;
  14. public float wireframeHeight = 2.0f;
  15. public bool drawWireframeWhenSelectedOnly = false;
  16. public bool drawInGame = true;
  17. public enum Size
  18. {
  19. Calibrated,
  20. _400x300,
  21. _300x225,
  22. _200x150
  23. }
  24. public Size size;
  25. public Color color = Color.cyan;
  26. [HideInInspector]
  27. public Vector3[] vertices;
  28. public static bool GetBounds( Size size, ref HmdQuad_t pRect )
  29. {
  30. if (size == Size.Calibrated)
  31. {
  32. var initOpenVR = (!SteamVR.active && !SteamVR.usingNativeSupport);
  33. if (initOpenVR)
  34. {
  35. var error = EVRInitError.None;
  36. OpenVR.Init(ref error, EVRApplicationType.VRApplication_Utility);
  37. }
  38. var chaperone = OpenVR.Chaperone;
  39. bool success = (chaperone != null) && chaperone.GetPlayAreaRect(ref pRect);
  40. if (!success)
  41. Debug.LogWarning("Failed to get Calibrated Play Area bounds! Make sure you have tracking first, and that your space is calibrated.");
  42. if (initOpenVR)
  43. OpenVR.Shutdown();
  44. return success;
  45. }
  46. else
  47. {
  48. try
  49. {
  50. var str = size.ToString().Substring(1);
  51. var arr = str.Split(new char[] {'x'}, 2);
  52. // convert to half size in meters (from cm)
  53. var x = float.Parse(arr[0]) / 200;
  54. var z = float.Parse(arr[1]) / 200;
  55. pRect.vCorners0.v0 = x;
  56. pRect.vCorners0.v1 = 0;
  57. pRect.vCorners0.v2 = -z;
  58. pRect.vCorners1.v0 = -x;
  59. pRect.vCorners1.v1 = 0;
  60. pRect.vCorners1.v2 = -z;
  61. pRect.vCorners2.v0 = -x;
  62. pRect.vCorners2.v1 = 0;
  63. pRect.vCorners2.v2 = z;
  64. pRect.vCorners3.v0 = x;
  65. pRect.vCorners3.v1 = 0;
  66. pRect.vCorners3.v2 = z;
  67. return true;
  68. }
  69. catch {}
  70. }
  71. return false;
  72. }
  73. public void BuildMesh()
  74. {
  75. var rect = new HmdQuad_t();
  76. if ( !GetBounds( size, ref rect ) )
  77. return;
  78. var corners = new HmdVector3_t[] { rect.vCorners0, rect.vCorners1, rect.vCorners2, rect.vCorners3 };
  79. vertices = new Vector3[corners.Length * 2];
  80. for (int i = 0; i < corners.Length; i++)
  81. {
  82. var c = corners[i];
  83. vertices[i] = new Vector3(c.v0, 0.01f, c.v2);
  84. }
  85. if (borderThickness == 0.0f)
  86. {
  87. GetComponent<MeshFilter>().mesh = null;
  88. return;
  89. }
  90. for (int i = 0; i < corners.Length; i++)
  91. {
  92. int next = (i + 1) % corners.Length;
  93. int prev = (i + corners.Length - 1) % corners.Length;
  94. var nextSegment = (vertices[next] - vertices[i]).normalized;
  95. var prevSegment = (vertices[prev] - vertices[i]).normalized;
  96. var vert = vertices[i];
  97. vert += Vector3.Cross(nextSegment, Vector3.up) * borderThickness;
  98. vert += Vector3.Cross(prevSegment, Vector3.down) * borderThickness;
  99. vertices[corners.Length + i] = vert;
  100. }
  101. var triangles = new int[]
  102. {
  103. 0, 4, 1,
  104. 1, 4, 5,
  105. 1, 5, 2,
  106. 2, 5, 6,
  107. 2, 6, 3,
  108. 3, 6, 7,
  109. 3, 7, 0,
  110. 0, 7, 4
  111. };
  112. var uv = new Vector2[]
  113. {
  114. new Vector2(0.0f, 0.0f),
  115. new Vector2(1.0f, 0.0f),
  116. new Vector2(0.0f, 0.0f),
  117. new Vector2(1.0f, 0.0f),
  118. new Vector2(0.0f, 1.0f),
  119. new Vector2(1.0f, 1.0f),
  120. new Vector2(0.0f, 1.0f),
  121. new Vector2(1.0f, 1.0f)
  122. };
  123. var colors = new Color[]
  124. {
  125. color,
  126. color,
  127. color,
  128. color,
  129. new Color(color.r, color.g, color.b, 0.0f),
  130. new Color(color.r, color.g, color.b, 0.0f),
  131. new Color(color.r, color.g, color.b, 0.0f),
  132. new Color(color.r, color.g, color.b, 0.0f)
  133. };
  134. var mesh = new Mesh();
  135. GetComponent<MeshFilter>().mesh = mesh;
  136. mesh.vertices = vertices;
  137. mesh.uv = uv;
  138. mesh.colors = colors;
  139. mesh.triangles = triangles;
  140. var renderer = GetComponent<MeshRenderer>();
  141. renderer.material = new Material(Shader.Find("Sprites/Default"));
  142. renderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
  143. renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  144. renderer.receiveShadows = false;
  145. renderer.lightProbeUsage = LightProbeUsage.Off;
  146. }
  147. #if UNITY_EDITOR
  148. Hashtable values;
  149. void Update()
  150. {
  151. if (!Application.isPlaying)
  152. {
  153. var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
  154. bool rebuild = false;
  155. if (values == null || (borderThickness != 0.0f && GetComponent<MeshFilter>().sharedMesh == null))
  156. {
  157. rebuild = true;
  158. }
  159. else
  160. {
  161. foreach (var f in fields)
  162. {
  163. if (!values.Contains(f) || !f.GetValue(this).Equals(values[f]))
  164. {
  165. rebuild = true;
  166. break;
  167. }
  168. }
  169. }
  170. if (rebuild)
  171. {
  172. BuildMesh();
  173. values = new Hashtable();
  174. foreach (var f in fields)
  175. values[f] = f.GetValue(this);
  176. }
  177. }
  178. }
  179. #endif
  180. void OnDrawGizmos()
  181. {
  182. if (!drawWireframeWhenSelectedOnly)
  183. DrawWireframe();
  184. }
  185. void OnDrawGizmosSelected()
  186. {
  187. if (drawWireframeWhenSelectedOnly)
  188. DrawWireframe();
  189. }
  190. public void DrawWireframe()
  191. {
  192. if (vertices == null || vertices.Length == 0)
  193. return;
  194. var offset = transform.TransformVector(Vector3.up * wireframeHeight);
  195. for (int i = 0; i < 4; i++)
  196. {
  197. int next = (i + 1) % 4;
  198. var a = transform.TransformPoint(vertices[i]);
  199. var b = a + offset;
  200. var c = transform.TransformPoint(vertices[next]);
  201. var d = c + offset;
  202. Gizmos.DrawLine(a, b);
  203. Gizmos.DrawLine(a, c);
  204. Gizmos.DrawLine(b, d);
  205. }
  206. }
  207. public void OnEnable()
  208. {
  209. if (Application.isPlaying)
  210. {
  211. GetComponent<MeshRenderer>().enabled = drawInGame;
  212. // No need to remain enabled at runtime.
  213. // Anyone that wants to change properties at runtime
  214. // should call BuildMesh themselves.
  215. enabled = false;
  216. // If we want the configured bounds of the user,
  217. // we need to wait for tracking.
  218. if (drawInGame && size == Size.Calibrated)
  219. StartCoroutine(UpdateBounds());
  220. }
  221. }
  222. IEnumerator UpdateBounds()
  223. {
  224. GetComponent<MeshFilter>().mesh = null; // clear existing
  225. var chaperone = OpenVR.Chaperone;
  226. if (chaperone == null)
  227. yield break;
  228. while (chaperone.GetCalibrationState() != ChaperoneCalibrationState.OK)
  229. yield return null;
  230. BuildMesh();
  231. }
  232. }