mirror of
https://github.com/FriendshipIsEpic/FiE-Game.git
synced 2024-11-21 21:37:59 +01:00
Added Highlighting System library.
This commit is contained in:
parent
ae34b2d806
commit
1789a03ea3
28 changed files with 2289 additions and 0 deletions
5
Assets/Highlighting System/Resources.meta
Normal file
5
Assets/Highlighting System/Resources.meta
Normal file
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2e2dd921d0779af4dad3fbd326388e14
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
100
Assets/Highlighting System/Resources/HighlightingBlur.shader
Normal file
100
Assets/Highlighting System/Resources/HighlightingBlur.shader
Normal 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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3070218404d1de94c9d081d248597046
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b0bd9de6a4f20954f9704e56568224a6
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
101
Assets/Highlighting System/Resources/HighlightingCut.shader
Normal file
101
Assets/Highlighting System/Resources/HighlightingCut.shader
Normal 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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 376af14ed82e64793b326012b8591fa9
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce3b12ca636563c48afb814d9aeb5b90
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fc04a058c8768648a6532aa07540ca5
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
5
Assets/Highlighting System/Scripts.meta
Normal file
5
Assets/Highlighting System/Scripts.meta
Normal file
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4b92650ecd71b67409ab3aafea97bd7d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
344
Assets/Highlighting System/Scripts/Highlighter.cs
Normal file
344
Assets/Highlighting System/Scripts/Highlighter.cs
Normal 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
|
||||
}
|
||||
}
|
8
Assets/Highlighting System/Scripts/Highlighter.cs.meta
Normal file
8
Assets/Highlighting System/Scripts/Highlighter.cs.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67d4de287b46eb34e83a61e4f9115070
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
10
Assets/Highlighting System/Scripts/HighlightingRenderer.cs
Normal file
10
Assets/Highlighting System/Scripts/HighlightingRenderer.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace HighlightingSystem
|
||||
{
|
||||
public class HighlightingRenderer : HighlightingBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -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:
|
5
Assets/Highlighting System/Scripts/Internal.meta
Normal file
5
Assets/Highlighting System/Scripts/Internal.meta
Normal file
|
@ -0,0 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3e2a98eec43f4f04788ccf35d4ae8ec4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd0100e03c13140a894e7744d95e3a1b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 051745279da5dc949a624a73543c6373
|
||||
timeCreated: 1432018011
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
593
Assets/Highlighting System/Scripts/Internal/HighlightingBase.cs
Normal file
593
Assets/Highlighting System/Scripts/Internal/HighlightingBase.cs
Normal 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9a69acb2622340e39a2b84d908232e3
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
170
Assets/Highlighting System/Scripts/Internal/RendererCache.cs
Normal file
170
Assets/Highlighting System/Scripts/Internal/RendererCache.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f97757299618eab4490066e41a69a6ca
|
||||
timeCreated: 1432110880
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bdf8fd90b69cf684cbbb8f6ec27bf953
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
|
@ -2259,6 +2259,13 @@
|
|||
<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\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>
|
||||
<None Include=".gitattributes" />
|
||||
|
|
Loading…
Reference in a new issue