AsteroidsManager.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using Unity.Collections;
  4. using Unity.Jobs;
  5. using UnityEngine;
  6. /// <summary>
  7. /// Used in the ZED planetarium sample to draw asteroids in the solar system's asteroid belt and rotate them.
  8. /// The asteroids are not instantiated as GameObjects, but drawn each frame with DrawMeshInstanced.
  9. /// Given there are many asteroids to draw, this reduces draw calls substantially along with some CPU overhead.
  10. /// </summary>
  11. public class AsteroidsManager : MonoBehaviour
  12. {
  13. /// <summary>
  14. /// Prefab containing the first asteroid mesh type.
  15. /// </summary>
  16. [Tooltip("Prefab containing the first asteroid mesh type.")]
  17. public GameObject asteroidsType1;
  18. /// <summary>
  19. /// Prefab containing the first asteroid mesh type.
  20. /// </summary>
  21. [Tooltip("Prefab containing the first asteroid mesh type.")]
  22. public GameObject asteroidsType2;
  23. /// <summary>
  24. /// How many asteroids of each type to draw. (There will be twice this number of asteroids in total).
  25. /// </summary>
  26. [Tooltip("How many asteroids of each type to draw. (There will be twice this number of asteroids in total).")]
  27. public static int amount = 100;
  28. /// <summary>
  29. /// The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1.
  30. /// </summary>
  31. [Tooltip("The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1. ")]
  32. public float radius = 1;
  33. /// <summary>
  34. /// How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter.
  35. /// </summary>
  36. [Tooltip("How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter. ")]
  37. public float offset = 0.05f;
  38. /// <summary>
  39. /// Holds the transform of where the asteroid started when it was created (for asteroid type 1).
  40. /// </summary>
  41. Matrix4x4[] listPositionsOrigin = new Matrix4x4[amount];
  42. /// <summary>
  43. /// Holds the current transforms of the type 1 asteroids, updated each frame based on the solar system's location and its orbit.
  44. /// </summary>
  45. Matrix4x4[] listPositions = new Matrix4x4[amount];
  46. /// <summary>
  47. /// Holds the transform of where the asteroid started when it was created (for asteroid type 1).
  48. /// </summary>
  49. Matrix4x4[] listPositionsOrigin2 = new Matrix4x4[amount];
  50. /// <summary>
  51. /// Holds the current transforms of the type 2 asteroids, updated each frame based on the solar system's location and its orbit.
  52. /// </summary>
  53. Matrix4x4[] listPositions2 = new Matrix4x4[amount];
  54. void Start()
  55. {
  56. CreateAsteroids(listPositionsOrigin, amount, radius, offset); //Create all type 1 asteroids.
  57. CreateAsteroids(listPositionsOrigin2, amount, radius, offset); //Create all type 2 asteroids.
  58. }
  59. /// <summary>
  60. /// Fills the first Matrix array with the origin positions and scales of randomly positioned asteroids.
  61. /// </summary>
  62. /// <param name="listPositionsOrigin">Array to be populated with matrixes of each asteroid's starting transform.</param>
  63. /// <param name="amount">How many asteroids to make.</param>
  64. /// <param name="radius">Radius of the asteroid belt/</param>
  65. /// <param name="offset">How far each asteroid can randomly deviate from the radius.</param>
  66. private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, int amount, float radius, float offset)
  67. {
  68. for (int i = 0; i < amount; ++i)
  69. {
  70. // 1. translation: displace along circle with 'radius' in range [-offset, offset]
  71. float angle = (float)i / (float)amount * 360.0f;
  72. float displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
  73. float x = Mathf.Sin(angle) * radius + displacement;
  74. displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
  75. float y = displacement * 2.0f; // keep height of asteroid field smaller compared to width of x and z
  76. displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
  77. float z = Mathf.Cos(angle) * radius + displacement;
  78. Vector3 position = new Vector3(x, y, z);
  79. //position = center.TransformPoint(position);
  80. //// 2. scale: Scale between 0.05 and 0.25f
  81. float scale = Random.Range(0.1f, 0.3f);
  82. //model = glm::scale(model, glm::vec3(scale));
  83. // 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
  84. float rotAngle = (Random.Range(0, 100000) % 360);
  85. //Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.identity, new Vector3(scale, scale, scale));
  86. Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.Euler(rotAngle, rotAngle, rotAngle), new Vector3(scale, scale, scale));
  87. listPositionsOrigin[i] = m;
  88. }
  89. }
  90. /// <summary>
  91. /// Called each frame to move, rotate and scale the asteroids based on this object's transform and their orbit.
  92. /// </summary>
  93. /// <param name="listPositionsOrigin">All asteroids' initial matrixes.</param>
  94. /// <param name="listPositions">All asteroids' current matrixes.</param>
  95. void UpdatePosition(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPositions)
  96. {
  97. for (int i = 0; i < listPositionsOrigin.Length; ++i)
  98. {
  99. listPositionsOrigin[i] = listPositionsOrigin[i] * Matrix4x4.TRS(Vector3.zero,
  100. Quaternion.Euler(Time.deltaTime * Random.Range(0, 100), Time.deltaTime * Random.Range(0, 100), Time.deltaTime * Random.Range(0, 100)),
  101. Vector3.one);
  102. listPositions[i] = transform.localToWorldMatrix* ( listPositionsOrigin[i]);
  103. }
  104. }
  105. // Update is called once per frame
  106. void Update()
  107. {
  108. foreach(ZEDManager manager in ZEDManager.GetInstances())
  109. {
  110. DrawAsteroids(manager);
  111. }
  112. }
  113. private void DrawAsteroids(ZEDManager manager)
  114. {
  115. Camera leftcamera = manager.GetLeftCamera();
  116. Camera rightcamera = manager.GetRightCamera();
  117. //Update positions and draw asteroids of type 1
  118. UpdatePosition(listPositionsOrigin, listPositions);
  119. Graphics.DrawMeshInstanced(asteroidsType1.GetComponent<MeshFilter>().sharedMesh,
  120. 0, asteroidsType1.GetComponent<MeshRenderer>().sharedMaterial,
  121. listPositions,
  122. listPositions.Length,
  123. null,
  124. UnityEngine.Rendering.ShadowCastingMode.Off,
  125. false,
  126. gameObject.layer,
  127. leftcamera);
  128. if (manager.IsStereoRig)
  129. {
  130. Graphics.DrawMeshInstanced(asteroidsType1.GetComponent<MeshFilter>().sharedMesh,
  131. 0,
  132. asteroidsType1.GetComponent<MeshRenderer>().sharedMaterial,
  133. listPositions,
  134. listPositions.Length,
  135. null,
  136. UnityEngine.Rendering.ShadowCastingMode.Off,
  137. false,
  138. gameObject.layer,
  139. rightcamera);
  140. }
  141. //Update positions and draw asteroids of type 2
  142. UpdatePosition(listPositionsOrigin2, listPositions2);
  143. Graphics.DrawMeshInstanced(asteroidsType2.GetComponent<MeshFilter>().sharedMesh,
  144. 0,
  145. asteroidsType2.GetComponent<MeshRenderer>().sharedMaterial,
  146. listPositions2,
  147. listPositions2.Length,
  148. null,
  149. UnityEngine.Rendering.ShadowCastingMode.Off,
  150. false,
  151. gameObject.layer,
  152. leftcamera);
  153. if (manager.IsStereoRig)
  154. {
  155. Graphics.DrawMeshInstanced(asteroidsType2.GetComponent<MeshFilter>().sharedMesh,
  156. 0,
  157. asteroidsType2.GetComponent<MeshRenderer>().sharedMaterial,
  158. listPositions2,
  159. listPositions2.Length,
  160. null,
  161. UnityEngine.Rendering.ShadowCastingMode.Off,
  162. false,
  163. gameObject.layer,
  164. rightcamera);
  165. }
  166. }
  167. }