YiHe_AllVersion/YHWeb/Assets/Plugins/HighlightingSystem/Scripts/Internal/HighlighterRenderer.cs

207 lines
5.2 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
[DisallowMultipleComponent]
public class HighlighterRenderer : MonoBehaviour
{
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
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";
private Renderer r;
private List<Data> data;
private Camera lastCamera = null;
private bool isAlive;
private Coroutine endOfFrame;
#region MonoBehaviour
//
void OnEnable()
{
endOfFrame = StartCoroutine(EndOfFrame());
}
//
void OnDisable()
{
lastCamera = null;
if (endOfFrame != null)
{
StopCoroutine(endOfFrame);
}
}
// Called once (before OnPreRender) for each camera if the object is visible
void OnWillRenderObject()
{
Camera cam = Camera.current;
// Another camera may intercept rendering and send it's own OnWillRenderObject events (i.e. water rendering),
// so we're caching currently rendering camera only if it has HighlighterBase component
if (HighlightingBase.IsHighlightingCamera(cam))
{
// VR Camera renders twice per frame (once for each eye), but OnWillRenderObject is called once so we have to cache reference to the camera
lastCamera = cam;
}
}
#endregion
#region Private Methods
//
IEnumerator EndOfFrame()
{
while (true)
{
yield return new WaitForEndOfFrame();
lastCamera = null;
if (!isAlive)
{
Destroy(this);
}
}
}
#endregion
#region Public Methods
//
public void Initialize(Material sharedOpaqueMaterial, Shader transparentShader) // int zTest, int stencilRef
{
data = new List<Data>();
r = GetComponent<Renderer>();
this.hideFlags = flags;
Material[] materials = r.sharedMaterials;
if (materials != null)
{
for (int i = 0; i < materials.Length; i++)
{
Material sourceMat = materials[i];
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);
//replacementMat.SetInt(ShaderPropertyID._ZTest, zTest);
//replacementMat.SetInt(ShaderPropertyID._StencilRef, stencilRef);
// To render both sides of the Sprite
if (r is SpriteRenderer) { replacementMat.SetInt(ShaderPropertyID._Cull, 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 = i;
data.Add(d);
}
}
}
//
public bool FillBuffer(CommandBuffer buffer)
{
if (r == null) { return false; }
if (lastCamera == Camera.current)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
buffer.DrawRenderer(r, d.material, d.submeshIndex);
}
}
return true;
}
// Sets given color as highlighting color on all transparent materials of this renderer
public void SetColorForTransparent(Color clr)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
if (d.transparent)
{
d.material.SetColor(ShaderPropertyID._Color, clr);
}
}
}
// Sets ZTest parameter on all transparent materials of this renderer
public void SetZTestForTransparent(int zTest)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
if (d.transparent)
{
d.material.SetInt(ShaderPropertyID._ZTest, zTest);
}
}
}
// Sets Stencil Ref parameter on all transparent materials of this renderer
public void SetStencilRefForTransparent(int stencilRef)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
if (d.transparent)
{
d.material.SetInt(ShaderPropertyID._StencilRef, stencilRef);
}
}
}
//
public void SetState(bool alive)
{
isAlive = alive;
}
#endregion
}
}