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

596 lines
16 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
[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;
protected const CameraEvent queue = CameraEvent.BeforeImageEffectsOpaque;
static protected RenderTargetIdentifier cameraTargetID;
static protected Mesh quad;
// Current graphics device version
static protected GraphicsDeviceType device = GraphicsDeviceType.Null;
// Same check as in HLSLSupport.cginc
static protected bool uvStartsAtTop
{
get
{
return
device == GraphicsDeviceType.Direct3D9 // SHADER_API_D3D9
|| device == GraphicsDeviceType.Xbox360 // SHADER_API_XBOX360
|| device == GraphicsDeviceType.PlayStation3 // SHADER_API_PS3
|| device == GraphicsDeviceType.Direct3D11 // SHADER_API_D3D11
|| device == GraphicsDeviceType.PlayStationVita // SHADER_API_PSP2
|| device == GraphicsDeviceType.PlayStation4 // SHADER_API_PSSL
|| device == GraphicsDeviceType.Metal // SHADER_API_METAL
// device == GraphicsDeviceType.? // SHADER_API_D3D11_9X - Direct3D 11 “feature level 9.x” target for Windows Store & Windows Phone.
// device == GraphicsDeviceType.? // SHADER_API_WIIU - Nintendo WiiU
;
}
}
#endregion
#region Public Fields
// True if supported on this platform
public bool isSupported
{
get
{
return CheckSupported(false);
}
}
// Depth offset factor for highlighting shaders
public float offsetFactor = 0f;
// Depth offset units for highlighting shaders
public float offsetUnits = 0f;
// 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._Intensity, _blurIntensity);
}
}
}
}
// Blitter component reference (optional)
public HighlightingBlitter blitter
{
get { return _blitter; }
set
{
if (_blitter != null)
{
_blitter.Unregister(this);
}
_blitter = value;
if (_blitter != null)
{
_blitter.Register(this);
}
}
}
#endregion
#region Protected Fields
protected CommandBuffer renderBuffer;
protected int cachedWidth = -1;
protected int cachedHeight = -1;
protected int cachedAA = -1;
[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 HighlightingBlitter _blitter;
// RenderTargetidentifier for the highlightingBuffer RenderTexture
protected RenderTargetIdentifier highlightingBufferID;
// RenderTexture with highlighting buffer
protected RenderTexture highlightingBuffer = null;
// Camera reference
protected Camera cam = null;
// True if framebuffer depth data is currently available (it is required for the highlighting occlusion feature)
protected bool isDepthAvailable = true;
// 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;
static protected HashSet<Camera> cameras = new HashSet<Camera>();
#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;
}
blurMaterial = new Material(materials[BLUR]);
cutMaterial = new Material(materials[CUT]);
compMaterial = new Material(materials[COMP]);
// Set initial intensity in blur material
blurMaterial.SetFloat(ShaderPropertyID._Intensity, _blurIntensity);
renderBuffer = new CommandBuffer();
renderBuffer.name = renderBufferName;
cam = GetComponent<Camera>();
cameras.Add(cam);
cam.AddCommandBuffer(queue, renderBuffer);
if (_blitter != null)
{
_blitter.Register(this);
}
}
//
protected virtual void OnDisable()
{
cameras.Remove(cam);
if (renderBuffer != null)
{
cam.RemoveCommandBuffer(queue, renderBuffer);
renderBuffer = null;
}
if (highlightingBuffer != null && highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
highlightingBuffer = null;
}
if (_blitter != null)
{
_blitter.Unregister(this);
}
}
//
protected virtual void OnPreRender()
{
bool updateHighlightingBuffer = false;
int aa = GetAA();
bool depthAvailable = (aa == 1);
if (cam.actualRenderingPath == RenderingPath.Forward || cam.actualRenderingPath == RenderingPath.VertexLit)
{
// In case MSAA is enabled in forward/vertex lit rendeirng paths - depth buffer is not available
if (aa > 1)
{
depthAvailable = false;
}
// In case camera clearFlags is set to 'Depth only' or 'Don't clear' in forward/vertex lit rendeirng paths - depth buffer is not available
if (cam.clearFlags == CameraClearFlags.Depth || cam.clearFlags == CameraClearFlags.Nothing)
{
depthAvailable = false;
}
}
// Check if framebuffer depth data availability has changed
if (isDepthAvailable != depthAvailable)
{
updateHighlightingBuffer = true;
isDepthAvailable = depthAvailable;
// Update ZWrite value for all highlighting shaders correspondingly (isDepthAvailable ? ZWrite Off : ZWrite On)
Highlighter.SetZWrite(isDepthAvailable ? 0 : 1);
if (isDepthAvailable)
{
Debug.LogWarning("HighlightingSystem : Framebuffer depth data is available back again. Depth occlusion enabled, highlighting occluders disabled. (This message is harmless)");
}
else
{
Debug.LogWarning("HighlightingSystem : Framebuffer depth data is not available. Depth occlusion disabled, highlighting occluders enabled. (This message is harmless)");
}
}
updateHighlightingBuffer |= (highlightingBuffer == null || cam.pixelWidth != cachedWidth || cam.pixelHeight != cachedHeight || aa != cachedAA);
if (updateHighlightingBuffer)
{
if (highlightingBuffer != null && highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
}
cachedWidth = cam.pixelWidth;
cachedHeight = cam.pixelHeight;
cachedAA = aa;
highlightingBuffer = new RenderTexture(cachedWidth, cachedHeight, isDepthAvailable ? 0 : 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
highlightingBuffer.antiAliasing = cachedAA;
highlightingBuffer.filterMode = FilterMode.Point;
highlightingBuffer.useMipMap = false;
highlightingBuffer.wrapMode = TextureWrapMode.Clamp;
if (!highlightingBuffer.Create())
{
Debug.LogError("HighlightingSystem : UpdateHighlightingBuffer() : Failed to create highlightingBuffer RenderTexture!");
}
highlightingBufferID = new RenderTargetIdentifier(highlightingBuffer);
cutMaterial.SetTexture(ShaderPropertyID._HighlightingBuffer, highlightingBuffer);
compMaterial.SetTexture(ShaderPropertyID._HighlightingBuffer, highlightingBuffer);
Vector4 v = new Vector4(1f / (float)highlightingBuffer.width, 1f / (float)highlightingBuffer.height, 0f, 0f);
cutMaterial.SetVector(ShaderPropertyID._HighlightingBufferTexelSize, v);
}
// Set global depth offset properties for highlighting shaders to the values which has this HighlightingBase component
Highlighter.SetOffsetFactor(offsetFactor);
Highlighter.SetOffsetUnits(offsetUnits);
RebuildCommandBuffer();
}
// 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
protected virtual void OnRenderImage(RenderTexture src, RenderTexture dst)
{
if (blitter == null)
{
Blit(src, dst);
}
else
{
Graphics.Blit(src, dst);
}
}
#endregion
#region Internal
//
static public bool IsHighlightingCamera(Camera cam)
{
return cameras.Contains(cam);
}
//
static protected void Initialize()
{
if (initialized) { return; }
// Determine graphics device type
device = SystemInfo.graphicsDeviceType;
// Initialize shader property constants
ShaderPropertyID.Initialize();
// 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;
}
// Initialize static RenderTargetIdentifier(s)
cameraTargetID = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
// Create static quad mesh
CreateQuad();
initialized = true;
}
//
static protected void CreateQuad()
{
if (quad == null)
{
quad = new Mesh();
}
else
{
quad.Clear();
}
float y1 = -1f;
float y2 = 1f;
if (uvStartsAtTop)
{
y1 = 1f;
y2 = -1f;
}
quad.vertices = new Vector3[]
{
new Vector3(-1f, y1, 0f), // Bottom-Left
new Vector3(-1f, y2, 0f), // Upper-Left
new Vector3( 1f, y2, 0f), // Upper-Right
new Vector3( 1f, y1, 0f) // Bottom-Right
};
quad.uv = new Vector2[]
{
new Vector2(0f, 0f),
new Vector2(0f, 1f),
new Vector2(1f, 1f),
new Vector2(1f, 0f)
};
quad.colors = new Color[]
{
colorClear,
colorClear,
colorClear,
colorClear
};
quad.triangles = new int[] { 0, 1, 2, 2, 3, 0 };
}
//
protected virtual int GetAA()
{
int aa = QualitySettings.antiAliasing;
if (aa == 0) { aa = 1; }
// Reset 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; }
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;
}
// Render Textures supported?
if (!SystemInfo.supportsRenderTextures)
{
if (verbose) { Debug.LogError("HighlightingSystem : RenderTextures 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;
}
// Stencil buffer supported?
if (SystemInfo.supportsStencil < 1)
{
if (verbose) { Debug.LogError("HighlightingSystem : Stencil buffer is not supported on this platform!"); }
supported = false;
}
// HighlightingOpaque shader supported?
if (!Highlighter.opaqueShader.isSupported)
{
if (verbose) { Debug.LogError("HighlightingSystem : HighlightingOpaque shader is not supported on this platform!"); }
supported = false;
}
// HighlightingTransparent shader supported?
if (!Highlighter.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();
RenderTargetIdentifier depthID = isDepthAvailable ? cameraTargetID : highlightingBufferID;
// Prepare and clear render target
renderBuffer.SetRenderTarget(highlightingBufferID, depthID);
renderBuffer.ClearRenderTarget(!isDepthAvailable, true, colorClear);
// Fill buffer with highlighters rendering commands
Highlighter.FillBuffer(renderBuffer, isDepthAvailable);
// Create two buffers for blurring the image
RenderTargetIdentifier blur1ID = new RenderTargetIdentifier(ShaderPropertyID._HighlightingBlur1);
RenderTargetIdentifier blur2ID = new RenderTargetIdentifier(ShaderPropertyID._HighlightingBlur2);
int width = highlightingBuffer.width / _downsampleFactor;
int height = highlightingBuffer.height / _downsampleFactor;
renderBuffer.GetTemporaryRT(ShaderPropertyID._HighlightingBlur1, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
renderBuffer.GetTemporaryRT(ShaderPropertyID._HighlightingBlur2, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
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.SetGlobalTexture(ShaderPropertyID._HighlightingBlurred, oddEven ? blur1ID : blur2ID);
renderBuffer.SetRenderTarget(highlightingBufferID, depthID);
renderBuffer.DrawMesh(quad, identityMatrix, cutMaterial);
// Cleanup
renderBuffer.ReleaseTemporaryRT(ShaderPropertyID._HighlightingBlur1);
renderBuffer.ReleaseTemporaryRT(ShaderPropertyID._HighlightingBlur2);
}
// Blit highlighting result to the destination RenderTexture
public virtual void Blit(RenderTexture src, RenderTexture dst)
{
Graphics.Blit(src, dst, compMaterial);
}
#endregion
}
}