// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.GraphicsTools { /// /// Component which can be used to render an outline around a hierarchy of mesh renderers using /// the component. /// [DisallowMultipleComponent, AddComponentMenu("Scripts/GraphicsTools/MeshOutlineHierarchy")] public class MeshOutlineHierarchy : BaseMeshOutline { /// /// Defines how to exclude objects from the outline hierarchy. /// public enum ExclusionMode { None, Tag, NameStartsWith, NameContains, } /// /// Whether and how to exclude objects from the outline hierarchy. /// public ExclusionMode Exclusion { get { return exclusionMode; } set { if (exclusionMode != value) { exclusionMode = value; Refresh(); } } } [Tooltip("Whether and how to exclude objects from the outline hierarchy.")] [SerializeField, HideInInspector] private ExclusionMode exclusionMode = ExclusionMode.None; /// /// When exclusionMode is set to "NameStartsWith" or "NameContains" what string to match against. /// public string ExclusionString { get { return exclusionString; } set { if (exclusionString != value) { exclusionString = value; Refresh(); } } } [Tooltip("When exclusionMode is set to \"NameStartsWith\" or \"NameContains\" what string to match against.")] [SerializeField, HideInInspector] private string exclusionString = string.Empty; /// /// When exclusionMode is set to "NameStartsWith" or "NameContains" what string to match against. /// public string ExclusionTag { get { return exclusionTag; } set { if (exclusionTag != value) { exclusionTag = value; Refresh(); } } } [Tooltip("When exclusionMode is set to \"Tag\" what tag to compare against.")] [SerializeField, HideInInspector] private string exclusionTag = "Untagged"; private List meshOutlines = new List(); #region MonoBehaviour Implementation /// /// Creates a component on each child MeshRenderer/SkinnedMeshRenderer. /// private void Awake() { Create(); } /// /// Enables all child mesh outlines. /// private void OnEnable() { foreach (var meshOutline in meshOutlines) { if (meshOutline != null) { meshOutline.enabled = true; } } } /// /// Disables all child mesh outlines. /// private void OnDisable() { foreach (var meshOutline in meshOutlines) { if (meshOutline != null) { meshOutline.enabled = false; } } } /// /// Removes any components this component has created. /// private void OnDestroy() { // Don't use DestroyImmediate on the same object in OnDisable or OnDestroy. Clear(false); } #endregion MonoBehaviour Implementation #region BaseMeshOutline Implementation /// /// Forwards settings to all children s. /// public override void ApplyOutlineMaterial() { ApplyToChildren(); } /// /// Forwards settings to all children s. /// public override void ApplyOutlineWidth() { ApplyToChildren(); } /// /// Forwards settings to all children s. /// public override void ApplyStencilReference() { ApplyToChildren(); } #endregion BaseMeshOutline Implementation /// /// Removes and re-adds all this component has created. /// public void Refresh() { Clear(true); Create(); } /// /// Creates a component on each child MeshRenderer/SkinnedMeshRenderer. /// private void Create() { var meshRenderers = GetComponentsInChildren(); for (int i = 0; i < meshRenderers.Length; ++i) { AddMeshOutline(meshRenderers[i]); } var skinnedMeshRenderers = GetComponentsInChildren(); for (int i = 0; i < skinnedMeshRenderers.Length; ++i) { AddMeshOutline(skinnedMeshRenderers[i]); } } /// /// Removes any components this component has created. /// private void Clear(bool destroyImmediately) { for (int i = 0; i < meshOutlines.Count; ++i) { if (destroyImmediately) { DestroyImmediate(meshOutlines[i]); } else { Destroy(meshOutlines[i]); } } meshOutlines.Clear(); } private void AddMeshOutline(Renderer target) { switch (exclusionMode) { case ExclusionMode.None: default: break; case ExclusionMode.NameStartsWith: if (target.name.StartsWith(exclusionString)) { return; } break; case ExclusionMode.NameContains: if (target.name.Contains(exclusionString)) { return; } break; case ExclusionMode.Tag: if (target.CompareTag(exclusionTag)) { return; } break; } var meshOutline = target.gameObject.EnsureComponent(); meshOutline.CopyFrom(this); meshOutlines.Add(meshOutline); } private void ApplyToChildren() { foreach (var meshOutline in meshOutlines) { if (meshOutline != null) { meshOutline.CopyFrom(this); } } } } }