using UnityEngine; using UnityEngine.Rendering; using System.Collections; using System.Collections.Generic; namespace HighlightingSystem { [DisallowMultipleComponent] [AddComponentMenu("")] // Hide in 'Add Component' menu [UnityEngine.Internal.ExcludeFromDocs] public class HighlighterRenderer : MonoBehaviour { [UnityEngine.Internal.ExcludeFromDocs] private struct Data { public Material material; public int submeshIndex; public bool transparent; } #region Constants // Default transparency cutoff value (used for shaders without _Cutoff property) static private float transparentCutoff = 0.5f; // Flags to hide and don't save this component in editor private const HideFlags flags = HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.NotEditable | HideFlags.DontSaveInBuild; // Cull Off private const int cullOff = (int)CullMode.Off; #endregion #region Static Fields static private readonly string sRenderType = "RenderType"; static private readonly string sOpaque = "Opaque"; static private readonly string sTransparent = "Transparent"; static private readonly string sTransparentCutout = "TransparentCutout"; static private readonly string sMainTex = "_MainTex"; #endregion #region Public Fields public bool isAlive = false; #endregion #region Private Fields private Renderer r; private List data = new List(); #endregion #region MonoBehaviour // void Awake() { this.hideFlags = flags; } // void OnEnable() { EndOfFrame.AddListener(OnEndOfFrame); } // void OnDisable() { EndOfFrame.RemoveListener(OnEndOfFrame); } // Called once (before OnPreRender) for each camera if the object is visible. // The function is called during the culling process just before rendering each culled object. void OnWillRenderObject() { HighlightingBase.SetVisible(this); } // void OnDestroy() { // Data will be null if Undo / Redo was performed in Editor to delete / restore object with this component if (data == null) { return; } for (int i = 0, imax = data.Count; i < imax; i++) { Data d = data[i]; // Unity never garbage-collects unreferenced materials, so it is our responsibility to destroy them if (d.transparent) { Destroy(d.material); } } } #endregion #region Public Methods // public void Initialize(Material sharedOpaqueMaterial, Shader transparentShader, List submeshIndices) { data.Clear(); r = GetComponent(); Material[] materials = r.sharedMaterials; int materialsLength = materials.Length; if (materials == null || materialsLength == 0) { return; } // Highlight all submeshes if (submeshIndices.Count == 1 && submeshIndices[0] == -1) { submeshIndices.Clear(); for (int i = 0; i < materialsLength; i++) { submeshIndices.Add(i); } } // Prepare specified submeshIndices for (int i = 0, imax = submeshIndices.Count; i < imax; i++) { int submeshIndex = submeshIndices[i]; // Invalid submeshIndex if (submeshIndex >= materialsLength) { continue; } Material sourceMat = materials[submeshIndex]; if (sourceMat == null) { continue; } Data d = new Data(); string tag = sourceMat.GetTag(sRenderType, true, sOpaque); if (tag == sTransparent || tag == sTransparentCutout) { Material replacementMat = new Material(transparentShader); // To render both sides of the Sprite if (r is SpriteRenderer) { replacementMat.SetInt(ShaderPropertyID._HighlightingCull, cullOff); } if (sourceMat.HasProperty(ShaderPropertyID._MainTex)) { replacementMat.SetTexture(ShaderPropertyID._MainTex, sourceMat.mainTexture); replacementMat.SetTextureOffset(sMainTex, sourceMat.mainTextureOffset); replacementMat.SetTextureScale(sMainTex, sourceMat.mainTextureScale); } int cutoff = ShaderPropertyID._Cutoff; replacementMat.SetFloat(cutoff, sourceMat.HasProperty(cutoff) ? sourceMat.GetFloat(cutoff) : transparentCutoff); d.material = replacementMat; d.transparent = true; } else { d.material = sharedOpaqueMaterial; d.transparent = false; } d.submeshIndex = submeshIndex; data.Add(d); } } // public void SetOverlay(bool overlay) { for (int i = 0, imax = data.Count; i < imax; i++) { Data d = data[i]; if (d.transparent) { d.material.SetKeyword(HighlighterCore.keywordOverlay, overlay); } } } // Sets given color as highlighting color on all transparent materials of this renderer public void SetColor(Color clr) { for (int i = 0, imax = data.Count; i < imax; i++) { Data d = data[i]; if (d.transparent) { d.material.SetColor(ShaderPropertyID._HighlightingColor, clr); } } } // public void FillBuffer(CommandBuffer buffer) { for (int i = 0, imax = data.Count; i < imax; i++) { Data d = data[i]; buffer.DrawRenderer(r, d.material, d.submeshIndex); } } // public bool IsValid() { return r != null; } #endregion #region Private Methods // private void OnEndOfFrame() { if (!isAlive) { Destroy(this); } } #endregion } }