// Object Appearance|Interactions|30090 namespace VRTK { using UnityEngine; using System.Collections; using System.Collections.Generic; using Highlighters; /// /// A collection of static methods for calling controlling the appearance of GameObjects such as opacity, render state and highlighter state. /// /// /// **Script Usage:** /// > 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)`. /// public class VRTK_ObjectAppearance : MonoBehaviour { protected static VRTK_ObjectAppearance instance; protected Dictionary setOpacityCoroutines = new Dictionary(); /// /// The SetOpacity method allows the opacity of the given GameObject to be changed. `0f` is full transparency, `1f` is full opacity. /// /// The GameObject to change the renderer opacity on. /// The colour alpha/opacity level. `0f` to `1f`. /// The time to transition from the current opacity to the new opacity. public static void SetOpacity(GameObject model, float alpha, float transitionDuration = 0f) { SetupInstance(); if (instance != null) { instance.InternalSetOpacity(model, alpha, transitionDuration); } } /// /// 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. /// /// The GameObject to show the renderers for. /// An optional GameObject to ignore the renderer toggle on. public static void SetRendererVisible(GameObject model, GameObject ignoredModel = null) { SetupInstance(); if (instance != null) { instance.InternalSetRendererVisible(model, ignoredModel); } } /// /// 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. /// /// The GameObject to hide the renderers for. /// An optional GameObject to ignore the renderer toggle on. public static void SetRendererHidden(GameObject model, GameObject ignoredModel = null) { SetupInstance(); if (instance != null) { instance.InternalSetRendererHidden(model, ignoredModel); } } /// /// 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. /// /// If true then the renderers will be enabled, if false the renderers will be disabled. /// The GameObject to toggle the renderer states of. /// An optional GameObject to ignore the renderer toggle on. public static void ToggleRenderer(bool state, GameObject model, GameObject ignoredModel = null) { if (state) { SetRendererVisible(model, ignoredModel); } else { SetRendererHidden(model, ignoredModel); } } /// /// 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. /// /// The GameObject to check for visibility on. /// A GameObject to ignore when doing the visibility check. /// Returns true if any of the child renderers are enabled, returns false if all child renderers are disabled. public static bool IsRendererVisible(GameObject model, GameObject ignoredModel = null) { if (model != null) { Renderer[] renderers = model.GetComponentsInChildren(true); for (int i = 0; i < renderers.Length; i++) { Renderer renderer = renderers[i]; if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform)) && renderer.enabled) { return true; } } } return false; } /// /// The HighlightObject method calls the Highlight method on the highlighter attached to the given GameObject with the provided colour. /// /// The GameObject to attempt to call the Highlight on. /// The Color to highlight to. /// The duration in time to fade from the initial colour to the target colour. public static void HighlightObject(GameObject model, Color? highlightColor, float fadeDuration = 0f) { SetupInstance(); if (instance != null) { instance.InternalHighlightObject(model, highlightColor, fadeDuration); } } /// /// The UnhighlightObject method calls the Unhighlight method on the highlighter attached to the given GameObject. /// /// The GameObject to attempt to call the Unhighlight on. public static void UnhighlightObject(GameObject model) { SetupInstance(); if (instance != null) { instance.InternalUnhighlightObject(model); } } protected virtual void OnDisable() { foreach (KeyValuePair setOpacityCoroutine in setOpacityCoroutines) { CancelSetOpacityCoroutine(setOpacityCoroutine.Key); } } protected static void SetupInstance() { if (instance == null && VRTK_SDKManager.ValidInstance()) { instance = VRTK_SDKManager.instance.gameObject.AddComponent(); } } protected virtual void InternalSetOpacity(GameObject model, float alpha, float transitionDuration = 0f) { if (model && model.activeInHierarchy) { if (transitionDuration == 0f) { ChangeRendererOpacity(model, alpha); } else { CancelSetOpacityCoroutine(model); VRTK_SharedMethods.AddDictionaryValue(setOpacityCoroutines, model, StartCoroutine(TransitionRendererOpacity(model, GetInitialAlpha(model), alpha, transitionDuration))); } } } protected virtual void InternalSetRendererVisible(GameObject model, GameObject ignoredModel = null) { if (model != null) { Renderer[] renderers = model.GetComponentsInChildren(true); for (int i = 0; i < renderers.Length; i++) { Renderer renderer = renderers[i]; if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform))) { renderer.enabled = true; } } } EmitControllerEvents(model, true); } protected virtual void InternalSetRendererHidden(GameObject model, GameObject ignoredModel = null) { if (model != null) { Renderer[] renderers = model.GetComponentsInChildren(true); for (int i = 0; i < renderers.Length; i++) { Renderer renderer = renderers[i]; if (renderer.gameObject != ignoredModel && (ignoredModel == null || !renderer.transform.IsChildOf(ignoredModel.transform))) { renderer.enabled = false; } } } EmitControllerEvents(model, false); } protected virtual void InternalHighlightObject(GameObject model, Color? highlightColor, float fadeDuration = 0f) { VRTK_BaseHighlighter highlighter = model.GetComponentInChildren(); if (model.activeInHierarchy && highlighter != null) { highlighter.Highlight((highlightColor != null ? highlightColor : Color.white), fadeDuration); } } protected virtual void InternalUnhighlightObject(GameObject model) { VRTK_BaseHighlighter highlighter = model.GetComponentInChildren(); if (model.activeInHierarchy && highlighter != null) { highlighter.Unhighlight(); } } //If the object is a controller, then emit the relevant event for it. protected virtual void EmitControllerEvents(GameObject model, bool state) { GameObject controllerObject = null; //Check to see if the given model is either the left or right controller model alias object if (VRTK_DeviceFinder.GetModelAliasControllerHand(model) == SDK_BaseController.ControllerHand.Left) { controllerObject = VRTK_DeviceFinder.GetControllerLeftHand(false); } else if (VRTK_DeviceFinder.GetModelAliasControllerHand(model) == SDK_BaseController.ControllerHand.Right) { controllerObject = VRTK_DeviceFinder.GetControllerRightHand(false); } //if it is then attempt to get the controller events script from the script alias if (controllerObject != null && controllerObject.activeInHierarchy) { VRTK_ControllerEvents controllerEvents = controllerObject.GetComponentInChildren(); if (controllerEvents != null) { if (state) { controllerEvents.OnControllerVisible(controllerEvents.SetControllerEvent()); } else { controllerEvents.OnControllerHidden(controllerEvents.SetControllerEvent()); } } } } protected virtual void ChangeRendererOpacity(GameObject model, float alpha) { if (model != null) { alpha = Mathf.Clamp(alpha, 0f, 1f); Renderer[] renderers = model.GetComponentsInChildren(true); for (int i = 0; i < renderers.Length; i++) { Renderer renderer = renderers[i]; if (alpha < 1f) { renderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); renderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); renderer.material.SetInt("_ZWrite", 0); renderer.material.DisableKeyword("_ALPHATEST_ON"); renderer.material.DisableKeyword("_ALPHABLEND_ON"); renderer.material.EnableKeyword("_ALPHAPREMULTIPLY_ON"); renderer.material.renderQueue = 3000; } else { renderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); renderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); renderer.material.SetInt("_ZWrite", 1); renderer.material.DisableKeyword("_ALPHATEST_ON"); renderer.material.DisableKeyword("_ALPHABLEND_ON"); renderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); renderer.material.renderQueue = -1; } if (renderer.material.HasProperty("_Color")) { renderer.material.color = new Color(renderer.material.color.r, renderer.material.color.g, renderer.material.color.b, alpha); } } } } protected virtual float GetInitialAlpha(GameObject model) { Renderer modelRenderer = model.GetComponentInChildren(true); if (modelRenderer.material.HasProperty("_Color")) { return modelRenderer.material.color.a; } return 0f; } protected virtual IEnumerator TransitionRendererOpacity(GameObject model, float initialAlpha, float targetAlpha, float transitionDuration) { float elapsedTime = 0f; while (elapsedTime < transitionDuration) { float newAlpha = Mathf.Lerp(initialAlpha, targetAlpha, (elapsedTime / transitionDuration)); ChangeRendererOpacity(model, newAlpha); elapsedTime += Time.deltaTime; yield return null; } ChangeRendererOpacity(model, targetAlpha); } protected virtual void CancelSetOpacityCoroutine(GameObject model) { Coroutine currentOpacityRoutine = VRTK_SharedMethods.GetDictionaryValue(setOpacityCoroutines, model); if (currentOpacityRoutine != null) { StopCoroutine(currentOpacityRoutine); } } } }