Added Highlighting System library.

This commit is contained in:
Alex.Kirel 2023-07-27 16:48:00 +05:00
parent ae34b2d806
commit 1789a03ea3
28 changed files with 2289 additions and 0 deletions

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 2e2dd921d0779af4dad3fbd326388e14
folderAsset: yes
DefaultImporter:
userData:

View file

@ -0,0 +1,100 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Hidden/Highlighted/Blur"
{
Properties
{
[HideInInspector] _MainTex ("", 2D) = "" {}
[HideInInspector] _Intensity ("", Range (0.25,0.5)) = 0.3
}
SubShader
{
Pass
{
ZTest Always
Cull Off
ZWrite Off
Lighting Off
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform half4 _MainTex_TexelSize;
uniform half _HighlightingBlurOffset;
uniform half _Intensity;
struct v2f
{
float4 pos : POSITION;
float2 uv[4] : TEXCOORD0; // 8 to add straight directions
};
v2f vert (appdata_img v)
{
// Shader code optimized for the Unity shader compiler
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
float2 offs = _HighlightingBlurOffset * _MainTex_TexelSize.xy;
// Diagonal directions
o.uv[0].x = v.texcoord.x - offs.x;
o.uv[0].y = v.texcoord.y - offs.y;
o.uv[1].x = v.texcoord.x + offs.x;
o.uv[1].y = v.texcoord.y - offs.y;
o.uv[2].x = v.texcoord.x + offs.x;
o.uv[2].y = v.texcoord.y + offs.y;
o.uv[3].x = v.texcoord.x - offs.x;
o.uv[3].y = v.texcoord.y + offs.y;
/*
// Straight directions
o.uv[4].x = v.texcoord.x - offs.x;
o.uv[4].y = v.texcoord.y;
o.uv[5].x = v.texcoord.x + offs.x;
o.uv[5].y = v.texcoord.y;
o.uv[6].x = v.texcoord.x;
o.uv[6].y = v.texcoord.y - offs.y;
o.uv[7].x = v.texcoord.x;
o.uv[7].y = v.texcoord.y + offs.y;
*/
return o;
}
half4 frag(v2f i) : COLOR
{
int start = 0;
int end = 4;
half4 color1 = tex2D(_MainTex, i.uv[start]);
fixed4 color2;
for (int n = start + 1; n < end; n++)
{
color2 = tex2D(_MainTex, i.uv[n]);
color1.rgb = max(color1.rgb, color2.rgb);
color1.a += color2.a;
}
color1.a *= _Intensity;
return color1;
}
ENDCG
}
}
Fallback off
}

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 3070218404d1de94c9d081d248597046
ShaderImporter:
defaultTextures: []
userData:

View file

@ -0,0 +1,69 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Hidden/Highlighted/Composite"
{
Properties
{
[HideInInspector] _MainTex ("", 2D) = "" {}
}
SubShader
{
Pass
{
Lighting Off
Fog { Mode off }
ZWrite Off
ZTest Always
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f
{
float4 pos : POSITION;
half2 uv0 : TEXCOORD0;
half2 uv1 : TEXCOORD1;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_TexelSize;
uniform sampler2D _HighlightingBuffer;
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv0 = v.texcoord.xy;
o.uv1 = v.texcoord.xy;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
{
o.uv1.y = 1-o.uv1.y;
#if defined(UNITY_HALF_TEXEL_OFFSET)
o.uv1.y -= _MainTex_TexelSize.y;
#endif
}
#endif
return o;
}
fixed4 frag(v2f i) : COLOR
{
fixed4 c1 = tex2D(_MainTex, i.uv0);
fixed4 c2 = tex2D(_HighlightingBuffer, i.uv1);
c1.rgb = lerp(c1.rgb, c2.rgb, c2.a);
return c1;
}
ENDCG
}
}
FallBack Off
}

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: b0bd9de6a4f20954f9704e56568224a6
ShaderImporter:
defaultTextures: []
userData:

View file

