NewN_UAVPlane/Assets/Plugins/HighlightingSystem/Scripts/Internal/HighlighterRenderer.cs

215 lines
5.2 KiB
C#

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> data = new List<Data>();
#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<int> submeshIndices)
{
data.Clear();
r = GetComponent<Renderer>();
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
}
}