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.

321 lines
14 KiB

  1. // Object Appearance|Interactions|30090
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using Highlighters;
  8. /// <summary>
  9. /// A collection of static methods for calling controlling the appearance of GameObjects such as opacity, render state and highlighter state.
  10. /// </summary>
  11. /// <remarks>
  12. /// **Script Usage:**
  13. /// > There is no requirement to add this script to a GameObject as all of the public methods are static and can be called directly e.g. `VRTK_ObjectAppearance.SetOpacity(obj, 1f)`.
  14. /// </remarks>
  15. public class VRTK_ObjectAppearance : MonoBehaviour
  16. {
  17. protected static VRTK_ObjectAppearance instance;
  18. protected Dictionary<GameObject, Coroutine> setOpacityCoroutines = new Dictionary<GameObject, Coroutine>();
  19. /// <summary>
  20. /// The SetOpacity method allows the opacity of the given GameObject to be changed. `0f` is full transparency, `1f` is full opacity.
  21. /// </summary>
  22. /// <param name="model">The GameObject to change the renderer opacity on.</param>
  23. /// <param name="alpha">The colour alpha/opacity level. `0f` to `1f`.</param>
  24. /// <param name="transitionDuration">The time to transition from the current opacity to the new opacity.</param>
  25. public static void SetOpacity(GameObject model, float alpha, float transitionDuration = 0f)
  26. {
  27. SetupInstance();
  28. if (instance != null)
  29. {
  30. instance.InternalSetOpacity(model, alpha, transitionDuration);
  31. }
  32. }
  33. /// <summary>
  34. /// The SetRendererVisible method turns on renderers of a given GameObject. It can also be provided with an optional GameObject to ignore the render toggle on.
  35. /// </summary>
  36. /// <param name="model">The GameObject to show the renderers for.</param>
  37. /// <param name="ignoredModel">An optional GameObject to ignore the renderer toggle on.</param>
  38. public static void SetRendererVisible(GameObject model, GameObject ignoredModel = null)
  39. {
  40. SetupInstance();
  41. if (instance != null)
  42. {
  43. instance.InternalSetRendererVisible(model, ignoredModel);
  44. }
  45. }
  46. /// <summary>
  47. /// The SetRendererHidden method turns off renderers of a given GameObject. It can also be provided with an optional GameObject to ignore the render toggle on.
  48. /// </summary>
  49. /// <param name="model">The GameObject to hide the renderers for.</param>
  50. /// <param name="ignoredModel">An optional GameObject to ignore the renderer toggle on.</param>
  51. public static void SetRendererHidden(GameObject model, GameObject ignoredModel = null)
  52. {
  53. SetupInstance();
  54. if (instance != null)
  55. {
  56. instance.InternalSetRendererHidden(model, ignoredModel);
  57. }
  58. }
  59. /// <summary>
  60. /// The ToggleRenderer method turns on or off the renderers of a given GameObject. It can also be provided with an optional GameObject to ignore the render toggle of.
  61. /// </summary>
  62. /// <param name="state">If true then the renderers will be enabled, if false the renderers will be disabled.</param>
  63. /// <param name="model">The GameObject to toggle the renderer states of.</param>
  64. /// <param name="ignoredModel">An optional GameObject to ignore the renderer toggle on.</param>
  65. public static void ToggleRenderer(bool state, GameObject model, GameObject ignoredModel = null)
  66. {
  67. if (state)
  68. {
  69. SetRendererVisible(model, ignoredModel);
  70. }
  71. else
  72. {
  73. SetRendererHidden(model, ignoredModel);
  74. }
  75. }
  76. /// <summary>
  77. /// The IsRendererVisible method is used to check if a given GameObject is visible in the scene by any of it's child renderers being enabled.
  78. /// </summary>
  79. /// <param name="model">The GameObject to check for visibility on.</param>
  80. /// <param name="ignoredModel">A GameObject to ignore when doing the visibility check.</param>
  81. /// <returns>Returns true if any of the child renderers are enabled, returns false if all child renderers are disabled.</returns>
  82. public static bool IsRendererVisible(GameObject model, GameObject ignoredModel = null)
  83. {
  84. if (model != null)
  85. {
  86. Renderer[] renderers = model.GetComponentsInChildren<Renderer>(true);
  87. for (int i = 0; i < renderers.Length; i++)
  88. {
  89. Renderer renderer = renderers[i];
  90. if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform)) && renderer.enabled)
  91. {
  92. return true;
  93. }
  94. }
  95. }
  96. return false;
  97. }
  98. /// <summary>
  99. /// The HighlightObject method calls the Highlight method on the highlighter attached to the given GameObject with the provided colour.
  100. /// </summary>
  101. /// <param name="model">The GameObject to attempt to call the Highlight on.</param>
  102. /// <param name="highlightColor">The Color to highlight to.</param>
  103. /// <param name="fadeDuration">The duration in time to fade from the initial colour to the target colour.</param>
  104. public static void HighlightObject(GameObject model, Color? highlightColor, float fadeDuration = 0f)
  105. {
  106. SetupInstance();
  107. if (instance != null)
  108. {
  109. instance.InternalHighlightObject(model, highlightColor, fadeDuration);
  110. }
  111. }
  112. /// <summary>
  113. /// The UnhighlightObject method calls the Unhighlight method on the highlighter attached to the given GameObject.
  114. /// </summary>
  115. /// <param name="model">The GameObject to attempt to call the Unhighlight on.</param>
  116. public static void UnhighlightObject(GameObject model)
  117. {
  118. SetupInstance();
  119. if (instance != null)
  120. {
  121. instance.InternalUnhighlightObject(model);
  122. }
  123. }
  124. protected virtual void OnDisable()
  125. {
  126. foreach (KeyValuePair<GameObject, Coroutine> setOpacityCoroutine in setOpacityCoroutines)
  127. {
  128. CancelSetOpacityCoroutine(setOpacityCoroutine.Key);
  129. }
  130. }
  131. protected static void SetupInstance()
  132. {
  133. if (instance == null && VRTK_SDKManager.ValidInstance())
  134. {
  135. instance = VRTK_SDKManager.instance.gameObject.AddComponent<VRTK_ObjectAppearance>();
  136. }
  137. }
  138. protected virtual void InternalSetOpacity(GameObject model, float alpha, float transitionDuration = 0f)
  139. {
  140. if (model && model.activeInHierarchy)
  141. {
  142. if (transitionDuration == 0f)
  143. {
  144. ChangeRendererOpacity(model, alpha);
  145. }
  146. else
  147. {
  148. CancelSetOpacityCoroutine(model);
  149. VRTK_SharedMethods.AddDictionaryValue(setOpacityCoroutines, model, StartCoroutine(TransitionRendererOpacity(model, GetInitialAlpha(model), alpha, transitionDuration)));
  150. }
  151. }
  152. }
  153. protected virtual void InternalSetRendererVisible(GameObject model, GameObject ignoredModel = null)
  154. {
  155. if (model != null)
  156. {
  157. Renderer[] renderers = model.GetComponentsInChildren<Renderer>(true);
  158. for (int i = 0; i < renderers.Length; i++)
  159. {
  160. Renderer renderer = renderers[i];
  161. if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform)))
  162. {
  163. renderer.enabled = true;
  164. }
  165. }
  166. }
  167. EmitControllerEvents(model, true);
  168. }
  169. protected virtual void InternalSetRendererHidden(GameObject model, GameObject ignoredModel = null)
  170. {
  171. if (model != null)
  172. {
  173. Renderer[] renderers = model.GetComponentsInChildren<Renderer>(true);
  174. for (int i = 0; i < renderers.Length; i++)
  175. {
  176. Renderer renderer = renderers[i];
  177. if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform)))
  178. {
  179. renderer.enabled = false;
  180. }
  181. }
  182. }
  183. EmitControllerEvents(model, false);
  184. }
  185. protected virtual void InternalHighlightObject(GameObject model, Color? highlightColor, float fadeDuration = 0f)
  186. {
  187. VRTK_BaseHighlighter highlighter = model.GetComponentInChildren<VRTK_BaseHighlighter>();
  188. if (model.activeInHierarchy && highlighter != null)
  189. {
  190. highlighter.Highlight((highlightColor != null ? highlightColor : Color.white), fadeDuration);
  191. }
  192. }
  193. protected virtual void InternalUnhighlightObject(GameObject model)
  194. {
  195. VRTK_BaseHighlighter highlighter = model.GetComponentInChildren<VRTK_BaseHighlighter>();
  196. if (model.activeInHierarchy && highlighter != null)
  197. {
  198. highlighter.Unhighlight();
  199. }
  200. }
  201. //If the object is a controller, then emit the relevant event for it.
  202. protected virtual void EmitControllerEvents(GameObject model, bool state)
  203. {
  204. GameObject controllerObject = null;
  205. //Check to see if the given model is either the left or right controller model alias object
  206. if (VRTK_DeviceFinder.GetModelAliasControllerHand(model) == SDK_BaseController.ControllerHand.Left)
  207. {
  208. controllerObject = VRTK_DeviceFinder.GetControllerLeftHand(false);
  209. }
  210. else if (VRTK_DeviceFinder.GetModelAliasControllerHand(model) == SDK_BaseController.ControllerHand.Right)
  211. {
  212. controllerObject = VRTK_DeviceFinder.GetControllerRightHand(false);
  213. }
  214. //if it is then attempt to get the controller events script from the script alias
  215. if (controllerObject != null && controllerObject.activeInHierarchy)
  216. {
  217. VRTK_ControllerEvents controllerEvents = controllerObject.GetComponentInChildren<VRTK_ControllerEvents>();
  218. if (controllerEvents != null)
  219. {
  220. if (state)
  221. {
  222. controllerEvents.OnControllerVisible(controllerEvents.SetControllerEvent());
  223. }
  224. else
  225. {
  226. controllerEvents.OnControllerHidden(controllerEvents.SetControllerEvent());
  227. }
  228. }
  229. }
  230. }
  231. protected virtual void ChangeRendererOpacity(GameObject model, float alpha)
  232. {
  233. if (model != null)
  234. {
  235. alpha = Mathf.Clamp(alpha, 0f, 1f);
  236. Renderer[] renderers = model.GetComponentsInChildren<Renderer>(true);
  237. for (int i = 0; i < renderers.Length; i++)
  238. {
  239. Renderer renderer = renderers[i];
  240. if (alpha < 1f)
  241. {
  242. renderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  243. renderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  244. renderer.material.SetInt("_ZWrite", 0);
  245. renderer.material.DisableKeyword("_ALPHATEST_ON");
  246. renderer.material.DisableKeyword("_ALPHABLEND_ON");
  247. renderer.material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
  248. renderer.material.renderQueue = 3000;
  249. }
  250. else
  251. {
  252. renderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  253. renderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  254. renderer.material.SetInt("_ZWrite", 1);
  255. renderer.material.DisableKeyword("_ALPHATEST_ON");
  256. renderer.material.DisableKeyword("_ALPHABLEND_ON");
  257. renderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  258. renderer.material.renderQueue = -1;
  259. }
  260. if (renderer.material.HasProperty("_Color"))
  261. {
  262. renderer.material.color = new Color(renderer.material.color.r, renderer.material.color.g, renderer.material.color.b, alpha);
  263. }
  264. }
  265. }
  266. }
  267. protected virtual float GetInitialAlpha(GameObject model)
  268. {
  269. Renderer modelRenderer = model.GetComponentInChildren<Renderer>(true);
  270. if (modelRenderer.material.HasProperty("_Color"))
  271. {
  272. return modelRenderer.material.color.a;
  273. }
  274. return 0f;
  275. }
  276. protected virtual IEnumerator TransitionRendererOpacity(GameObject model, float initialAlpha, float targetAlpha, float transitionDuration)
  277. {
  278. float elapsedTime = 0f;
  279. while (elapsedTime < transitionDuration)
  280. {
  281. float newAlpha = Mathf.Lerp(initialAlpha, targetAlpha, (elapsedTime / transitionDuration));
  282. ChangeRendererOpacity(model, newAlpha);
  283. elapsedTime += Time.deltaTime;
  284. yield return null;
  285. }
  286. ChangeRendererOpacity(model, targetAlpha);
  287. }
  288. protected virtual void CancelSetOpacityCoroutine(GameObject model)
  289. {
  290. Coroutine currentOpacityRoutine = VRTK_SharedMethods.GetDictionaryValue(setOpacityCoroutines, model);
  291. if (currentOpacityRoutine != null)
  292. {
  293. StopCoroutine(currentOpacityRoutine);
  294. }
  295. }
  296. }
  297. }