Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
6.5 KiB

  1. /************************************************************************************
  2. Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  3. See SampleFramework license.txt for license terms. Unless required by applicable law
  4. or agreed to in writing, the sample code is provided AS IS WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied. See the license for specific
  6. language governing permissions and limitations under the license.
  7. ************************************************************************************/
  8. using UnityEngine;
  9. using UnityEngine.Assertions;
  10. namespace OculusSampleFramework
  11. {
  12. public class TrackSegment : MonoBehaviour
  13. {
  14. public enum SegmentType
  15. {
  16. Straight = 0,
  17. LeftTurn,
  18. RightTurn,
  19. Switch
  20. }
  21. [SerializeField] private SegmentType _segmentType = SegmentType.Straight;
  22. [SerializeField] private MeshFilter _straight = null;
  23. [SerializeField] private MeshFilter _leftTurn = null;
  24. [SerializeField] private MeshFilter _rightTurn = null;
  25. private float _gridSize = 0.8f;
  26. private int _subDivCount = 20;
  27. private const float _originalGridSize = 0.8f;
  28. private const float _trackWidth = 0.15f;
  29. private GameObject _mesh = null;
  30. public float StartDistance { get; set; }
  31. // create variables here to avoid realtime allocation
  32. private Pose _p1 = new Pose();
  33. private Pose _p2 = new Pose();
  34. public float GridSize
  35. {
  36. get
  37. {
  38. return _gridSize;
  39. }
  40. private set
  41. {
  42. _gridSize = value;
  43. }
  44. }
  45. public int SubDivCount
  46. {
  47. get
  48. {
  49. return _subDivCount;
  50. }
  51. set
  52. {
  53. _subDivCount = value;
  54. }
  55. }
  56. public SegmentType Type
  57. {
  58. get
  59. {
  60. return _segmentType;
  61. }
  62. }
  63. private Pose _endPose = new Pose();
  64. public Pose EndPose
  65. {
  66. get
  67. {
  68. UpdatePose(SegmentLength, _endPose);
  69. return _endPose;
  70. }
  71. }
  72. public float Radius
  73. {
  74. get
  75. {
  76. return 0.5f * GridSize;
  77. }
  78. }
  79. public float setGridSize(float size)
  80. {
  81. GridSize = size;
  82. return GridSize / _originalGridSize;
  83. }
  84. public float SegmentLength
  85. {
  86. get
  87. {
  88. switch (Type)
  89. {
  90. case SegmentType.Straight:
  91. return GridSize;
  92. case SegmentType.LeftTurn:
  93. case SegmentType.RightTurn:
  94. // return quarter of circumference.
  95. return 0.5f * Mathf.PI * Radius;
  96. }
  97. return 1f;
  98. }
  99. }
  100. private void Awake()
  101. {
  102. Assert.IsNotNull(_straight);
  103. Assert.IsNotNull(_leftTurn);
  104. Assert.IsNotNull(_rightTurn);
  105. }
  106. /// <summary>
  107. /// Updates pose given distance into segment. While this mutates a value,
  108. /// it avoids generating a new object.
  109. /// </summary>
  110. public void UpdatePose(float distanceIntoSegment, Pose pose)
  111. {
  112. if (Type == SegmentType.Straight)
  113. {
  114. pose.Position = transform.position + distanceIntoSegment * transform.forward;
  115. pose.Rotation = transform.rotation;
  116. }
  117. else if (Type == SegmentType.LeftTurn)
  118. {
  119. float normalizedDistanceIntoSegment = distanceIntoSegment / SegmentLength;
  120. // the turn is 90 degrees, so find out how far we are into it
  121. float angle = 0.5f * Mathf.PI * normalizedDistanceIntoSegment;
  122. // unity is left handed so the rotations go the opposite directions in X for left turns --
  123. // invert that by subtracting by radius. also note the angle negation below
  124. Vector3 localPosition = new Vector3(Radius * Mathf.Cos(angle) - Radius, 0, Radius * Mathf.Sin(angle));
  125. Quaternion localRotation = Quaternion.Euler(0, -angle * Mathf.Rad2Deg, 0);
  126. pose.Position = transform.TransformPoint(localPosition);
  127. pose.Rotation = transform.rotation * localRotation;
  128. }
  129. else if (Type == SegmentType.RightTurn)
  130. {
  131. // when going to right, start from PI (180) and go toward 90
  132. float angle = Mathf.PI - 0.5f * Mathf.PI * distanceIntoSegment / SegmentLength;
  133. // going right means we start at radius distance away, and decrease toward zero
  134. Vector3 localPosition = new Vector3(Radius * Mathf.Cos(angle) + Radius, 0, Radius * Mathf.Sin(angle));
  135. Quaternion localRotation = Quaternion.Euler(0, (Mathf.PI - angle) * Mathf.Rad2Deg, 0);
  136. pose.Position = transform.TransformPoint(localPosition);
  137. pose.Rotation = transform.rotation * localRotation;
  138. }
  139. else
  140. {
  141. pose.Position = Vector3.zero;
  142. pose.Rotation = Quaternion.identity;
  143. }
  144. }
  145. private void Update()
  146. {
  147. // uncomment to debug the track path
  148. //DrawDebugLines();
  149. }
  150. private void OnDisable()
  151. {
  152. Destroy(_mesh);
  153. }
  154. private void DrawDebugLines()
  155. {
  156. for (int i = 1; i < SubDivCount + 1; i++)
  157. {
  158. float len = SegmentLength / SubDivCount;
  159. UpdatePose((i - 1) * len, _p1);
  160. UpdatePose(i * len, _p2);
  161. // right segment from p1 to p2
  162. var halfTrackWidth = 0.5f * _trackWidth;
  163. Debug.DrawLine(_p1.Position + halfTrackWidth * (_p1.Rotation * Vector3.right),
  164. _p2.Position + halfTrackWidth * (_p2.Rotation * Vector3.right));
  165. // left segment from p1 to p2
  166. Debug.DrawLine(_p1.Position - halfTrackWidth * (_p1.Rotation * Vector3.right),
  167. _p2.Position - halfTrackWidth * (_p2.Rotation * Vector3.right));
  168. }
  169. // bottom bound
  170. Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right,
  171. transform.position + 0.5f * GridSize * transform.right, Color.yellow);
  172. // left bound
  173. Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right,
  174. transform.position - 0.5f * GridSize * transform.right + GridSize * transform.forward, Color.yellow);
  175. // right bound
  176. Debug.DrawLine(transform.position + 0.5f * GridSize * transform.right,
  177. transform.position + 0.5f * GridSize * transform.right + GridSize * transform.forward, Color.yellow);
  178. // top bound
  179. Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right +
  180. GridSize * transform.forward, transform.position +
  181. 0.5f * GridSize * transform.right + GridSize * transform.forward,
  182. Color.yellow);
  183. }
  184. public void RegenerateTrackAndMesh()
  185. {
  186. if (transform.childCount > 0 && !_mesh)
  187. {
  188. _mesh = transform.GetChild(0).gameObject;
  189. }
  190. if (_mesh)
  191. {
  192. DestroyImmediate(_mesh);
  193. }
  194. if (_segmentType == SegmentType.LeftTurn)
  195. {
  196. _mesh = Instantiate(_leftTurn.gameObject);
  197. }
  198. else if (_segmentType == SegmentType.RightTurn)
  199. {
  200. _mesh = Instantiate(_rightTurn.gameObject);
  201. }
  202. else
  203. {
  204. _mesh = Instantiate(_straight.gameObject);
  205. }
  206. _mesh.transform.SetParent(transform, false);
  207. _mesh.transform.position += GridSize / 2.0f * transform.forward;
  208. _mesh.transform.localScale = new Vector3(GridSize / _originalGridSize, GridSize / _originalGridSize,
  209. GridSize / _originalGridSize);
  210. }
  211. }
  212. }