@ -0,0 +1,101 @@
Shader "Hidden/Highlighted/Cut"
{
SubShader
{
Lighting Off
Fog { Mode off }
ZWrite Off
ZTest Always
Cull Back
Blend Off
Pass
{
Stencil
{
Ref 1
Comp NotEqual
Pass Keep
ZFail Keep
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f
{
float4 pos : POSITION;
half2 uv : TEXCOORD0;
};
uniform sampler2D _HighlightingBlurred;
uniform float2 _HighlightingBufferTexelSize;
v2f vert(appdata_img v)
{
v2f o;
o.pos = v.vertex;
#if defined(UNITY_HALF_TEXEL_OFFSET)
o.pos.xy += _HighlightingBufferTexelSize;
#endif
o.uv = v.texcoord.xy;
return o;
}
fixed4 frag(v2f i) : COLOR
{
return tex2D(_HighlightingBlurred, i.uv);
}
ENDCG
}
Pass
{
Stencil
{
Ref 1
Comp Equal
Pass Keep
ZFail Keep
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_vert
{
float4 vertex : POSITION;
};
uniform float2 _HighlightingBufferTexelSize;
float4 vert(appdata_vert v) : POSITION
{
float4 pos = v.vertex;
#if defined(UNITY_HALF_TEXEL_OFFSET)
pos.xy += _HighlightingBufferTexelSize;
#endif
return pos;
}
fixed4 frag() : COLOR
{
return 0;
}
ENDCG
}
}
FallBack Off
}

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 376af14ed82e64793b326012b8591fa9
ShaderImporter:
defaultTextures: []
userData:

View file

@ -0,0 +1,54 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Hidden/Highlighted/Opaque"
{
Properties
{
[HideInInspector] _ZTest ("", Float) = 8 // UnityEngine.Rendering.CompareFunction. 4 = LessEqual, 8 = Always
[HideInInspector] _StencilRef ("", Float) = 1
}
SubShader
{
Pass
{
Lighting Off
Fog { Mode Off }
ZWrite [_HighlightingZWrite]
ZTest [_ZTest]
Offset [_HighlightingOffsetFactor], [_HighlightingOffsetUnits]
Stencil
{
Ref [_StencilRef]
Comp Always
Pass Replace
ZFail Keep
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform fixed4 _Outline;
struct appdata_vert
{
float4 vertex : POSITION;
};
float4 vert(appdata_vert v) : POSITION
{
return UnityObjectToClipPos(v.vertex);
}
fixed4 frag() : COLOR
{
return _Outline;
}
ENDCG
}
}
Fallback Off
}

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: ce3b12ca636563c48afb814d9aeb5b90
ShaderImporter:
defaultTextures: []
userData:

View file

@ -0,0 +1,79 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Hidden/Highlighted/Transparent"
{
Properties
{
[HideInInspector] _MainTex ("", 2D) = "" {}
[HideInInspector] _Cutoff ("", Float) = 0.5
[HideInInspector] _ZTest ("", Float) = 8 // UnityEngine.Rendering.CompareFunction. 4 = LessEqual, 8 = Always
[HideInInspector] _StencilRef ("", Float) = 1
[HideInInspector] _Cull ("", Float) = 2 // UnityEngine.Rendering.CullMode.Back
}
SubShader
{
Pass
{
Lighting Off
Fog { Mode Off }
ZWrite [_HighlightingZWrite]
ZTest [_ZTest]
Offset [_HighlightingOffsetFactor], [_HighlightingOffsetUnits]
Cull [_Cull]
Stencil
{
Ref [_StencilRef]
Comp Always
Pass Replace
ZFail Keep
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform fixed4 _Outline;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform fixed _Cutoff;
struct appdata_vert_tex
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
fixed alpha : TEXCOORD1;
};
v2f vert(appdata_vert_tex v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
o.alpha = v.color.a;
return o;
}
fixed4 frag(v2f i) : COLOR
{
fixed a = tex2D(_MainTex, i.texcoord).a;
clip(a - _Cutoff);
fixed4 c = _Outline;
c.a *= i.alpha;
return c;
}
ENDCG
}
}
Fallback Off
}

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 9fc04a058c8768648a6532aa07540ca5
ShaderImporter:
defaultTextures: []
userData:

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 4b92650ecd71b67409ab3aafea97bd7d
folderAsset: yes
DefaultImporter:
userData:

View file

@ -0,0 +1,344 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
public partial class Highlighter : MonoBehaviour
{
#region Editable Parameters
// Constant highlighting turning on speed (common property for all Highlighters)
static private float constantOnSpeed = 4.5f;
// Constant highlighting turning off speed (common property for all Highlighters)
static private float constantOffSpeed = 4f;
// Default transparency cutoff value (used for shaders without _Cutoff property)
static private float transparentCutoff = 0.5f;
// Builtin layer reserved for the highlighting. This layer shouldn't be used for anything else in the project!
public const int highlightingLayer = 7;
// Only these types of Renderers will be highlighted
static public readonly List<System.Type> types = new List<System.Type>()
{
typeof(MeshRenderer),
typeof(SkinnedMeshRenderer),
typeof(SpriteRenderer),
typeof(ParticleRenderer),
typeof(ParticleSystemRenderer),
};
#endregion
#region Public Methods
/// <summary>
/// Renderers reinitialization.
/// Call this method if your highlighted object has changed it's materials, renderers or child objects.
/// Can be called multiple times per update - renderers reinitialization will occur only once.
/// </summary>
public void ReinitMaterials()
{
renderersDirty = true;
}
/// <summary>
/// Set color for one-frame highlighting mode.
/// </summary>
/// <param name='color'>
/// Highlighting color.
/// </param>
public void OnParams(Color color)
{
onceColor = color;
}
/// <summary>
/// Turn on one-frame highlighting.
/// </summary>
public void On()
{
// Highlight object only in this frame
once = true;
}
/// <summary>
/// Turn on one-frame highlighting with given color.
/// Can be called multiple times per update, color only from the latest call will be used.
/// </summary>
/// <param name='color'>
/// Highlighting color.
/// </param>
public void On(Color color)
{
// Set new color for one-frame highlighting
onceColor = color;
On();
}
/// <summary>
/// Set flashing parameters.
/// </summary>
/// <param name='color1'>
/// Starting color.
/// </param>
/// <param name='color2'>
/// Ending color.
/// </param>
/// <param name='freq'>
/// Flashing frequency (times per second).
/// </param>
public void FlashingParams(Color color1, Color color2, float freq)
{
flashingColorMin = color1;
flashingColorMax = color2;
flashingFreq = freq;
}
/// <summary>
/// Turn on flashing.
/// </summary>
public void FlashingOn()
{
flashing = true;
}
/// <summary>
/// Turn on flashing from color1 to color2.
/// </summary>
/// <param name='color1'>
/// Starting color.
/// </param>
/// <param name='color2'>
/// Ending color.
/// </param>
public void FlashingOn(Color color1, Color color2)
{
flashingColorMin = color1;
flashingColorMax = color2;
FlashingOn();
}
/// <summary>
/// Turn on flashing from color1 to color2 with given frequency.
/// </summary>
/// <param name='color1'>
/// Starting color.
/// </param>
/// <param name='color2'>
/// Ending color.
/// </param>
/// <param name='freq'>
/// Flashing frequency (times per second).
/// </param>
public void FlashingOn(Color color1, Color color2, float freq)
{
flashingFreq = freq;
FlashingOn(color1, color2);
}
/// <summary>
/// Turn on flashing with given frequency.
/// </summary>
/// <param name='f'>
/// Flashing frequency (times per second).
/// </param>
public void FlashingOn(float freq)
{
flashingFreq = freq;
FlashingOn();
}
/// <summary>
/// Turn off flashing.
/// </summary>
public void FlashingOff()
{
flashing = false;
}
/// <summary>
/// Switch flashing mode.
/// </summary>
public void FlashingSwitch()
{
flashing = !flashing;
}
/// <summary>
/// Set constant highlighting color.
/// </summary>
/// <param name='color'>
/// Constant highlighting color.
/// </param>
public void ConstantParams(Color color)
{
constantColor = color;
}
/// <summary>
/// Fade in constant highlighting.
/// </summary>
public void ConstantOn()
{
// Enable constant highlighting
constantly = true;
// Start transition
transitionActive = true;
}
/// <summary>
/// Fade in constant highlighting with given color.
/// </summary>
/// <param name='color'>
/// Constant highlighting color.
/// </param>
public void ConstantOn(Color color)
{
// Set constant highlighting color
constantColor = color;
ConstantOn();
}
/// <summary>
/// Fade out constant highlighting.
/// </summary>
public void ConstantOff()
{
// Disable constant highlighting
constantly = false;
// Start transition
transitionActive = true;
}
/// <summary>
/// Switch Constant Highlighting.
/// </summary>
public void ConstantSwitch()
{
// Switch constant highlighting
constantly = !constantly;
// Start transition
transitionActive = true;
}
/// <summary>
/// Turn on constant highlighting immediately (without fading in).
/// </summary>
public void ConstantOnImmediate()
{
constantly = true;
// Set transition value to 1
transitionValue = 1f;
// Stop transition
transitionActive = false;
}
/// <summary>
/// Turn on constant highlighting with given color immediately (without fading in).
/// </summary>
/// <param name='color'>
/// Constant highlighting color.
/// </param>
public void ConstantOnImmediate(Color color)
{
// Set constant highlighting color
constantColor = color;
ConstantOnImmediate();
}
/// <summary>
/// Turn off constant highlighting immediately (without fading out).
/// </summary>
public void ConstantOffImmediate()
{
constantly = false;
// Set transition value to 0
transitionValue = 0f;
// Stop transition
transitionActive = false;
}
/// <summary>
/// Switch constant highlighting immediately (without fading in/out).
/// </summary>
public void ConstantSwitchImmediate()
{
constantly = !constantly;
// Set transition value to the final value
transitionValue = constantly ? 1f : 0f;
// Stop transition
transitionActive = false;
}
/// <summary>
/// Enable see-through mode
/// </summary>
public void SeeThroughOn()
{
seeThrough = true;
}
/// <summary>
/// Disable see-through mode
/// </summary>
public void SeeThroughOff()
{
seeThrough = false;
}
/// <summary>
/// Switch see-through mode
/// </summary>
public void SeeThroughSwitch()
{
seeThrough = !seeThrough;
}
/// <summary>
/// Enable occluder mode. Non-see-through occluders will be used only in case frame depth buffer is not accessible.
/// </summary>
public void OccluderOn()
{
occluder = true;
}
/// <summary>
/// Disable occluder mode. Non-see-through occluders will be used only in case frame depth buffer is not accessible.
/// </summary>
public void OccluderOff()
{
occluder = false;
}
/// <summary>
/// Switch occluder mode. Non-see-through occluders will be used only in case frame depth buffer is not accessible.
/// </summary>
public void OccluderSwitch()
{
occluder = !occluder;
}
/// <summary>
/// Turn off all types of highlighting.
/// </summary>
public void Off()
{
once = false;
flashing = false;
constantly = false;
// Set transition value to 0
transitionValue = 0f;
// Stop transition
transitionActive = false;
}
/// <summary>
/// Destroy this Highlighter component.
/// </summary>
public void Die()
{
Destroy(this);
}
#endregion
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 67d4de287b46eb34e83a61e4f9115070
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View file

@ -0,0 +1,10 @@
using UnityEngine;
using System.Collections;
namespace HighlightingSystem
{
public class HighlightingRenderer : HighlightingBase
{
}
}

View file

@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 8b765e0b5af3bcf4a9deb5895e477da8
labels:
- Glow
- Effect
- Outline
- Highlight
- Selection
- System
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View file

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 3e2a98eec43f4f04788ccf35d4ae8ec4
folderAsset: yes
DefaultImporter:
userData:

View file

@ -0,0 +1,542 @@
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
public partial class Highlighter : MonoBehaviour
{
// Constants (don't touch this!)
#region Constants
// 2 * PI constant required for flashing
private const float doublePI = 2f * Mathf.PI;
// Occlusion color
private readonly Color occluderColor = new Color(0f, 0f, 0f, 0f);
// ZTest LEqual
private const float zTestLessEqual = (float)CompareFunction.LessEqual;
// ZTest Always
private const float zTestAlways = (float)CompareFunction.Always;
// Cull Off
private const float cullOff = (float)CullMode.Off;
#endregion
#region Static Fields
// Global highlighting shaders ZWrite property
static private float zWrite = -1f; // Set to unusual default value to force initialization on start
// Global highlighting shaders Offset Factor property
static private float offsetFactor = float.NaN; // Set to unusual default value to force initialization on start
// Global highlighting shaders Offset Units property
static private float offsetUnits = float.NaN; // Set to unusual default value to force initialization on start
#endregion
#region Public Fields
// Current state of highlighting (true if highlighted and visible)
public bool highlighted { get; private set; }
#endregion
#region Private Fields
// Cached transform component reference
private Transform tr;
// Cached Renderers
private List<RendererCache> highlightableRenderers;
// Contains frame number, in which Highlighter visibility has been checked
private int visibilityCheckFrame = -1;
// Visibility changed in this frame
private bool visibilityChanged = false;
// At least 1 renderer is visible in this frame
private bool visible = false;
// Materials reinitialization is required flag
private bool renderersDirty = true;
// Current highlighting color
private Color currentColor;
// Transition is active flag
private bool transitionActive = false;
// Current transition value
private float transitionValue = 0f;
// Flashing frequency (times per second)
private float flashingFreq = 2f;
// One-frame highlighting flag
private int _once = 0;
private bool once
{
get { return _once == Time.frameCount; }
set { _once = value ? Time.frameCount : 0; }
}
// One-frame highlighting color
private Color onceColor = Color.red;
// Flashing state flag
private bool flashing = false;
// Flashing from color
private Color flashingColorMin = new Color(0f, 1f, 1f, 0f);
// Flashing to color
private Color flashingColorMax = new Color(0f, 1f, 1f, 1f);
// Constant highlighting state flag
private bool constantly = false;
// Constant highlighting color
private Color constantColor = Color.yellow;
// Occluder mode enabled flag
private bool occluder = false;
// See-through mode flag (should have same initial value with zTest and renderQueue variables!)
private bool seeThrough = true;
// RenderQueue (0 = Geometry, 1 = Geometry+1 (for seethrough mode on by default), 2 = Geometry+2)
private int renderQueue = 1;
// Current ZTest value (true = Always, false = LEqual)
private bool zTest = true;
// Current Stencil Ref value (true = 1, false = 0)
private bool stencilRef = true;
// Returns real ZTest float value which will be passed to the materials
private float zTestFloat { get { return zTest ? zTestAlways : zTestLessEqual; } }
// Returns real Stencil Ref float value which will be passed to the materials
private float stencilRefFloat { get { return stencilRef ? 1f : 0f; } }
// Opaque shader cached reference
static private Shader _opaqueShader;
static public Shader opaqueShader
{
get
{
if (_opaqueShader == null)
{
_opaqueShader = Shader.Find("Hidden/Highlighted/Opaque");
}
return _opaqueShader;
}
}
// Transparent shader cached reference
static private Shader _transparentShader;
static public Shader transparentShader
{
get
{
if (_transparentShader == null)
{
_transparentShader = Shader.Find("Hidden/Highlighted/Transparent");
}
return _transparentShader;
}
}
// Shared (for this component) replacement material for opaque geometry highlighting
private Material _opaqueMaterial;
private Material opaqueMaterial
{
get
{
if (_opaqueMaterial == null)
{
_opaqueMaterial = new Material(opaqueShader);
// Make sure that ShaderPropertyIDs is initialized
ShaderPropertyID.Initialize();
// Make sure that shader will have proper default values
_opaqueMaterial.SetFloat(ShaderPropertyID._ZTest, zTestFloat);
_opaqueMaterial.SetFloat(ShaderPropertyID._StencilRef, stencilRefFloat);
}
return _opaqueMaterial;
}
}
#endregion
#region MonoBehaviour
//
private void Awake()
{
tr = GetComponent<Transform>();
ShaderPropertyID.Initialize();
}
//
private void OnEnable()
{
if (!CheckInstance()) { return; }
HighlighterManager.Add(this);
}
//
private void OnDisable()
{
HighlighterManager.Remove(this);
// Clear cached renderers
if (highlightableRenderers != null) { highlightableRenderers.Clear(); }
// Reset highlighting parameters to default values
renderersDirty = true;
highlighted = false;
currentColor = Color.clear;
transitionActive = false;
transitionValue = 0f;
once = false;
flashing = false;
constantly = false;
occluder = false;
seeThrough = false;
/*
// Reset custom parameters of the highlighting
onceColor = Color.red;
flashingColorMin = new Color(0f, 1f, 1f, 0f);
flashingColorMax = new Color(0f, 1f, 1f, 1f);
flashingFreq = 2f;
constantColor = Color.yellow;
*/
}
//
private void Update()
{
// Update transition value
PerformTransition();
}
#endregion
#region Public Methods
// Returns true in case CommandBuffer should be rebuilt
public bool UpdateHighlighting(bool isDepthAvailable)
{
bool wasHighlighted = highlighted;
bool changed = false;
changed |= UpdateRenderers();
// Is any highlighting mode is enabled?
highlighted = (once || flashing || constantly || transitionActive);
int rq = 0;
// Render as highlighter
if (highlighted)
{
// ZTest = (seeThrough ? Always : LEqual), Stencil Ref = 1
UpdateShaderParams(seeThrough, true);
// RenderQueue = (seeThrough ? Geometry+1 : Geometry)
rq = seeThrough ? 2 : 0;
}
// Render as occluder
else if (occluder && (seeThrough || !isDepthAvailable))
{
// ZTest = (isDepthAvailable ? LEqual : Always), Stencil Ref = seeThrough ? 1 : 0
UpdateShaderParams(false, seeThrough);
// RenderQueue = (seeThrough ? Occluder queue : Geometry queue)
rq = seeThrough ? 1 : 0;
highlighted = true;
}
// In case renderer should be put to another render queue
if (renderQueue != rq)
{
renderQueue = rq;
changed = true;
}
if (highlighted)
{
changed |= UpdateVisibility();
if (visible)
{
UpdateColors();
}
else
{
highlighted = false;
}
}
changed |= (wasHighlighted != highlighted);
return changed;
}
// Fills given CommandBuffer with this Highlighter rendering commands
public void FillBuffer(CommandBuffer buffer, int renderQueue)
{
if (!highlighted) { return; }
if (this.renderQueue != renderQueue) { return; }
for (int i = highlightableRenderers.Count - 1; i >= 0; i--)
{
RendererCache renderer = highlightableRenderers[i];
if (!renderer.FillBuffer(buffer))
{
highlightableRenderers.RemoveAt(i);
}
}
}
#endregion
#region Private Methods
// Allow only single instance of the Highlighter component on a GameObject
private bool CheckInstance()
{
Highlighter[] highlighters = GetComponents<Highlighter>();
if (highlighters.Length > 1 && highlighters[0] != this)
{
enabled = false;
Debug.LogWarning("HighlightingSystem : Multiple Highlighter components on a single GameObject is not allowed! Highlighter has been disabled on a GameObject with name '" + gameObject.name + "'.");
return false;
}
return true;
}
// This method defines the way in which renderers are initialized
private bool UpdateRenderers()
{
if (renderersDirty)
{
List<Renderer> renderers = new List<Renderer>();
// Find all renderers which should be controlled by this Highlighter component
GrabRenderers(tr, ref renderers);
// Cache found renderers
highlightableRenderers = new List<RendererCache>();
int l = renderers.Count;
for (int i = 0; i < l; i++)
{
RendererCache cache = new RendererCache(renderers[i], opaqueMaterial, zTestFloat, stencilRefFloat);
highlightableRenderers.Add(cache);
}
// Reset
highlighted = false;
renderersDirty = false;
currentColor = Color.clear;
return true;
}
else
{
// To avoid null-reference exceptions when cached GameObject or Renderer has been removed but ReinitMaterials wasn't called
bool changed = false;
for (int i = highlightableRenderers.Count - 1; i >= 0; i--)
{
if (highlightableRenderers[i].IsDestroyed())
{
highlightableRenderers.RemoveAt(i);
changed = true;
}
}
return changed;
}
}
// Returns true in case visibility changed in this frame
private bool UpdateVisibility()
{
if (visibilityCheckFrame == Time.frameCount) { return visibilityChanged; }
visibilityCheckFrame = Time.frameCount;
visible = false;
visibilityChanged = false;
for (int i = 0, imax = highlightableRenderers.Count; i < imax; i++)
{
RendererCache rc = highlightableRenderers[i];
visibilityChanged |= rc.UpdateVisibility();
visible |= rc.visible;
}
return visibilityChanged;
}
// Follows hierarchy of objects from t, searches for Renderers and adds them to the list. Breaks if another Highlighter component found
private void GrabRenderers(Transform t, ref List<Renderer> renderers)
{
GameObject g = t.gameObject;
IEnumerator e;
// Find all Renderers of all types on current GameObject g and add them to the renderers list
for (int i = 0, imax = types.Count; i < imax; i++)
{
Component[] c = g.GetComponents(types[i]);
e = c.GetEnumerator();
while (e.MoveNext())
{
renderers.Add(e.Current as Renderer);
}
}
// Return if transform t doesn't have any children
if (t.childCount == 0) { return; }
// Recursively cache renderers on all child GameObjects
e = t.GetEnumerator();
while (e.MoveNext())
{
Transform childTransform = e.Current as Transform;
GameObject childGameObject = childTransform.gameObject;
Highlighter h = childGameObject.GetComponent<Highlighter>();
// Do not cache Renderers of this childTransform in case it has it's own Highlighter component
if (h != null) { continue; }
GrabRenderers(childTransform, ref renderers);
}
}
// Sets RenderQueue, ZTest and Stencil Ref parameters on all materials of all renderers of this object
private void UpdateShaderParams(bool zt, bool sr)
{
// ZTest
if (zTest != zt)
{
zTest = zt;
float ztf = zTestFloat;
opaqueMaterial.SetFloat(ShaderPropertyID._ZTest, ztf);
for (int i = 0; i < highlightableRenderers.Count; i++)
{
highlightableRenderers[i].SetZTestForTransparent(ztf);
}
}
// Stencil Ref
if (stencilRef != sr)
{
stencilRef = sr;
float srf = stencilRefFloat;
opaqueMaterial.SetFloat(ShaderPropertyID._StencilRef, srf);
for (int i = 0; i < highlightableRenderers.Count; i++)
{
highlightableRenderers[i].SetStencilRefForTransparent(srf);
}
}
}
// Update highlighting color if necessary
private void UpdateColors()
{
if (once)
{
SetColor(onceColor);
return;
}
if (flashing)
{
// Flashing frequency is not affected by Time.timeScale
Color c = Color.Lerp(flashingColorMin, flashingColorMax, 0.5f * Mathf.Sin(Time.realtimeSinceStartup * flashingFreq * doublePI) + 0.5f);
SetColor(c);
return;
}
if (transitionActive)
{
Color c = new Color(constantColor.r, constantColor.g, constantColor.b, constantColor.a * transitionValue);
SetColor(c);
return;
}
else if (constantly)
{
SetColor(constantColor);
return;
}
if (occluder)
{
SetColor(occluderColor);
return;
}
}
// Set given highlighting color
private void SetColor(Color value)
{
if (currentColor == value) { return; }
currentColor = value;
opaqueMaterial.SetColor(ShaderPropertyID._Outline, currentColor);
for (int i = 0; i < highlightableRenderers.Count; i++)
{
highlightableRenderers[i].SetColorForTransparent(currentColor);
}
}
// Calculate new transition value if necessary
private void PerformTransition()
{
if (transitionActive == false) { return; }
float targetValue = constantly ? 1f : 0f;
// Is transition finished?
if (transitionValue == targetValue)
{
transitionActive = false;
return;
}
if (Time.timeScale != 0f)
{
// Calculating delta time untouched by Time.timeScale
float unscaledDeltaTime = Time.deltaTime / Time.timeScale;
// Calculating new transition value
transitionValue = Mathf.Clamp01(transitionValue + (constantly ? constantOnSpeed : -constantOffSpeed) * unscaledDeltaTime);
}
else { return; }
}
#endregion
#region Static Methods
// Globally sets ZWrite shader parameter for all highlighting materials
static public void SetZWrite(float value)
{
if (zWrite == value) { return; }
zWrite = value;
Shader.SetGlobalFloat(ShaderPropertyID._HighlightingZWrite, zWrite);
}
// Globally sets Offset Factor shader parameter for all highlighting materials
static public void SetOffsetFactor(float value)
{
if (offsetFactor == value) { return; }
offsetFactor = value;
Shader.SetGlobalFloat(ShaderPropertyID._HighlightingOffsetFactor, offsetFactor);
}
// Globally sets Offset Units shader parameter for all highlighting materials
static public void SetOffsetUnits(float value)
{
if (offsetUnits == value) { return; }
offsetUnits = value;
Shader.SetGlobalFloat(ShaderPropertyID._HighlightingOffsetUnits, offsetUnits);
}
#endregion
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bd0100e03c13140a894e7744d95e3a1b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View file

@ -0,0 +1,46 @@
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
static public class HighlighterManager
{
static private int dirtyFrame = -1;
static public bool isDirty
{
get
{
return dirtyFrame == Time.frameCount;
}
private set
{
dirtyFrame = value ? Time.frameCount : -1;
}
}
static private HashSet<Highlighter> highlighters = new HashSet<Highlighter>();
//
static public void Add(Highlighter highlighter)
{
highlighters.Add(highlighter);
}
//
static public void Remove(Highlighter instance)
{
if (highlighters.Remove(instance) && instance.highlighted)
{
isDirty = true;
}
}
//
static public HashSet<Highlighter>.Enumerator GetEnumerator()
{
return highlighters.GetEnumerator();
}
}
}

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 051745279da5dc949a624a73543c6373
timeCreated: 1432018011
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,593 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
[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;
// Graphics device version identifiers
protected const int OGL = 0;
protected const int D3D9 = 1;
protected const int D3D11 = 2;
// Current graphics device version: 0 = OpenGL or unknown (default), 1 = Direct3D 9, 2 = Direct3D 11
static protected int graphicsDeviceVersion = D3D9;
#endregion
#region Public Fields
// 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;
isDirty = true;
}
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;
isDirty = true;
}
}
}
// Blur minimal spread
public float blurMinSpread
{
get { return _blurMinSpread; }
set
{
if (_blurMinSpread != value)
{
_blurMinSpread = value;
isDirty = true;
}
}
}
// Blur spread per iteration
public float blurSpread
{
get { return _blurSpread; }
set
{
if (_blurSpread != value)
{
_blurSpread = value;
isDirty = true;
}
}
}
// 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);
}
}
}
}
#endregion
#region Protected Fields
protected CommandBuffer renderBuffer;
protected bool isDirty = true;
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;
// RenderTargetidentifier for the highlightingBuffer RenderTexture
protected RenderTargetIdentifier highlightingBufferID;
// RenderTexture with highlighting buffer
protected RenderTexture highlightingBuffer = null;
// Camera reference
protected Camera cam = null;
// True if HighlightingSystem is supported on this platform
protected bool isSupported = false;
// 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;
// Static materials
static protected Material cutMaterial;
static protected Material compMaterial;
// Dynamic materials
protected Material blurMaterial;
static protected bool initialized = false;
#endregion
#region MonoBehaviour
//
protected virtual void OnEnable()
{
if (!CheckInstance()) { return; }
Initialize();
isSupported = CheckSupported();
if (!isSupported)
{
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]);
// Set initial intensity in blur material
blurMaterial.SetFloat(ShaderPropertyID._Intensity, _blurIntensity);
renderBuffer = new CommandBuffer();
renderBuffer.name = renderBufferName;
cam = GetComponent<Camera>();
UpdateHighlightingBuffer();
// Force-rebuild renderBuffer
isDirty = true;
cam.AddCommandBuffer(queue, renderBuffer);
}
//
protected virtual void OnDisable()
{
if (renderBuffer != null)
{
cam.RemoveCommandBuffer(queue, renderBuffer);
renderBuffer = null;
}
if (highlightingBuffer != null && highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
highlightingBuffer = null;
}
}
//
protected virtual void OnPreRender()
{
UpdateHighlightingBuffer();
int aa = GetAA();
bool depthAvailable = (aa == 1);
// In case MSAA is enabled in forward/vertex lit rendeirng paths - depth buffer is not available
if (aa > 1 && (cam.actualRenderingPath == RenderingPath.Forward || cam.actualRenderingPath == RenderingPath.VertexLit))
{
depthAvailable = false;
}
// Check if framebuffer depth data availability has changed
if (isDepthAvailable != depthAvailable)
{
isDepthAvailable = depthAvailable;
// Update ZWrite value for all highlighting shaders correspondingly (isDepthAvailable ? ZWrite Off : ZWrite On)
Highlighter.SetZWrite(isDepthAvailable ? 0f : 1f);
if (isDepthAvailable)
{
Debug.LogWarning("HighlightingSystem : Framebuffer depth data is available back again and will be used to occlude highlighting. Highlighting occluders disabled.");
}
else
{
Debug.LogWarning("HighlightingSystem : Framebuffer depth data is not available and can't be used to occlude highlighting. Highlighting occluders enabled.");
}
isDirty = true;
}
// Set global depth offset properties for highlighting shaders to the values which has this HighlightingBase component
Highlighter.SetOffsetFactor(offsetFactor);
Highlighter.SetOffsetUnits(offsetUnits);
isDirty |= HighlighterManager.isDirty;
isDirty |= HighlightersChanged();
if (isDirty)
{
RebuildCommandBuffer();
isDirty = false;
}
}
//
protected virtual void OnRenderImage(RenderTexture src, RenderTexture dst)
{
Graphics.Blit(src, dst, compMaterial);
}
#endregion
#region Internal
//
static protected void Initialize()
{
if (initialized) { return; }
// Determine graphics device version
string version = SystemInfo.graphicsDeviceVersion.ToLower();
if (version.Contains("direct3d") || version.Contains("directx"))
{
if (version.Contains("direct3d 11") || version.Contains("directx 11")) { graphicsDeviceVersion = D3D11; }
else { graphicsDeviceVersion = D3D9; }
}
#if UNITY_EDITOR_WIN && (UNITY_ANDROID || UNITY_IOS)
else if (version.Contains("emulated"))
{
graphicsDeviceVersion = D3D9;
}
#endif
else
{
graphicsDeviceVersion = OGL;
}
// 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;
}
cutMaterial = materials[CUT];
compMaterial = materials[COMP];
// Initialize static RenderTargetIdentifiers
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 (graphicsDeviceVersion == OGL)
{
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 void UpdateHighlightingBuffer()
{
int aa = GetAA();
if (cam.pixelWidth == cachedWidth && cam.pixelHeight == cachedHeight && aa == cachedAA) { return; }
cachedWidth = cam.pixelWidth;
cachedHeight = cam.pixelHeight;
cachedAA = aa;
if (highlightingBuffer != null && highlightingBuffer.IsCreated())
{
highlightingBuffer.Release();
}
highlightingBuffer = new RenderTexture(cachedWidth, cachedHeight, 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);
Shader.SetGlobalTexture(ShaderPropertyID._HighlightingBuffer, highlightingBuffer);
Vector4 v = new Vector4((graphicsDeviceVersion == OGL ? 1f : -1f) / (float)highlightingBuffer.width, 1f / (float)highlightingBuffer.height, 0f, 0f);
Shader.SetGlobalVector(ShaderPropertyID._HighlightingBufferTexelSize, v);
// Always set as dirty, because camera width/height/anti-aliasing has changed
isDirty = true;
}
// Allow only single instance of the HighlightingBase component on a GameObject
public virtual bool CheckInstance()
{
HighlightingBase[] highlightingBases = GetComponents<HighlightingBase>();
if (highlightingBases.Length > 1 && highlightingBases[0] != this)
{
enabled = false;
string className = this.GetType().ToString();
Debug.LogWarning(string.Format("HighlightingSystem : Only single instance of the HighlightingRenderer component is allowed on a single Gameobject! {0} has been disabled on GameObject with name '{1}'.", className, name));
return false;
}
return true;
}
//
protected virtual bool CheckSupported()
{
// Image Effects supported?
if (!SystemInfo.supportsImageEffects)
{
Debug.LogError("HighlightingSystem : Image effects is not supported on this platform!");
return false;
}
// Render Textures supported?
if (!SystemInfo.supportsRenderTextures)
{
Debug.LogError("HighlightingSystem : RenderTextures is not supported on this platform!");
return false;
}
// Required Render Texture Format supported?
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGB32))
{
Debug.LogError("HighlightingSystem : RenderTextureFormat.ARGB32 is not supported on this platform!");
return false;
}
if (SystemInfo.supportsStencil < 1)
{
Debug.LogError("HighlightingSystem : Stencil buffer is not supported on this platform!");
return false;
}
// HighlightingOpaque shader supported?
if (!Highlighter.opaqueShader.isSupported)
{
Debug.LogError("HighlightingSystem : HighlightingOpaque shader is not supported on this platform!");
return false;
}
// HighlightingTransparent shader supported?
if (!Highlighter.transparentShader.isSupported)
{
Debug.LogError("HighlightingSystem : HighlightingTransparent shader is not supported on this platform!");
return false;
}
// Required shaders supported?
for (int i = 0; i < shaders.Length; i++)
{
Shader shader = shaders[i];
if (!shader.isSupported)
{
Debug.LogError("HighlightingSystem : Shader '" + shader.name + "' is not supported on this platform!");
return false;
}
}
return true;
}
//
protected virtual bool HighlightersChanged()
{
bool changed = false;
// Check if list of highlighted objects has changed
HashSet<Highlighter>.Enumerator e = HighlighterManager.GetEnumerator();
while (e.MoveNext())
{
Highlighter highlighter = e.Current;
changed |= highlighter.UpdateHighlighting(isDepthAvailable);
}
return changed;
}
//
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
FillBuffer(renderBuffer, 0); // Highlighters
FillBuffer(renderBuffer, 1); // Occluders
FillBuffer(renderBuffer, 2); // See-through Highlighters
// 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);
}
//
protected virtual void FillBuffer(CommandBuffer buffer, int renderQueue)
{
HashSet<Highlighter>.Enumerator e;
e = HighlighterManager.GetEnumerator();
while (e.MoveNext())
{
Highlighter highlighter = e.Current;
highlighter.FillBuffer(renderBuffer, renderQueue);
}
}
#endregion
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c9a69acb2622340e39a2b84d908232e3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View file

