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

634 lines
16 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.XR;
using System.Collections;
using System.Collections.Generic;
#if UNITY_5_5_OR_NEWER
using UnityEngine.Profiling;
#endif
namespace HighlightingSystem
{
public enum BlurDirections : int
{
Diagonal,
Straight,
All
}
public enum AntiAliasing : int
{
QualitySettings,
Disabled,
MSAA2x,
MSAA4x,
MSAA8x,
}
[DisallowMultipleComponent]
[RequireComponent(typeof(Camera))]
public class HighlightingBase : MonoBehaviour
{
#region Static Fields and Constants
static protected readonly Color colorClear = new Color(0f, 0f, 0f, 0f);
static protected readonly string renderBufferName = "HighlightingSystem";
static protected readonly Matrix4x4 identityMatrix = Matrix4x4.identity;
static protected readonly string keywordStraightDirections = "STRAIGHT_DIRECTIONS";
static protected readonly string keywordAllDirections = "ALL_DIRECTIONS";
static protected readonly string profileHighlightingSystem = "HighlightingSystem";
protected const CameraEvent queue = CameraEvent.BeforeImageEffectsOpaque;
static protected Camera currentCamera;
static protected HashSet<HighlighterRenderer> visibleRenderers = new HashSet<HighlighterRenderer>();
#endregion
#region Accessors
// True if supported on this platform
public bool isSupported
{
get
{
return CheckSupported(false);
}
}
public float fillAlpha
{
get { return _fillAlpha; }
set
{
value = Mathf.Clamp01(value);
if (_fillAlpha != value)
{
if (Application.isPlaying)
{
cutMaterial.SetFloat(ShaderPropertyID._HighlightingFillAlpha, value);
}
_fillAlpha = value;
}
}
}
// Highlighting buffer size downsample factor
public int downsampleFactor
{
get { return _downsampleFactor; }
set
{
if (_downsampleFactor != value)
{
// Is power of two check
if ((value != 0) && ((value & (value - 1)) == 0))
{
_downsampleFactor = value;
}
else
{
Debug.LogWarning("HighlightingSystem : Prevented attempt to set incorrect downsample factor value.");
}
}
}
}
// Blur iterations
public int iterations
{
get { return _iterations; }
set
{
if (_iterations != value)
{
_iterations = value;
}
}
}
// Blur minimal spread
public float blurMinSpread
{
get { return _blurMinSpread; }
set
{
if (_blurMinSpread != value)
{
_blurMinSpread = value;
}
}
}
// Blur spread per iteration
public float blurSpread
{
get { return _blurSpread; }
set
{
if (_blurSpread != value)
{
_blurSpread = value;
}
}
}
// Blurring intensity for the blur material
public float blurIntensity
{
get { return _blurIntensity; }
set
{
if (_blurIntensity != value)
{
_blurIntensity = value;
if (Application.isPlaying)
{
blurMaterial.SetFloat(ShaderPropertyID._HighlightingIntensity, _blurIntensity);
}
}
}
}
public BlurDirections blurDirections
{
get { return _blurDirections; }
set
{
if (_blurDirections != value)
{
_blurDirections = value;
if (Application.isPlaying)
{
blurMaterial.SetKeyword(keywordStraightDirections, _blurDirections == BlurDirections.Straight);
blurMaterial.SetKeyword(keywordAllDirections, _blurDirections == BlurDirections.All);
}
}
}
}
// Blitter component reference (optional)
public HighlightingBlitter blitter
{
get { return _blitter; }
set
{
if (_blitter != value)
{
if (_blitter != null)
{
_blitter.Unregister(this);
}
_blitter = value;
if (_blitter != null)
{
_blitter.Register(this);
}
}
}
}
public AntiAliasing antiAliasing
{
get { return _antiAliasing; }
set
{
if (_antiAliasing != value)
{
_antiAliasing = value;
}
}
}
#endregion
#region Protected Fields
protected CommandBuffer renderBuffer;
protected RenderTextureDescriptor cachedDescriptor;
[SerializeField]
protected float _fillAlpha = 0f;
[FormerlySerializedAs("downsampleFactor")]
[SerializeField]
protected int _downsampleFactor = 4;
[FormerlySerializedAs("iterations")]
[SerializeField]
protected int _iterations = 2;
[FormerlySerializedAs("blurMinSpread")]
[SerializeField]
protected float _blurMinSpread = 0.65f;
[FormerlySerializedAs("blurSpread")]
[SerializeField]
protected float _blurSpread = 0.25f;
[SerializeField]
protected float _blurIntensity = 0.3f;
[SerializeField]
protected BlurDirections _blurDirections = BlurDirections.Diagonal;
[SerializeField]
protected HighlightingBlitter _blitter;
[SerializeField]
protected AntiAliasing _antiAliasing = AntiAliasing.QualitySettings;
// RenderTargetidentifier for the highlightingBuffer RenderTexture
protected RenderTargetIdentifier highlightingBufferID;
protected RenderTargetIdentifier blur1ID;
protected RenderTargetIdentifier blur2ID;
// RenderTexture with highlighting buffer
protected RenderTexture highlightingBuffer = null;
// Camera reference
protected Camera cam = null;
// Material parameters
protected const int BLUR = 0;
protected const int CUT = 1;
protected const int COMP = 2;
static protected readonly string[] shaderPaths = new string[]
{
"Hidden/Highlighted/Blur",
"Hidden/Highlighted/Cut",
"Hidden/Highlighted/Composite",
};
static protected Shader[] shaders;
static protected Material[] materials;
// Dynamic materials
protected Material blurMaterial;
protected Material cutMaterial;
protected Material compMaterial;
static protected bool initialized = false;
#endregion
#region MonoBehaviour
//
protected virtual void OnEnable()
{
Initialize();
if (!CheckSupported(true))
{
enabled = false;
Debug.LogError("HighlightingSystem : Highlighting System has been disabled due to unsupported Unity features on the current platform!");
return;
}
blur1ID = new RenderTargetIdentifier(ShaderPropertyID._HighlightingBlur1);
blur2ID = new RenderTargetIdentifier(ShaderPropertyID._HighlightingBlur2);
blurMaterial = new Material(materials[BLUR]);
cutMaterial = new Material(materials[CUT]);
compMaterial = new Material(materials[COMP]);
// Set initial material properties
blurMaterial.SetKeyword(keywordStraightDirections, _blurDirections == BlurDirections.Straight);
blurMaterial.SetKeyword(keywordAllDirections, _blurDirections == BlurDirections.All);
blurMaterial.SetFloat(ShaderPropertyID._HighlightingIntensity, _blurIntensity);
cutMaterial.SetFloat(ShaderPropertyID._HighlightingFillAlpha, _fillAlpha);
renderBuffer = new CommandBuffer();
renderBuffer.name = renderBufferName;
cam = GetComponent<Camera>();
cam.depthTextureMode |= DepthTextureMode.Depth;
cam.AddCommandBuffer(queue, renderBuffer);
if (_blitter != null)
{
_blitter.Register(this);
}
EndOfFrame.AddListener(OnEndOfFrame);
}
//
protected virtual void OnDisable()
{
if (renderBuffer != null)
{
cam.RemoveCommandBuffer(queue, renderBuffer);
renderBuffer = null;
}
if (highlightingBuffer != null && highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
highlightingBuffer = null;
}
if (_blitter != null)
{
_blitter.Unregister(this);
}
EndOfFrame.RemoveListener(OnEndOfFrame);
}
//
protected virtual void OnPreCull()
{
currentCamera = cam;
visibleRenderers.Clear();
}
//
protected virtual void OnPreRender()
{
Profiler.BeginSample("HighlightingSystem.OnPreRender");
var descriptor = GetDescriptor();
if (highlightingBuffer == null || !Equals(cachedDescriptor, descriptor))
{
if (highlightingBuffer != null)
{
if (highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
}
highlightingBuffer = null;
}
cachedDescriptor = descriptor;
highlightingBuffer = new RenderTexture(cachedDescriptor);
highlightingBuffer.filterMode = FilterMode.Point;
highlightingBuffer.wrapMode = TextureWrapMode.Clamp;
if (!highlightingBuffer.Create())
{
Debug.LogError("HighlightingSystem : UpdateHighlightingBuffer() : Failed to create highlightingBuffer RenderTexture!");
}
highlightingBufferID = new RenderTargetIdentifier(highlightingBuffer);
compMaterial.SetTexture(ShaderPropertyID._HighlightingBuffer, highlightingBuffer);
}
RebuildCommandBuffer();
Profiler.EndSample();
}
// Do not remove!
// Having this method in this script is necessary to support multiple cameras with different clear flags even in case custom blitter is being used.
// Also, CommandBuffer is bound to CameraEvent.BeforeImageEffectsOpaque event,
// so Unity will spam 'depthSurface == NULL || rcolorZero->backBuffer == depthSurface->backBuffer' error even if MSAA is enabled
protected virtual void OnRenderImage(RenderTexture src, RenderTexture dst)
{
Profiler.BeginSample("HighlightingSystem.OnRenderImage");
if (blitter == null)
{
Blit(src, dst);
}
else
{
Graphics.Blit(src, dst);
}
Profiler.EndSample();
}
//
protected virtual void OnEndOfFrame()
{
currentCamera = null;
visibleRenderers.Clear();
}
#endregion
#region Internal
//
[UnityEngine.Internal.ExcludeFromDocs]
static public void SetVisible(HighlighterRenderer renderer)
{
// Another camera may intercept rendering and send it's own OnWillRenderObject events (i.e. water rendering).
// Also, VR Camera with Multi Pass Stereo Rendering Method renders twice per frame (once for each eye),
// but OnWillRenderObject is called once so we have to check.
if (Camera.current != currentCamera) { return; }
// Add to the list of renderers visible for the current Highlighting renderer
visibleRenderers.Add(renderer);
}
//
[UnityEngine.Internal.ExcludeFromDocs]
static public bool GetVisible(HighlighterRenderer renderer)
{
return visibleRenderers.Contains(renderer);
}
//
static protected void Initialize()
{
if (initialized) { return; }
// Initialize shaders and materials
int l = shaderPaths.Length;
shaders = new Shader[l];
materials = new Material[l];
for (int i = 0; i < l; i++)
{
Shader shader = Shader.Find(shaderPaths[i]);
shaders[i] = shader;
Material material = new Material(shader);
materials[i] = material;
}
initialized = true;
}
//
protected virtual RenderTextureDescriptor GetDescriptor()
{
RenderTextureDescriptor descriptor;
// RTT
var targetTexture = cam.targetTexture;
if (targetTexture != null)
{
descriptor = targetTexture.descriptor;
}
// VR
else if (XRSettings.enabled)
{
descriptor = XRSettings.eyeTextureDesc;
}
// Normal
else
{
descriptor = new RenderTextureDescriptor(cam.pixelWidth, cam.pixelHeight, RenderTextureFormat.ARGB32, 24);
}
// Overrides
descriptor.colorFormat = RenderTextureFormat.ARGB32;
descriptor.sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
descriptor.useMipMap = false;
descriptor.msaaSamples = GetAA(targetTexture);
return descriptor;
}
//
protected virtual bool Equals(RenderTextureDescriptor x, RenderTextureDescriptor y)
{
return x.width == y.width && x.height == y.height && x.msaaSamples == y.msaaSamples; // TODO compare all fields?
}
//
protected virtual int GetAA(RenderTexture targetTexture)
{
int aa = 1;
switch (_antiAliasing)
{
case AntiAliasing.QualitySettings:
// Set aa value to 1 in case camera is in DeferredLighting or DeferredShading Rendering Path
if (cam.actualRenderingPath == RenderingPath.DeferredLighting || cam.actualRenderingPath == RenderingPath.DeferredShading)
{
aa = 1;
}
else
{
if (targetTexture == null)
{
aa = QualitySettings.antiAliasing;
if (aa == 0) { aa = 1; }
}
else
{
aa = targetTexture.antiAliasing;
}
}
break;
case AntiAliasing.Disabled:
aa = 1;
break;
case AntiAliasing.MSAA2x:
aa = 2;
break;
case AntiAliasing.MSAA4x:
aa = 4;
break;
case AntiAliasing.MSAA8x:
aa = 8;
break;
}
return aa;
}
//
protected virtual bool CheckSupported(bool verbose)
{
bool supported = true;
// Image Effects supported?
if (!SystemInfo.supportsImageEffects)
{
if (verbose) { Debug.LogError("HighlightingSystem : Image effects is not supported on this platform!"); }
supported = false;
}
// Required Render Texture Format supported?
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGB32))
{
if (verbose) { Debug.LogError("HighlightingSystem : RenderTextureFormat.ARGB32 is not supported on this platform!"); }
supported = false;
}
// HighlightingOpaque shader supported?
if (!HighlighterCore.opaqueShader.isSupported)
{
if (verbose) { Debug.LogError("HighlightingSystem : HighlightingOpaque shader is not supported on this platform!"); }
supported = false;
}
// HighlightingTransparent shader supported?
if (!HighlighterCore.transparentShader.isSupported)
{
if (verbose) { Debug.LogError("HighlightingSystem : HighlightingTransparent shader is not supported on this platform!"); }
supported = false;
}
// Highlighting shaders supported?
for (int i = 0; i < shaders.Length; i++)
{
Shader shader = shaders[i];
if (!shader.isSupported)
{
if (verbose) { Debug.LogError("HighlightingSystem : Shader '" + shader.name + "' is not supported on this platform!"); }
supported = false;
}
}
return supported;
}
//
protected virtual void RebuildCommandBuffer()
{
renderBuffer.Clear();
renderBuffer.BeginSample(profileHighlightingSystem);
// Prepare and clear render target
renderBuffer.SetRenderTarget(highlightingBufferID);
renderBuffer.ClearRenderTarget(true, true, colorClear);
// Fill buffer with highlighters rendering commands
HighlighterCore.FillBuffer(renderBuffer);
RenderTextureDescriptor desc = cachedDescriptor;
desc.width = highlightingBuffer.width / _downsampleFactor;
desc.height = highlightingBuffer.height / _downsampleFactor;
desc.depthBufferBits = 0;
// Create two buffers for blurring the image
renderBuffer.GetTemporaryRT(ShaderPropertyID._HighlightingBlur1, desc, FilterMode.Bilinear);
renderBuffer.GetTemporaryRT(ShaderPropertyID._HighlightingBlur2, desc, FilterMode.Bilinear);
renderBuffer.Blit(highlightingBufferID, blur1ID);
// Blur the small texture
bool oddEven = true;
for (int i = 0; i < _iterations; i++)
{
float off = _blurMinSpread + _blurSpread * i;
renderBuffer.SetGlobalFloat(ShaderPropertyID._HighlightingBlurOffset, off);
if (oddEven)
{
renderBuffer.Blit(blur1ID, blur2ID, blurMaterial);
}
else
{
renderBuffer.Blit(blur2ID, blur1ID, blurMaterial);
}
oddEven = !oddEven;
}
// Upscale blurred texture and cut stencil from it
renderBuffer.Blit(oddEven ? blur1ID : blur2ID, highlightingBufferID, cutMaterial);
// Cleanup
renderBuffer.ReleaseTemporaryRT(ShaderPropertyID._HighlightingBlur1);
renderBuffer.ReleaseTemporaryRT(ShaderPropertyID._HighlightingBlur2);
renderBuffer.EndSample(profileHighlightingSystem);
}
// Blit highlighting result to the destination RenderTexture
public virtual void Blit(RenderTexture src, RenderTexture dst)
{
Graphics.Blit(src, dst, compMaterial);
}
#endregion
}
}