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.

423 lines
14 KiB

  1. //====================================================================================
  2. //
  3. // Purpose: To generate a bezier curve between at least 4 points in space and draw
  4. // a number of spheres across the generated curve
  5. //
  6. // This script is heavily based on the tutorial at:
  7. // http://catlikecoding.com/unity/tutorials/curves-and-splines/
  8. //
  9. //====================================================================================
  10. namespace VRTK
  11. {
  12. using UnityEngine;
  13. public static class Bezier
  14. {
  15. public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t)
  16. {
  17. t = Mathf.Clamp01(t);
  18. float oneMinusT = 1f - t;
  19. return
  20. oneMinusT * oneMinusT * p0 +
  21. 2f * oneMinusT * t * p1 +
  22. t * t * p2;
  23. }
  24. public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t)
  25. {
  26. return
  27. 2f * (1f - t) * (p1 - p0) +
  28. 2f * t * (p2 - p1);
  29. }
  30. public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
  31. {
  32. t = Mathf.Clamp01(t);
  33. float OneMinusT = 1f - t;
  34. return
  35. OneMinusT * OneMinusT * OneMinusT * p0 +
  36. 3f * OneMinusT * OneMinusT * t * p1 +
  37. 3f * OneMinusT * t * t * p2 +
  38. t * t * t * p3;
  39. }
  40. public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
  41. {
  42. t = Mathf.Clamp01(t);
  43. float oneMinusT = 1f - t;
  44. return
  45. 3f * oneMinusT * oneMinusT * (p1 - p0) +
  46. 6f * oneMinusT * t * (p2 - p1) +
  47. 3f * t * t * (p3 - p2);
  48. }
  49. }
  50. public class VRTK_CurveGenerator : MonoBehaviour
  51. {
  52. public enum BezierControlPointMode
  53. {
  54. Free,
  55. Aligned,
  56. Mirrored
  57. }
  58. protected Vector3[] points;
  59. protected GameObject[] items;
  60. protected BezierControlPointMode[] modes;
  61. protected bool loop;
  62. protected int frequency;
  63. protected bool customTracer;
  64. protected bool rescalePointerTracer;
  65. protected GameObject tracerLineRenderer;
  66. protected LineRenderer customLineRenderer;
  67. protected bool lineRendererAndItem;
  68. public virtual void Create(int setFrequency, float radius, GameObject tracer, bool rescaleTracer = false)
  69. {
  70. float circleSize = radius / 8;
  71. frequency = setFrequency;
  72. customLineRenderer = (tracer != null ? tracer.GetComponent<LineRenderer>() : null);
  73. lineRendererAndItem = (customLineRenderer != null && tracer.GetComponentInChildren<MeshFilter>());
  74. if (customLineRenderer != null)
  75. {
  76. tracerLineRenderer = Instantiate(tracer);
  77. tracerLineRenderer.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, name, "LineRenderer");
  78. for (int i = 0; i < tracerLineRenderer.transform.childCount; i++)
  79. {
  80. Destroy(tracerLineRenderer.transform.GetChild(i).gameObject);
  81. }
  82. customLineRenderer = tracerLineRenderer.GetComponent<LineRenderer>();
  83. #if UNITY_5_5
  84. customLineRenderer.numPositions = frequency;
  85. #elif UNITY_5_6_OR_NEWER
  86. customLineRenderer.positionCount = frequency;
  87. #else
  88. customLineRenderer.SetVertexCount(frequency);
  89. #endif
  90. }
  91. if (customLineRenderer == null || lineRendererAndItem)
  92. {
  93. items = new GameObject[frequency];
  94. for (int f = 0; f < items.Length; f++)
  95. {
  96. customTracer = true;
  97. items[f] = (tracer != null ? Instantiate(tracer) : CreateSphere());
  98. items[f].transform.SetParent(transform);
  99. items[f].layer = LayerMask.NameToLayer("Ignore Raycast");
  100. items[f].transform.localScale = new Vector3(circleSize, circleSize, circleSize);
  101. if (customLineRenderer != null)
  102. {
  103. Destroy(items[f].GetComponent<LineRenderer>());
  104. }
  105. }
  106. }
  107. rescalePointerTracer = rescaleTracer;
  108. }
  109. public virtual void SetPoints(Vector3[] controlPoints, Material material, Color color)
  110. {
  111. PointsInit(controlPoints);
  112. SetObjects(material, color);
  113. }
  114. public virtual Vector3[] GetPoints(Vector3[] controlPoints)
  115. {
  116. PointsInit(controlPoints);
  117. Vector3[] calculatedPoints = new Vector3[frequency];
  118. float stepSize = frequency * 1;
  119. if (Loop || stepSize == 1)
  120. {
  121. stepSize = VRTK_SharedMethods.DividerToMultiplier(stepSize);
  122. }
  123. else
  124. {
  125. stepSize = VRTK_SharedMethods.DividerToMultiplier((stepSize - 1));
  126. }
  127. for (int f = 0; f < frequency; f++)
  128. {
  129. calculatedPoints[f] = GetPoint(f * stepSize);
  130. }
  131. return calculatedPoints;
  132. }
  133. public virtual void TogglePoints(bool state)
  134. {
  135. gameObject.SetActive(state);
  136. if (tracerLineRenderer != null)
  137. {
  138. tracerLineRenderer.SetActive(state);
  139. }
  140. }
  141. protected virtual void OnDisable()
  142. {
  143. if (tracerLineRenderer != null)
  144. {
  145. tracerLineRenderer.SetActive(false);
  146. }
  147. }
  148. protected virtual void PointsInit(Vector3[] controlPoints)
  149. {
  150. points = controlPoints;
  151. modes = new BezierControlPointMode[]
  152. {
  153. BezierControlPointMode.Free,
  154. BezierControlPointMode.Free
  155. };
  156. }
  157. protected virtual GameObject CreateSphere()
  158. {
  159. customTracer = false;
  160. GameObject item = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  161. item.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, "Sphere");
  162. Destroy(item.GetComponent<SphereCollider>());
  163. item.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  164. item.GetComponent<MeshRenderer>().receiveShadows = false;
  165. return item;
  166. }
  167. protected virtual bool Loop
  168. {
  169. get
  170. {
  171. return loop;
  172. }
  173. set
  174. {
  175. loop = value;
  176. if (value == true)
  177. {
  178. modes[modes.Length - 1] = modes[0];
  179. SetControlPoint(0, points[0]);
  180. }
  181. }
  182. }
  183. protected virtual int ControlPointCount
  184. {
  185. get
  186. {
  187. return points.Length;
  188. }
  189. }
  190. protected virtual Vector3 GetControlPoint(int index)
  191. {
  192. return points[index];
  193. }
  194. protected virtual void SetControlPoint(int index, Vector3 point)
  195. {
  196. if (index % 3 == 0)
  197. {
  198. Vector3 delta = point - points[index];
  199. if (loop)
  200. {
  201. if (index == 0)
  202. {
  203. points[1] += delta;
  204. points[points.Length - 2] += delta;
  205. points[points.Length - 1] = point;
  206. }
  207. else if (index == points.Length - 1)
  208. {
  209. points[0] = point;
  210. points[1] += delta;
  211. points[index - 1] += delta;
  212. }
  213. else
  214. {
  215. points[index - 1] += delta;
  216. points[index + 1] += delta;
  217. }
  218. }
  219. else
  220. {
  221. if (index > 0)
  222. {
  223. points[index - 1] += delta;
  224. }
  225. if (index + 1 < points.Length)
  226. {
  227. points[index + 1] += delta;
  228. }
  229. }
  230. }
  231. points[index] = point;
  232. EnforceMode(index);
  233. }
  234. protected virtual void EnforceMode(int index)
  235. {
  236. int modeIndex = (index + 1) / 3;
  237. BezierControlPointMode mode = modes[modeIndex];
  238. if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1))
  239. {
  240. return;
  241. }
  242. int middleIndex = modeIndex * 3;
  243. int fixedIndex, enforcedIndex;
  244. if (index <= middleIndex)
  245. {
  246. fixedIndex = middleIndex - 1;
  247. if (fixedIndex < 0)
  248. {
  249. fixedIndex = points.Length - 2;
  250. }
  251. enforcedIndex = middleIndex + 1;
  252. if (enforcedIndex >= points.Length)
  253. {
  254. enforcedIndex = 1;
  255. }
  256. }
  257. else
  258. {
  259. fixedIndex = middleIndex + 1;
  260. if (fixedIndex >= points.Length)
  261. {
  262. fixedIndex = 1;
  263. }
  264. enforcedIndex = middleIndex - 1;
  265. if (enforcedIndex < 0)
  266. {
  267. enforcedIndex = points.Length - 2;
  268. }
  269. }
  270. Vector3 middle = points[middleIndex];
  271. Vector3 enforcedTangent = middle - points[fixedIndex];
  272. if (mode == BezierControlPointMode.Aligned)
  273. {
  274. enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);
  275. }
  276. points[enforcedIndex] = middle + enforcedTangent;
  277. }
  278. protected virtual int CurveCount
  279. {
  280. get
  281. {
  282. return (points.Length - 1) / 3;
  283. }
  284. }
  285. protected virtual Vector3 GetPoint(float t)
  286. {
  287. int i;
  288. if (t >= 1f)
  289. {
  290. t = 1f;
  291. i = points.Length - 4;
  292. }
  293. else
  294. {
  295. t = Mathf.Clamp01(t) * CurveCount;
  296. i = (int)t;
  297. t -= i;
  298. i *= 3;
  299. }
  300. return transform.TransformPoint(Bezier.GetPoint(points[i], points[i + 1], points[i + 2], points[i + 3], t));
  301. }
  302. protected virtual void SetObjects(Material material, Color color)
  303. {
  304. float stepSize = frequency * 1;
  305. if (Loop || stepSize == 1)
  306. {
  307. stepSize = VRTK_SharedMethods.DividerToMultiplier(stepSize);
  308. }
  309. else
  310. {
  311. stepSize = VRTK_SharedMethods.DividerToMultiplier((stepSize - 1));
  312. }
  313. SetPointData(material, color, stepSize);
  314. }
  315. protected virtual void SetPointData(Material material, Color color, float stepSize)
  316. {
  317. for (int f = 0; f < frequency; f++)
  318. {
  319. Vector3 position = GetPoint(f * stepSize);
  320. if (customLineRenderer != null)
  321. {
  322. customLineRenderer.SetPosition(f, position);
  323. SetMaterial(customLineRenderer.sharedMaterial, color);
  324. }
  325. if (customLineRenderer == null || lineRendererAndItem)
  326. {
  327. SetItemPosition(f, position, material, color, stepSize);
  328. }
  329. }
  330. }
  331. protected virtual void SetItemPosition(int currentIndex, Vector3 setPosition, Material material, Color color, float stepSize)
  332. {
  333. if (customTracer && (currentIndex == (frequency - 1)))
  334. {
  335. items[currentIndex].SetActive(false);
  336. return;
  337. }
  338. SetItemMaterial(items[currentIndex], material, color);
  339. items[currentIndex].transform.position = setPosition;
  340. Vector3 nextPosition = GetPoint((currentIndex + 1) * stepSize);
  341. Vector3 offset = nextPosition - setPosition;
  342. Vector3 lookPosition = offset.normalized;
  343. if (lookPosition != Vector3.zero)
  344. {
  345. items[currentIndex].transform.rotation = Quaternion.LookRotation(lookPosition);
  346. // rescale the custom tracer according to the length of the beam
  347. if (rescalePointerTracer)
  348. {
  349. Vector3 scl = items[currentIndex].transform.localScale;
  350. scl.z = offset.magnitude / 2f; // (assuming a center-based scaling)
  351. items[currentIndex].transform.localScale = scl;
  352. }
  353. }
  354. }
  355. protected virtual void SetItemMaterial(GameObject item, Material material, Color color)
  356. {
  357. Renderer[] itemRenderers = item.GetComponentsInChildren<Renderer>();
  358. for (int i = 0; i < itemRenderers.Length; i++)
  359. {
  360. if (material != null)
  361. {
  362. itemRenderers[i].material = material;
  363. }
  364. SetMaterial(itemRenderers[i].material, color);
  365. }
  366. }
  367. protected virtual void SetMaterial(Material material, Color color)
  368. {
  369. if (material != null)
  370. {
  371. material.EnableKeyword("_EMISSION");
  372. if (material.HasProperty("_Color"))
  373. {
  374. material.color = color;
  375. }
  376. if (material.HasProperty("_EmissionColor"))
  377. {
  378. material.SetColor("_EmissionColor", VRTK_SharedMethods.ColorDarken(color, 50));
  379. }
  380. }
  381. }
  382. }
  383. }