@ -0,0 +1,170 @@
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
using System.Collections.Generic;
namespace HighlightingSystem
{
public partial class Highlighter : MonoBehaviour
{
// Internal class for renderers caching
private class RendererCache
{
private static readonly string sRenderType = "RenderType";
private static readonly string sOpaque = "Opaque";
private static readonly string sTransparent = "Transparent";
private static readonly string sTransparentCutout = "TransparentCutout";
private static readonly string sMainTex = "_MainTex";
private struct Data
{
public Material material;
public int submeshIndex;
public bool transparent;
}
private const int opaquePassID = 0;
private const int transparentPassID = 1;
public bool visible { get; private set; }
private GameObject go;
private Renderer renderer;
private List<Data> data;
// Constructor
public RendererCache(Renderer r, Material sharedOpaqueMaterial, float zTest, float stencilRef)
{
data = new List<Data>();
renderer = r;
go = r.gameObject;
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.SetFloat(ShaderPropertyID._ZTest, zTest);
replacementMat.SetFloat(ShaderPropertyID._StencilRef, stencilRef);
if (r is SpriteRenderer) { replacementMat.SetFloat(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);
}
}
visible = !IsDestroyed() && IsVisible();
}
//
public bool UpdateVisibility()
{
bool visibleNow = !IsDestroyed() && IsVisible();
if (visible != visibleNow)
{
visible = visibleNow;
return true;
}
return false;
}
// Fills given command buffer with this highlighter rendering commands
public bool FillBuffer(CommandBuffer buffer)
{
if (IsDestroyed()) { return false; }
if (IsVisible())
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
buffer.DrawRenderer(renderer, 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._Outline, clr);
}
}
}
// Sets ZTest parameter on all transparent materials of this renderer
public void SetZTestForTransparent(float zTest)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
if (d.transparent)
{
d.material.SetFloat(ShaderPropertyID._ZTest, zTest);
}
}
}
// Sets Stencil Ref parameter on all transparent materials of this renderer
public void SetStencilRefForTransparent(float stencilRef)
{
for (int i = 0, imax = data.Count; i < imax; i++)
{
Data d = data[i];
if (d.transparent)
{
d.material.SetFloat(ShaderPropertyID._StencilRef, stencilRef);
}
}
}
//
private bool IsVisible()
{
return renderer.enabled && renderer.isVisible;
}
//
public bool IsDestroyed()
{
return go == null || renderer == null;
}
}
}
}

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f97757299618eab4490066e41a69a6ca
timeCreated: 1432110880
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,63 @@
using UnityEngine;
using System.Collections;
namespace HighlightingSystem
{
static public class ShaderPropertyID
{
#region PUBLIC FIELDS
// Common
static public int _MainTex { get; private set; }
// HighlightingSystem
static public int _Outline { get; private set; }
static public int _Cutoff { get; private set; }
static public int _Intensity { get; private set; }
static public int _ZTest { get; private set; }
static public int _StencilRef { get; private set; }
static public int _Cull { get; private set; }
static public int _HighlightingBlur1 { get; private set; }
static public int _HighlightingBlur2 { get; private set; }
// HighlightingSystem global shader properties. Should be unique!
static public int _HighlightingBuffer { get; private set; }
static public int _HighlightingBlurred { get; private set; }
static public int _HighlightingBlurOffset { get; private set; }
static public int _HighlightingZWrite { get; private set; }
static public int _HighlightingOffsetFactor { get; private set; }
static public int _HighlightingOffsetUnits { get; private set; }
static public int _HighlightingBufferTexelSize { get; private set; }
#endregion
#region PRIVATE FIELDS
static private bool initialized = false;
#endregion
//
static public void Initialize()
{
if (initialized) { return; }
_MainTex = Shader.PropertyToID("_MainTex");
_Outline = Shader.PropertyToID("_Outline");
_Cutoff = Shader.PropertyToID("_Cutoff");
_Intensity = Shader.PropertyToID("_Intensity");
_ZTest = Shader.PropertyToID("_ZTest");
_StencilRef = Shader.PropertyToID("_StencilRef");
_Cull = Shader.PropertyToID("_Cull");
_HighlightingBlur1 = Shader.PropertyToID("_HighlightingBlur1");
_HighlightingBlur2 = Shader.PropertyToID("_HighlightingBlur2");
_HighlightingBuffer = Shader.PropertyToID("_HighlightingBuffer");
_HighlightingBlurred = Shader.PropertyToID("_HighlightingBlurred");
_HighlightingBlurOffset = Shader.PropertyToID("_HighlightingBlurOffset");
_HighlightingZWrite = Shader.PropertyToID("_HighlightingZWrite");
_HighlightingOffsetFactor = Shader.PropertyToID("_HighlightingOffsetFactor");
_HighlightingOffsetUnits = Shader.PropertyToID("_HighlightingOffsetUnits");
_HighlightingBufferTexelSize = Shader.PropertyToID("_HighlightingBufferTexelSize");
initialized = true;
}
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bdf8fd90b69cf684cbbb8f6ec27bf953
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View file

@ -2259,6 +2259,13 @@
<Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundBrushPresetC.cs" /> <Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundBrushPresetC.cs" />
<Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundPresetCircleShotC.cs" /> <Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundPresetCircleShotC.cs" />
<Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundPresetLaserC.cs" /> <Compile Include="Assets\Particle Playground\Scripts\Presets\PlaygroundPresetLaserC.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Highlighter.cs" />
<Compile Include="Assets\Highlighting System\Scripts\HighlightingRenderer.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Internal\HighlighterInternal.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Internal\HighlighterManager.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Internal\HighlightingBase.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Internal\RendererCache.cs" />
<Compile Include="Assets\Highlighting System\Scripts\Internal\ShaderPropertyID.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".gitattributes" /> <None Include=".gitattributes" />