diff --git a/Assets/Examples/Prefabs/TestOutlineLayers.asset b/Assets/Examples/Prefabs/TestOutlineLayers.asset
index 4db7174..47339ac 100644
--- a/Assets/Examples/Prefabs/TestOutlineLayers.asset
+++ b/Assets/Examples/Prefabs/TestOutlineLayers.asset
@@ -19,6 +19,8 @@ MonoBehaviour:
_outlineWidth: 5
_outlineIntensity: 2
_outlineMode: 0
+ _name:
+ _zOrder: 0
_enabled: 1
- _settings:
_outlineSettings: {fileID: 0}
@@ -26,6 +28,8 @@ MonoBehaviour:
_outlineWidth: 15
_outlineIntensity: 2
_outlineMode: 1
+ _name:
+ _zOrder: 0
_enabled: 1
- _settings:
_outlineSettings: {fileID: 0}
@@ -33,4 +37,6 @@ MonoBehaviour:
_outlineWidth: 4
_outlineIntensity: 2
_outlineMode: 0
+ _name:
+ _zOrder: 0
_enabled: 1
diff --git a/Assets/Examples/Scripts/OutlineEffectBuilder.cs b/Assets/Examples/Scripts/OutlineEffectBuilder.cs
index ff2e31b..c5a2355 100644
--- a/Assets/Examples/Scripts/OutlineEffectBuilder.cs
+++ b/Assets/Examples/Scripts/OutlineEffectBuilder.cs
@@ -47,6 +47,14 @@ private void Awake()
_outlineEffect.OutlineLayers.Add(_outlineLayer);
}
}
+
+ foreach (var go in _outlineGos)
+ {
+ if (go)
+ {
+ _outlineLayer.Add(go);
+ }
+ }
}
private void OnValidate()
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs
index bf49e44..cc46038 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs
@@ -9,7 +9,7 @@ namespace UnityFx.Outline
///
/// Defines outline settings.
///
- public interface IOutlineSettings
+ public interface IOutlineSettings : IEquatable
{
///
/// Gets or sets outline color.
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs
index 4f41843..11e3e0c 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs
@@ -171,9 +171,11 @@ private void Update()
if (_outlineResources != null && _renderers != null && (_outlineSettings.IsChanged || _commandBuffer.sizeInBytes == 0))
{
+ _commandBuffer.Clear();
+
using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget))
{
- renderer.RenderSingleObject(_renderers, _outlineSettings.OutlineMaterials);
+ renderer.Render(_renderers, _outlineSettings.OutlineResources, _outlineSettings);
}
_outlineSettings.AcceptChanges();
@@ -297,6 +299,16 @@ public OutlineMode OutlineMode
#endregion
+ #region IEquatable
+
+ ///
+ public bool Equals(IOutlineSettings other)
+ {
+ return OutlineSettings.Equals(_outlineSettings, other);
+ }
+
+ #endregion
+
#region implementation
private void RemoveDestroyedCameras()
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs
index c5f9e75..fe306cd 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs
@@ -264,6 +264,8 @@ private void Reset()
private void FillCommandBuffer()
{
+ _commandBuffer.Clear();
+
if (_outlineResources && _outlineResources.IsValid)
{
using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget))
@@ -271,10 +273,6 @@ private void FillCommandBuffer()
_outlineLayers.Render(renderer, _outlineResources);
}
}
- else
- {
- _commandBuffer.Clear();
- }
_changed = false;
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs
index acbcf47..f909b66 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs
@@ -210,6 +210,25 @@ public bool TryGetRenderers(GameObject go, out ICollection renderers)
return false;
}
+ ///
+ /// Renders the layers.
+ ///
+ public void Render(OutlineRenderer renderer, OutlineResources resources)
+ {
+ if (_enabled)
+ {
+ _settings.SetResources(resources);
+
+ foreach (var kvp in _outlineObjects)
+ {
+ if (kvp.Key && kvp.Key.activeInHierarchy)
+ {
+ renderer.Render(kvp.Value, _settings.OutlineResources, _settings);
+ }
+ }
+ }
+ }
+
#endregion
#region internals
@@ -257,22 +276,6 @@ internal void SetCollection(OutlineLayerCollection collection)
}
}
- internal void Render(OutlineRenderer renderer, OutlineResources resources)
- {
- if (_enabled)
- {
- _settings.SetResources(resources);
-
- foreach (var kvp in _outlineObjects)
- {
- if (kvp.Key && kvp.Key.activeInHierarchy)
- {
- renderer.RenderSingleObject(kvp.Value, _settings.OutlineMaterials);
- }
- }
- }
- }
-
#endregion
#region IOutlineSettingsEx
@@ -452,8 +455,19 @@ public void AcceptChanges()
#endregion
+ #region IEquatable
+
+ ///
+ public bool Equals(IOutlineSettings other)
+ {
+ return OutlineSettings.Equals(this, other);
+ }
+
+ #endregion
+
#region Object
+ ///
public override string ToString()
{
var text = new StringBuilder();
@@ -496,6 +510,18 @@ public override string ToString()
return string.Format("{0}", text);
}
+ ///
+ public override bool Equals(object other)
+ {
+ return OutlineSettings.Equals(this, other as IOutlineSettings);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
#endregion
#region implementation
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs
index 77b8a65..9ec46cf 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs
@@ -47,11 +47,24 @@ public OutlineLayer[] SortedLayers
{
get
{
- UpdateSortedLayersIdNeeded();
+ UpdateSortedLayersIfNeeded();
return _sortedLayers.ToArray();
}
}
+ ///
+ /// Renders all layers.
+ ///
+ public void Render(OutlineRenderer renderer, OutlineResources resources)
+ {
+ UpdateSortedLayersIfNeeded();
+
+ foreach (var layer in _sortedLayers)
+ {
+ layer.Render(renderer, resources);
+ }
+ }
+
#endregion
#region internals
@@ -78,16 +91,6 @@ internal void UpdateChanged()
}
}
- internal void Render(OutlineRenderer renderer, OutlineResources resources)
- {
- UpdateSortedLayersIdNeeded();
-
- foreach (var layer in _sortedLayers)
- {
- layer.Render(renderer, resources);
- }
- }
-
#endregion
#region ScriptableObject
@@ -327,7 +330,7 @@ public void AcceptChanges()
#region implementation
- private void UpdateSortedLayersIdNeeded()
+ private void UpdateSortedLayersIfNeeded()
{
if (_orderChanged)
{
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs
deleted file mode 100644
index e3e8ce7..0000000
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved.
-// See the LICENSE.md file in the project root for more information.
-
-using System;
-using UnityEngine;
-
-namespace UnityFx.Outline
-{
- ///
- /// A set of materials needed to render outlines.
- ///
- ///
- public sealed class OutlineMaterialSet : IOutlineSettings, IDisposable
- {
- #region data
-
- private readonly OutlineResources _outlineResources;
- private readonly Material _renderMaterial;
- private readonly Material _hPassMaterial;
- private readonly Material _vPassMaterial;
- private readonly float[] _gaussSamples = new float[OutlineRenderer.MaxWidth];
-
- private Color _color;
- private int _width = OutlineRenderer.MinWidth;
- private float _intensity = OutlineRenderer.MinIntensity;
- private OutlineMode _mode;
- private bool _disposed;
-
- #endregion
-
- #region interface
-
- ///
- /// NameID of the outline color shader parameter.
- ///
- public readonly int ColorNameId = Shader.PropertyToID("_Color");
-
- ///
- /// NameID of the outline width shader parameter.
- ///
- public readonly int WidthNameId = Shader.PropertyToID("_Width");
-
- ///
- /// NameID of the outline intensity shader parameter.
- ///
- public readonly int IntensityNameId = Shader.PropertyToID("_Intensity");
-
- ///
- /// NameID of the outline width shader parameter.
- ///
- public readonly int GaussSamplesNameId = Shader.PropertyToID("_GaussSamples");
-
- ///
- /// Gets resources used by the effect implementation.
- ///
- public OutlineResources OutlineResources
- {
- get
- {
- return _outlineResources;
- }
- }
-
- ///
- /// Gets material for .
- ///
- ///
- ///
- public Material RenderMaterial
- {
- get
- {
- return _renderMaterial;
- }
- }
-
- ///
- /// Gets material for .
- ///
- ///
- ///
- public Material HPassMaterial
- {
- get
- {
- return _hPassMaterial;
- }
- }
-
- ///
- /// Gets material for .
- ///
- ///
- ///
- public Material VPassBlendMaterial
- {
- get
- {
- return _vPassMaterial;
- }
- }
-
- ///
- /// Gets Gauss samples for blur calculations.
- ///
- public float[] GaussSamples
- {
- get
- {
- return _gaussSamples;
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The preferred way of creating instances of is calling method.
- ///
- public OutlineMaterialSet(OutlineResources resources)
- {
- if (resources == null)
- {
- throw new ArgumentNullException("resources");
- }
-
- _outlineResources = resources;
- _renderMaterial = new Material(resources.RenderShader);
- _hPassMaterial = new Material(resources.HPassShader);
- _vPassMaterial = new Material(resources.VPassBlendShader);
-
- _hPassMaterial.SetInt(WidthNameId, _width);
- _vPassMaterial.SetInt(WidthNameId, _width);
- _vPassMaterial.SetColor(ColorNameId, _color);
- _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity);
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- internal OutlineMaterialSet(OutlineResources resources, Material renderMaterial)
- {
- Debug.Assert(resources);
- Debug.Assert(resources.IsValid);
- Debug.Assert(renderMaterial);
-
- _outlineResources = resources;
- _renderMaterial = renderMaterial;
- _hPassMaterial = new Material(resources.HPassShader);
- _vPassMaterial = new Material(resources.VPassBlendShader);
-
- _hPassMaterial.SetInt(WidthNameId, _width);
- _vPassMaterial.SetInt(WidthNameId, _width);
- _vPassMaterial.SetColor(ColorNameId, _color);
- _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity);
- }
-
- ///
- /// Resets materials state.
- ///
- ///
- ///
- ///
- public void Reset(IOutlineSettings settings)
- {
- ThrowIfDisposed();
-
- if (settings == null)
- {
- throw new ArgumentNullException("settings");
- }
-
- SetColor(settings.OutlineColor);
- SetIntensity(settings.OutlineIntensity);
- SetWidth(settings.OutlineWidth);
- SetMode(settings.OutlineMode);
- UpdateGaussSamples();
- }
-
- #endregion
-
- #region IOutlineSettings
-
- ///
- public Color OutlineColor
- {
- get
- {
- return _color;
- }
- set
- {
- ThrowIfDisposed();
- SetColor(value);
- }
- }
-
- ///
- public int OutlineWidth
- {
- get
- {
- return _width;
- }
- set
- {
- ThrowIfDisposed();
-
- if (_width != value)
- {
- SetWidth(value);
- UpdateGaussSamples();
- }
- }
- }
-
- ///
- public float OutlineIntensity
- {
- get
- {
- return _intensity;
- }
- set
- {
- ThrowIfDisposed();
-
- if (_intensity != value)
- {
- SetIntensity(value);
- }
- }
- }
-
- ///
- public OutlineMode OutlineMode
- {
- get
- {
- return _mode;
- }
- set
- {
- ThrowIfDisposed();
-
- if (_mode != value)
- {
- SetMode(value);
- }
- }
- }
-
- #endregion
-
- #region IDisposable
-
- ///
- public void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
-
- if (_renderMaterial)
- {
- UnityEngine.Object.DestroyImmediate(_renderMaterial);
- }
-
- if (_hPassMaterial)
- {
- UnityEngine.Object.DestroyImmediate(_hPassMaterial);
- }
-
- if (_vPassMaterial)
- {
- UnityEngine.Object.DestroyImmediate(_vPassMaterial);
- }
- }
- }
-
- #endregion
-
- #region implementation
-
- private void SetColor(Color color)
- {
- _color = color;
- _vPassMaterial.SetColor(ColorNameId, color);
- }
-
- private void SetWidth(int width)
- {
- _width = Mathf.Clamp(width, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth);
- _hPassMaterial.SetInt(WidthNameId, _width);
- _vPassMaterial.SetInt(WidthNameId, _width);
- }
-
- private void SetIntensity(float intensity)
- {
- _intensity = Mathf.Clamp(intensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity);
- _vPassMaterial.SetFloat(IntensityNameId, _intensity);
- }
-
- private void SetMode(OutlineMode mode)
- {
- _mode = mode;
-
- if (mode == OutlineMode.Solid)
- {
- _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity);
- }
- else
- {
- _vPassMaterial.SetFloat(IntensityNameId, _intensity);
- }
- }
-
- private void UpdateGaussSamples()
- {
- OutlineRenderer.GetGaussSamples(_width, _gaussSamples);
- }
-
- private void ThrowIfDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
- }
-
- #endregion
- }
-}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs.meta b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs.meta
deleted file mode 100644
index 60b81e5..0000000
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: c4199c3138c5f4d45ac4e1663e30ee7d
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs
index 0866684..aa08159 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs
@@ -9,37 +9,74 @@
namespace UnityFx.Outline
{
///
- /// Helper low-level class for building outline .
+ /// Helper class for outline rendering with .
///
///
- /// This class is used by higher level outline implementations ( and ).
- /// It implements to be used inside block as shown in the code sample. Disposing
- /// does not dispose the .
+ /// The class can be used on its own or as part of a higher level systems. It is used
+ /// by higher level outline implementations ( and
+ /// ). It is fully compatible with Unity post processing stack as well.
+ /// The class implements to be used inside
+ /// block as shown in the code samples. Disposing does not dispose
+ /// the corresponding .
+ /// Command buffer is not cleared before rendering. It is user responsibility to do so if needed.
///
///
+ /// var commandBuffer = new CommandBuffer();
+ ///
/// using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget))
/// {
- /// renderer.RenderSingleObject(outlineRenderers, renderMaterial, postProcessMaterial);
+ /// renderer.Render(renderers, resources, settings);
/// }
+ ///
+ /// camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer);
///
- ///
+ ///
+ /// [Preserve]
+ /// public class OutlineEffectRenderer : PostProcessEffectRenderer
+ /// {
+ /// public override void Init()
+ /// {
+ /// base.Init();
+ ///
+ /// // Reuse fullscreen triangle mesh from PostProcessing (do not create own).
+ /// settings.OutlineResources.FullscreenTriangleMesh = RuntimeUtilities.fullscreenTriangle;
+ /// }
+ ///
+ /// public override void Render(PostProcessRenderContext context)
+ /// {
+ /// var resources = settings.OutlineResources;
+ /// var layers = settings.OutlineLayers;
+ ///
+ /// if (resources && resources.IsValid && layers)
+ /// {
+ /// // No need to setup property sheet parameters, all the rendering staff is handled by the OutlineRenderer.
+ /// using (var renderer = new OutlineRenderer(context.command, context.source, context.destination))
+ /// {
+ /// layers.Render(renderer, resources);
+ /// }
+ /// }
+ /// }
+ /// }
+ ///
+ ///
public struct OutlineRenderer : IDisposable
{
#region data
- private readonly int _maskRtId;
- private readonly int _hPassRtId;
- private readonly RenderTargetIdentifier _renderTarget;
- private readonly CommandBuffer _commandBuffer;
+ private static readonly int _mainRtId = Shader.PropertyToID("_MainTex");
+ private static readonly int _maskRtId = Shader.PropertyToID("_MaskTex");
+ private static readonly int _hPassRtId = Shader.PropertyToID("_HPassTex");
- private bool _disposed;
+ private readonly RenderTargetIdentifier _source;
+ private readonly RenderTargetIdentifier _destination;
+ private readonly CommandBuffer _commandBuffer;
#endregion
#region interface
///
- /// A outline rendering should be assosiated with.
+ /// A default outline rendering should be assosiated with.
///
public const CameraEvent RenderEvent = CameraEvent.BeforeImageEffects;
@@ -51,120 +88,158 @@ public struct OutlineRenderer : IDisposable
///
/// Minimum value of outline width parameter.
///
+ ///
public const int MinWidth = 1;
///
/// Maximum value of outline width parameter.
///
+ ///
public const int MaxWidth = 32;
///
/// Minimum value of outline intensity parameter.
///
+ ///
+ ///
public const int MinIntensity = 1;
///
/// Maximum value of outline intensity parameter.
///
+ ///
+ ///
public const int MaxIntensity = 64;
///
/// Value of outline intensity parameter that is treated as solid fill.
///
+ ///
+ ///
public const int SolidIntensity = 100;
///
/// Initializes a new instance of the struct.
///
- public OutlineRenderer(CommandBuffer commandBuffer, BuiltinRenderTextureType dst)
- : this(commandBuffer, new RenderTargetIdentifier(dst))
+ /// A to render the effect to. It should be cleared manually (if needed) before passing to this method.
+ /// Render target.
+ /// Thrown if is .
+ public OutlineRenderer(CommandBuffer commandBuffer, BuiltinRenderTextureType rt)
+ : this(commandBuffer, rt, rt)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// A to render the effect to. It should be cleared manually (if needed) before passing to this method.
+ /// Render target.
+ /// Thrown if is .
+ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier rt)
+ : this(commandBuffer, rt, rt)
{
}
///
/// Initializes a new instance of the struct.
///
- public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier dst)
+ /// A to render the effect to. It should be cleared manually (if needed) before passing to this method.
+ /// Source image. Can be the same as .
+ /// Render target.
+ /// Thrown if is .
+ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier src, RenderTargetIdentifier dst)
{
- Debug.Assert(commandBuffer != null);
+ if (commandBuffer == null)
+ {
+ throw new ArgumentNullException("commandBuffer");
+ }
- _disposed = false;
- _maskRtId = Shader.PropertyToID("_MaskTex");
- _hPassRtId = Shader.PropertyToID("_HPassTex");
- _renderTarget = dst;
+ _source = src;
+ _destination = dst;
_commandBuffer = commandBuffer;
- _commandBuffer.Clear();
_commandBuffer.BeginSample(EffectName);
_commandBuffer.GetTemporaryRT(_maskRtId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.R8);
_commandBuffer.GetTemporaryRT(_hPassRtId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.R8);
+
+ // Need to copy src content into dst if they are not the same. For instance this is the case when rendering
+ // the outline effect as part of Unity Post Processing stack.
+ if (!src.Equals(dst))
+ {
+ if (SystemInfo.copyTextureSupport > CopyTextureSupport.None)
+ {
+ _commandBuffer.CopyTexture(src, dst);
+ }
+ else
+ {
+#if UNITY_2018_2_OR_NEWER
+ _commandBuffer.SetRenderTarget(dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+#else
+ _commandBuffer.SetRenderTarget(dst);
+#endif
+ _commandBuffer.Blit(src, BuiltinRenderTextureType.CurrentActive);
+ }
+ }
}
///
- /// Adds commands for rendering single outline object.
+ /// Renders outline around a single object.
///
- public void RenderSingleObject(IEnumerable renderers, OutlineMaterialSet materials)
+ /// One or more renderers representing a single object to be outlined.
+ /// Outline resources.
+ /// Outline settings.
+ /// Thrown if any of the arguments is .
+ public void Render(IEnumerable renderers, OutlineResources resources, IOutlineSettings settings)
{
if (renderers == null)
{
throw new ArgumentNullException("renderers");
}
- if (materials == null)
+ if (resources == null)
{
- throw new ArgumentNullException("materials");
+ throw new ArgumentNullException("resources");
}
- _commandBuffer.SetRenderTarget(_maskRtId);
- _commandBuffer.ClearRenderTarget(false, true, Color.black);
-
- foreach (var r in renderers)
+ if (settings == null)
{
- if (r && r.enabled && r.gameObject.activeInHierarchy)
- {
- for (var j = 0; j < r.sharedMaterials.Length; ++j)
- {
- _commandBuffer.DrawRenderer(r, materials.RenderMaterial, j);
- }
- }
+ throw new ArgumentNullException("settings");
}
- _commandBuffer.SetGlobalFloatArray(materials.GaussSamplesNameId, materials.GaussSamples);
- _commandBuffer.SetGlobalTexture(_maskRtId, _maskRtId);
- _commandBuffer.Blit(_maskRtId, _hPassRtId, materials.HPassMaterial);
- _commandBuffer.Blit(_hPassRtId, _renderTarget, materials.VPassBlendMaterial);
+ Init(resources, settings);
+ RenderObject(renderers, resources.RenderMaterial);
+ RenderHPass(resources, settings);
+ RenderVPassBlend(resources, settings);
}
///
- /// Adds commands for rendering single outline object.
+ /// Renders outline around a single object.
///
- public void RenderSingleObject(Renderer renderer, OutlineMaterialSet materials)
+ /// A representing an object to be outlined.
+ /// Outline resources.
+ /// Outline settings.
+ /// Thrown if any of the arguments is .
+ public void Render(Renderer renderer, OutlineResources resources, IOutlineSettings settings)
{
if (renderer == null)
{
- throw new ArgumentNullException("renderer");
+ throw new ArgumentNullException("renderers");
}
- if (materials == null)
+ if (resources == null)
{
- throw new ArgumentNullException("materials");
+ throw new ArgumentNullException("resources");
}
- _commandBuffer.SetRenderTarget(_maskRtId);
- _commandBuffer.ClearRenderTarget(false, true, Color.black);
-
- if (renderer && renderer.gameObject.activeInHierarchy && renderer.enabled)
+ if (settings == null)
{
- for (var i = 0; i < renderer.sharedMaterials.Length; ++i)
- {
- _commandBuffer.DrawRenderer(renderer, materials.RenderMaterial, i);
- }
+ throw new ArgumentNullException("settings");
}
- _commandBuffer.SetGlobalFloatArray(materials.GaussSamplesNameId, materials.GaussSamples);
- _commandBuffer.SetGlobalTexture(_maskRtId, _maskRtId);
- _commandBuffer.Blit(_maskRtId, _hPassRtId, materials.HPassMaterial);
- _commandBuffer.Blit(_hPassRtId, _renderTarget, materials.VPassBlendMaterial);
+ Init(resources, settings);
+ RenderObject(renderer, resources.RenderMaterial);
+ RenderHPass(resources, settings);
+ RenderVPassBlend(resources, settings);
}
///
@@ -208,21 +283,115 @@ public static float[] GetGaussSamples(int width, float[] samples)
#region IDisposable
- ///
+ ///
+ /// Finalizes the effect rendering and releases temporary textures used. Should only be called once.
+ ///
public void Dispose()
{
- if (!_disposed)
- {
- _disposed = true;
- _commandBuffer.ReleaseTemporaryRT(_hPassRtId);
- _commandBuffer.ReleaseTemporaryRT(_maskRtId);
- _commandBuffer.EndSample(EffectName);
- }
+ _commandBuffer.ReleaseTemporaryRT(_hPassRtId);
+ _commandBuffer.ReleaseTemporaryRT(_maskRtId);
+ _commandBuffer.EndSample(EffectName);
}
#endregion
#region implementation
+
+ private void Init(OutlineResources resources, IOutlineSettings settings)
+ {
+ _commandBuffer.SetGlobalFloatArray(resources.GaussSamplesId, resources.GetGaussSamples(settings.OutlineWidth));
+ }
+
+ private void RenderObject(IEnumerable renderers, Material mat)
+ {
+#if UNITY_2018_2_OR_NEWER
+ _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+#else
+ _commandBuffer.SetRenderTarget(_maskRtId);
+#endif
+ _commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ foreach (var r in renderers)
+ {
+ if (r && r.enabled && r.gameObject.activeInHierarchy)
+ {
+ for (var j = 0; j < r.sharedMaterials.Length; ++j)
+ {
+ _commandBuffer.DrawRenderer(r, mat, j);
+ }
+ }
+ }
+ }
+
+ private void RenderObject(Renderer renderer, Material mat)
+ {
+#if UNITY_2018_2_OR_NEWER
+ _commandBuffer.SetRenderTarget(_maskRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+#else
+ _commandBuffer.SetRenderTarget(_maskRtId);
+#endif
+ _commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ if (renderer && renderer.gameObject.activeInHierarchy && renderer.enabled)
+ {
+ for (var i = 0; i < renderer.sharedMaterials.Length; ++i)
+ {
+ _commandBuffer.DrawRenderer(renderer, mat, i);
+ }
+ }
+ }
+
+ private void RenderHPass(OutlineResources resources, IOutlineSettings settings)
+ {
+ // Setup shader parameter overrides.
+ var props = resources.HPassProperties;
+ props.SetFloat(resources.WidthId, settings.OutlineWidth);
+
+ // Set source texture as _MainTex to match Blit behavior.
+ _commandBuffer.SetGlobalTexture(_mainRtId, _maskRtId);
+
+ // Set destination texture as render target.
+#if UNITY_2018_2_OR_NEWER
+ _commandBuffer.SetRenderTarget(_hPassRtId, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+#else
+ _commandBuffer.SetRenderTarget(_hPassRtId);
+#endif
+
+ // Blit fullscreen triangle.
+ _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.HPassMaterial, 0, 0, props);
+ }
+
+ private void RenderVPassBlend(OutlineResources resources, IOutlineSettings settings)
+ {
+ // Setup shader parameter overrides.
+ var props = resources.VPassBlendProperties;
+
+ props.SetFloat(resources.WidthId, settings.OutlineWidth);
+ props.SetColor(resources.ColorId, settings.OutlineColor);
+
+ if (settings.OutlineMode == OutlineMode.Solid)
+ {
+ props.SetFloat(resources.IntensityId, SolidIntensity);
+ }
+ else
+ {
+ props.SetFloat(resources.IntensityId, settings.OutlineIntensity);
+ }
+
+ // Set source texture as _MainTex to match Blit behavior.
+ _commandBuffer.SetGlobalTexture(_mainRtId, _source);
+
+ // Set destination texture as render target.
+#if UNITY_2018_2_OR_NEWER
+ _commandBuffer.SetRenderTarget(_destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+#else
+ _commandBuffer.SetRenderTarget(_destination);
+#endif
+
+ // Blit fullscreen triangle.
+ _commandBuffer.DrawMesh(resources.FullscreenTriangleMesh, Matrix4x4.identity, resources.VPassBlendMaterial, 0, 0, props);
+ }
+
#endregion
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs
index 98cbab0..36d4514 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs
@@ -9,10 +9,43 @@ namespace UnityFx.Outline
///
/// This asset is used to store references to shaders and other resources needed at runtime without having to use a Resources folder.
///
+ ///
[CreateAssetMenu(fileName = "OutlineResources", menuName = "UnityFx/Outline/Outline Resources")]
- public class OutlineResources : ScriptableObject
+ public sealed class OutlineResources : ScriptableObject
{
+ #region data
+
private Material _renderMaterial;
+ private Material _hPassMaterial;
+ private Material _vPassMaterial;
+ private MaterialPropertyBlock _hPassProperties;
+ private MaterialPropertyBlock _vPassProperties;
+ private Mesh _fullscreenTriangleMesh;
+ private float[][] _gaussSmples;
+
+ #endregion
+
+ #region interface
+
+ ///
+ /// Hashed name of _Color shader parameter.
+ ///
+ public readonly int ColorId = Shader.PropertyToID("_Color");
+
+ ///
+ /// Hashed name of _Width shader parameter.
+ ///
+ public readonly int WidthId = Shader.PropertyToID("_Width");
+
+ ///
+ /// Hashed name of _Intensity shader parameter.
+ ///
+ public readonly int IntensityId = Shader.PropertyToID("_Intensity");
+
+ ///
+ /// Hashed name of _GaussSamples shader parameter.
+ ///
+ public readonly int GaussSamplesId = Shader.PropertyToID("_GaussSamples");
///
/// Gets or sets a that renders objects outlined with a solid while color.
@@ -25,10 +58,130 @@ public class OutlineResources : ScriptableObject
public Shader HPassShader;
///
- /// Gets or sets a that renders outline around the mask, that was generated with (pass 2).
+ /// Gets or sets a that renders outline around the mask, that was generated with and (pass 2).
///
public Shader VPassBlendShader;
+ ///
+ /// Gets a -based material.
+ ///
+ public Material RenderMaterial
+ {
+ get
+ {
+ if (_renderMaterial == null)
+ {
+ _renderMaterial = new Material(RenderShader)
+ {
+ name = "Outline - SimpleRender",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+ }
+
+ return _renderMaterial;
+ }
+ }
+
+ ///
+ /// Gets a -based material.
+ ///
+ public Material HPassMaterial
+ {
+ get
+ {
+ if (_hPassMaterial == null)
+ {
+ _hPassMaterial = new Material(HPassShader)
+ {
+ name = "Outline - HPassRender",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+ }
+
+ return _hPassMaterial;
+ }
+ }
+
+ ///
+ /// Gets a -based material.
+ ///
+ public Material VPassBlendMaterial
+ {
+ get
+ {
+ if (_vPassMaterial == null)
+ {
+ _vPassMaterial = new Material(VPassBlendShader)
+ {
+ name = "Outline - VPassBlendRender",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+ }
+
+ return _vPassMaterial;
+ }
+ }
+
+ ///
+ /// Gets a for .
+ ///
+ public MaterialPropertyBlock HPassProperties
+ {
+ get
+ {
+ if (_hPassProperties == null)
+ {
+ _hPassProperties = new MaterialPropertyBlock();
+ }
+
+ return _hPassProperties;
+ }
+ }
+
+ ///
+ /// Gets a for .
+ ///
+ public MaterialPropertyBlock VPassBlendProperties
+ {
+ get
+ {
+ if (_vPassProperties == null)
+ {
+ _vPassProperties = new MaterialPropertyBlock();
+ }
+
+ return _vPassProperties;
+ }
+ }
+
+ ///
+ /// Gets or sets a fullscreen triangle mesh.
+ ///
+ public Mesh FullscreenTriangleMesh
+ {
+ get
+ {
+ if (_fullscreenTriangleMesh == null)
+ {
+ _fullscreenTriangleMesh = new Mesh()
+ {
+ name = "Outline - FullscreenTriangle",
+ hideFlags = HideFlags.HideAndDontSave,
+ vertices = new Vector3[] { new Vector3(-1f, -1f, 0f), new Vector3(-1f, 3f, 0f), new Vector3( 3f, -1f, 0f) },
+ triangles = new int[] {0, 1, 2 }
+ };
+
+ _fullscreenTriangleMesh.UploadMeshData(true);
+ }
+
+ return _fullscreenTriangleMesh;
+ }
+ set
+ {
+ _fullscreenTriangleMesh = value;
+ }
+ }
+
///
/// Gets a value indicating whether the instance is in valid state.
///
@@ -40,6 +193,24 @@ public bool IsValid
}
}
+ ///
+ /// Gets cached gauss samples for the specified outline .
+ ///
+ public float[] GetGaussSamples(int width)
+ {
+ if (_gaussSmples == null)
+ {
+ _gaussSmples = new float[OutlineRenderer.MaxWidth][];
+ }
+
+ if (_gaussSmples[width] == null)
+ {
+ _gaussSmples[width] = OutlineRenderer.GetGaussSamples(width, null);
+ }
+
+ return _gaussSmples[width];
+ }
+
///
/// Resets the resources to defaults.
///
@@ -50,17 +221,6 @@ public void ResetToDefaults()
VPassBlendShader = Shader.Find("UnityFx/Outline/VPassBlend");
}
- ///
- /// Gets a new instance for the resources.
- ///
- public OutlineMaterialSet CreateMaterialSet()
- {
- if (_renderMaterial == null)
- {
- _renderMaterial = new Material(RenderShader);
- }
-
- return new OutlineMaterialSet(this, _renderMaterial);
- }
+ #endregion
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs
index e9e0d76..7bb7cfe 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs
@@ -27,6 +27,20 @@ public sealed class OutlineSettings : ScriptableObject, IOutlineSettings
#endregion
#region interface
+
+ public static bool Equals(IOutlineSettings lhs, IOutlineSettings rhs)
+ {
+ if (lhs == null || rhs == null)
+ {
+ return false;
+ }
+
+ return lhs.OutlineColor == rhs.OutlineColor &&
+ lhs.OutlineWidth == rhs.OutlineWidth &&
+ lhs.OutlineMode == rhs.OutlineMode &&
+ Mathf.Approximately(lhs.OutlineIntensity, rhs.OutlineIntensity);
+ }
+
#endregion
#region IOutlineSettings
@@ -84,5 +98,31 @@ public OutlineMode OutlineMode
}
#endregion
+
+ #region IEquatable
+
+ ///
+ public bool Equals(IOutlineSettings other)
+ {
+ return Equals(this, other);
+ }
+
+ #endregion
+
+ #region Object
+
+ ///
+ public override bool Equals(object other)
+ {
+ return Equals(this, other as IOutlineSettings);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ #endregion
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs
index b8509da..cd90e9c 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs
@@ -8,7 +8,7 @@
namespace UnityFx.Outline
{
[Serializable]
- internal class OutlineSettingsInstance : IOutlineSettingsEx, IChangeTracking, IDisposable
+ internal class OutlineSettingsInstance : IOutlineSettingsEx, IChangeTracking
{
#region data
@@ -28,35 +28,26 @@ internal class OutlineSettingsInstance : IOutlineSettingsEx, IChangeTracking, ID
#pragma warning restore 0649
- private OutlineMaterialSet _materials;
+ private OutlineResources _resources;
private bool _changed = true;
#endregion
#region interface
- public OutlineMaterialSet OutlineMaterials
+ public OutlineResources OutlineResources
{
get
{
- return _materials;
+ return _resources;
}
}
internal void SetResources(OutlineResources resources)
{
- if (resources == null)
+ if (resources != _resources)
{
- if (_materials != null)
- {
- _materials.Dispose();
- _materials = null;
- }
- }
- else if (_materials == null || _materials.OutlineResources != resources)
- {
- _materials = resources.CreateMaterialSet();
- _materials.Reset(this);
+ _resources = resources;
_changed = true;
}
}
@@ -65,20 +56,15 @@ internal void UpdateChanged()
{
if (_outlineSettings != null)
{
- _outlineColor = _outlineSettings.OutlineColor;
- _outlineWidth = _outlineSettings.OutlineWidth;
- _outlineIntensity = _outlineSettings.OutlineIntensity;
- _outlineMode = _outlineSettings.OutlineMode;
- }
-
- if (_materials != null)
- {
- if (_outlineColor != _materials.OutlineColor ||
- _outlineWidth != _materials.OutlineWidth ||
- _outlineIntensity != _materials.OutlineIntensity ||
- _outlineMode != _materials.OutlineMode)
+ if (_outlineColor != _outlineSettings.OutlineColor ||
+ _outlineWidth != _outlineSettings.OutlineWidth ||
+ _outlineIntensity != _outlineSettings.OutlineIntensity ||
+ _outlineMode != _outlineSettings.OutlineMode)
{
- _materials.Reset(this);
+ _outlineColor = _outlineSettings.OutlineColor;
+ _outlineWidth = _outlineSettings.OutlineWidth;
+ _outlineIntensity = _outlineSettings.OutlineIntensity;
+ _outlineMode = _outlineSettings.OutlineMode;
_changed = true;
}
}
@@ -106,12 +92,6 @@ public OutlineSettings OutlineSettings
_outlineWidth = _outlineSettings.OutlineWidth;
_outlineIntensity = _outlineSettings.OutlineIntensity;
_outlineMode = _outlineSettings.OutlineMode;
-
- if (_materials != null)
- {
- _materials.Reset(this);
- }
-
_changed = true;
}
}
@@ -137,11 +117,6 @@ public Color OutlineColor
{
_outlineColor = value;
_changed = true;
-
- if (_materials != null)
- {
- _materials.OutlineColor = value;
- }
}
}
}
@@ -163,11 +138,6 @@ public int OutlineWidth
{
_outlineWidth = value;
_changed = true;
-
- if (_materials != null)
- {
- _materials.OutlineWidth = value;
- }
}
}
}
@@ -189,11 +159,6 @@ public float OutlineIntensity
{
_outlineIntensity = value;
_changed = true;
-
- if (_materials != null)
- {
- _materials.OutlineIntensity = value;
- }
}
}
}
@@ -213,11 +178,6 @@ public OutlineMode OutlineMode
{
_outlineMode = value;
_changed = true;
-
- if (_materials != null)
- {
- _materials.OutlineMode = value;
- }
}
}
}
@@ -243,15 +203,11 @@ public void AcceptChanges()
#endregion
- #region IDisposable
+ #region IEquatable
- public void Dispose()
+ public bool Equals(IOutlineSettings other)
{
- if (_materials != null)
- {
- _materials.Dispose();
- _materials = null;
- }
+ return OutlineSettings.Equals(this, other);
}
#endregion
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader
index e617203..737bf8c 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass1.shader
@@ -12,19 +12,20 @@ Shader "UnityFx/Outline/HPass"
SubShader
{
+ Cull Off
ZWrite Off
ZTest Always
Lighting Off
Pass
{
- CGPROGRAM
+ HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
+ #pragma vertex Vert
+ #pragma fragment Frag
#include "UnityCG.cginc"
- sampler2D _MaskTex;
+ UNITY_DECLARE_TEX2D(_MaskTex);
float2 _MaskTex_TexelSize;
int _Width;
float _GaussSamples[32];
@@ -35,17 +36,17 @@ Shader "UnityFx/Outline/HPass"
float2 uvs : TEXCOORD0;
};
- v2f vert(appdata_base v)
+ v2f Vert(appdata_base v)
{
v2f o;
- o.pos = UnityObjectToClipPos(v.vertex);
+ o.pos = float4(v.vertex.xy, 0.0, 1.0);
o.uvs = ComputeScreenPos(o.pos);
return o;
}
- float frag(v2f i) : COLOR
+ float Frag(v2f i) : COLOR
{
float TX_x = _MaskTex_TexelSize.x;
float intensity;
@@ -53,13 +54,13 @@ Shader "UnityFx/Outline/HPass"
for (int k = -n; k <= n; k += 1)
{
- intensity += tex2D(_MaskTex, i.uvs.xy + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)];
+ intensity += UNITY_SAMPLE_TEX2D(_MaskTex, i.uvs.xy + float2(k * TX_x, 0)).r * _GaussSamples[abs(k)];
}
return intensity;
}
- ENDCG
+ ENDHLSL
}
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader
index 3221d7a..5b46ff2 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlinePass2.shader
@@ -14,19 +14,24 @@ Shader "UnityFx/Outline/VPassBlend"
SubShader
{
+ Cull Off
+ ZWrite Off
+ ZTest Always
+ Lighting Off
+
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
- CGPROGRAM
+ HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
+ #pragma vertex Vert
+ #pragma fragment Frag
#include "UnityCG.cginc"
- sampler2D _MaskTex;
+ UNITY_DECLARE_TEX2D(_MaskTex);
float2 _MaskTex_TexelSize;
- sampler2D _HPassTex;
+ UNITY_DECLARE_TEX2D(_HPassTex);
float2 _HPassTex_TexelSize;
float4 _Color;
float _Intensity;
@@ -39,19 +44,19 @@ Shader "UnityFx/Outline/VPassBlend"
float2 uvs : TEXCOORD0;
};
- v2f vert(appdata_base v)
+ v2f Vert(appdata_base v)
{
v2f o;
- o.pos = UnityObjectToClipPos(v.vertex);
+ o.pos = float4(v.vertex.xy, 0.0, 1.0);
o.uvs = ComputeScreenPos(o.pos);
return o;
}
- float4 frag(v2f i) : COLOR
+ float4 Frag(v2f i) : COLOR
{
- if (tex2D(_MaskTex, i.uvs.xy).r > 0)
+ if (UNITY_SAMPLE_TEX2D(_MaskTex, i.uvs.xy).r > 0)
{
discard;
}
@@ -62,14 +67,14 @@ Shader "UnityFx/Outline/VPassBlend"
for (int k = -n; k <= _Width; k += 1)
{
- intensity += tex2D(_HPassTex, i.uvs.xy + float2(0, k * TX_y)).r * _GaussSamples[abs(k)];
+ intensity += UNITY_SAMPLE_TEX2D(_HPassTex, i.uvs.xy + float2(0, k * TX_y)).r * _GaussSamples[abs(k)];
}
intensity = _Intensity > 99 ? step(0.01, intensity) : intensity * _Intensity;
return float4(_Color.rgb, saturate(_Color.a * intensity));
}
- ENDCG
+ ENDHLSL
}
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader
index 2d81bf9..1b79f93 100644
--- a/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader
+++ b/Assets/Plugins/UnityFx.Outline/Runtime/Shaders/OutlineRenderColor.shader
@@ -7,35 +7,37 @@ Shader "UnityFx/Outline/RenderColor"
{
SubShader
{
+ Cull Off
ZWrite Off
ZTest Always
Lighting Off
Pass
{
- CGPROGRAM
+ HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
+ #pragma vertex Vert
+ #pragma fragment Frag
+ #include "UnityCG.cginc"
struct v2f
{
float4 pos: POSITION;
};
- v2f vert(v2f i)
+ v2f Vert(v2f i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.pos);
return o;
}
- half4 frag(): COLOR0
+ half4 Frag(): COLOR0
{
return half4(1, 1, 1, 1);
}
- ENDCG
+ ENDHLSL
}
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs
deleted file mode 100644
index c35cf03..0000000
--- a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved.
-// See the LICENSE.md file in the project root for more information.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using UnityEditor;
-using UnityEngine;
-using UnityEngine.TestTools;
-using NUnit.Framework;
-
-namespace UnityFx.Outline
-{
- [Category("OutlineMaterialSet"), TestOf(typeof(OutlineMaterialSet))]
- public class OutlineMaterialSetTests : IOutlineSettingsTests, IDisposable
- {
- private OutlineResources _resources;
- private OutlineMaterialSet _materialSet;
-
- [SetUp]
- public void Init()
- {
- _resources = ScriptableObject.CreateInstance();
- _materialSet = _resources.CreateMaterialSet();
- Init(_materialSet);
- }
-
- [TearDown]
- public void Dispose()
- {
- _materialSet.Dispose();
- UnityEngine.Object.DestroyImmediate(_resources);
- }
-
- [Test]
- public void Dispose_CanBeCalledMultipleTimes()
- {
- _materialSet.Dispose();
- _materialSet.Dispose();
- }
-
- [Test]
- public void Reset_ThrowsIfDisposed()
- {
- _materialSet.Dispose();
-
- Assert.Throws(() => _materialSet.Reset(_materialSet));
- }
-
- [Test]
- public void Reset_ThrowsIfArgumentIsNull()
- {
- Assert.Throws(() => _materialSet.Reset(null));
- }
-
- [Test]
- public void Reset_SetsValuesPassed()
- {
- var settings = ScriptableObject.CreateInstance();
-
- try
- {
- settings.OutlineColor = Color.yellow;
- settings.OutlineWidth = 20;
- settings.OutlineIntensity = 5;
- settings.OutlineMode = OutlineMode.Blurred;
-
- _materialSet.Reset(settings);
-
- Assert.AreEqual(settings.OutlineColor, _materialSet.OutlineColor);
- Assert.AreEqual(settings.OutlineWidth, _materialSet.OutlineWidth);
- Assert.AreEqual(settings.OutlineIntensity, _materialSet.OutlineIntensity);
- Assert.AreEqual(settings.OutlineMode, _materialSet.OutlineMode);
- }
- finally
- {
- UnityEngine.Object.DestroyImmediate(settings);
- }
- }
-
- [Test]
- public void OutlineColor_ThrowsIfDisposed()
- {
- _materialSet.Dispose();
-
- Assert.Throws(() => _materialSet.OutlineColor = Color.magenta);
- }
-
- [Test]
- public void OutlineColor_SetsMaterialParams()
- {
- var color = Color.blue;
- _materialSet.OutlineColor = color;
-
- Assert.AreEqual(color, _materialSet.VPassBlendMaterial.GetColor(_materialSet.ColorNameId));
- }
-
- [Test]
- public void OutlineWidth_ThrowsIfDisposed()
- {
- _materialSet.Dispose();
-
- Assert.Throws(() => _materialSet.OutlineWidth = 10);
- }
-
- [Test]
- public void OutlineWidth_SetsMaterialParams()
- {
- var width = UnityEngine.Random.Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth);
- _materialSet.OutlineWidth = width;
-
- Assert.AreEqual(width, _materialSet.HPassMaterial.GetInt(_materialSet.WidthNameId));
- Assert.AreEqual(width, _materialSet.VPassBlendMaterial.GetInt(_materialSet.WidthNameId));
- }
-
- [Test]
- public void OutlineMode_SetsMaterialParams()
- {
- _materialSet.OutlineMode = OutlineMode.Solid;
- Assert.AreEqual(OutlineRenderer.SolidIntensity, _materialSet.VPassBlendMaterial.GetFloat(_materialSet.IntensityNameId));
- }
-
- [Test]
- public void OutlineIntensity_SetsMaterialParams()
- {
- var intensity = UnityEngine.Random.Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity);
-
- _materialSet.OutlineIntensity = intensity;
-
- Assert.AreEqual(intensity, _materialSet.VPassBlendMaterial.GetFloat(_materialSet.IntensityNameId));
- }
- }
-}
diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta
deleted file mode 100644
index 8b04847..0000000
--- a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 8dd20ed2fbac7544a91b914158581811
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs
index 137c1b1..fc2b70f 100644
--- a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs
+++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs
@@ -40,8 +40,8 @@ public void Dispose_CanBeCalledMultipleTimes()
[Test]
public void RenderSingleObject_ThrowsIfNullArguments()
{
- Assert.Throws(() => _renderer.RenderSingleObject(default(IList), null));
- Assert.Throws(() => _renderer.RenderSingleObject(default(Renderer), null));
+ Assert.Throws(() => _renderer.Render(default(IList), null, null));
+ Assert.Throws(() => _renderer.Render(default(Renderer), null, null));
}
}
}
diff --git a/Assets/Plugins/UnityFx.Outline/package.json b/Assets/Plugins/UnityFx.Outline/package.json
index 006fc6a..696575f 100644
--- a/Assets/Plugins/UnityFx.Outline/package.json
+++ b/Assets/Plugins/UnityFx.Outline/package.json
@@ -1,7 +1,7 @@
{
"name": "com.unityfx.outline",
- "version": "0.5.0",
- "displayName": "Screen-space outline for Unity",
+ "version": "0.7.0",
+ "displayName": "Screen-space outlines for Unity",
"description": "Configurable per-object and per-camera outlines. Both solid and blurred outline modes are supported (Gauss blur). The outlines can be easily customized either through scripts or with Unity editor (both in edit-time or runtime).",
"unity": "2017.2",
"keywords": [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ffc89a3..14e4872 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/).
+## [0.7.0] - 2019.11.26
+
+`MaterialPropertyBlock`-based rendering and [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2) compatibility.
+
+### Added
+- Moved to for `MaterialPropertyBlock`-based rendering. This is in-line with Unity post-processing Stack and is more performant approach.
+- Significant optimizations made to `OutlineRenderer`.
+
+### Changed
+- `IOutlineSettings` now implements `IEquatable`.
+- Changed all outline shaders to use HLSL-based macros.
+- Modified all shaders to ignore MVP vertex transform to be compatible with the new rendering model.
+- Exposed rendering APIs for `OutlineLayer` and `OutlineLayerCollection`.
+
+### Fixed
+- Fixed `TiledGPUPerformanceWarning` on mobile targets.
+
+### Removed
+- Removed `OutlineMaterialSet` class. It is not used in `MaterialPropertyBlock`-based effect rendering.
+
## [0.6.0] - 2019.09.26
Quality of life improvements.
diff --git a/README.md b/README.md
index 6a6928d..15725b4 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,8 @@ Channel | UnityFx.Outline |
Github | [![GitHub release](https://img.shields.io/github/release/Arvtesh/UnityFx.Outline.svg?logo=github)](https://github.com/Arvtesh/UnityFx.Outline/releases)
Npm | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.svg)](https://www.npmjs.com/package/com.unityfx.outline) ![npm](https://img.shields.io/npm/dt/com.unityfx.outline)
-**Requires Unity 2017 or higher.**
+**Requires Unity 2017 or higher.**
+**Compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2).**
## Synopsis
![Outline demo](Docs/OutlineSamples.png "Outline demo")
@@ -13,7 +14,7 @@ Npm | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.svg)](htt
*UnityFx.Outline* implements configurable per-object and per-camera outlines. Both solid and blurred outline modes are supported (Gauss blur). The outlines can be easily customized either through scripts or with Unity editor (both in edit-time or runtime).
-Implementation is based on Unity [command buffers](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html), does not require putting objects into layers and has no dependencies.
+Implementation is based on Unity [command buffers](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html), compatible with [Unity Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2), extendable and has no external dependencies.
Supported outline parameters are:
- Color;
@@ -22,8 +23,9 @@ Supported outline parameters are:
- Intensity (for blurred outlines).
Supported platforms:
-- Windows standalone;
-- More platforms to test.
+- Windows/Mac standalone;
+- Android;
+- iOS.
Please see [CHANGELOG](CHANGELOG.md) for information on recent changes.
@@ -54,7 +56,7 @@ Npm package is available at [npmjs.com](https://www.npmjs.com/package/com.unityf
}
],
"dependencies": {
- "com.unityfx.outline": "0.6.0"
+ "com.unityfx.outline": "0.7.0"
}
}
```
@@ -81,7 +83,7 @@ layer.Add(myGo);
outlineEffect.OutlineLayers.Add(layer);
```
-This can be done at runtime or while editing a scene. If you choose to assign the script in runtime make sure `OutlineEffect.OutlineResources` is initialied. Disabling `OutlineEffect` script disables outlining for the camera (and frees all resources used).
+This can be done at runtime or while editing a scene. If you choose to assign the script in runtime make sure `OutlineEffect.OutlineResources` is initialized. Disabling `OutlineEffect` script disables outlining for the camera (and frees all resources used).
Multiple `OutlineEffect` scripts can share outline layers rendered. To achieve that assign the same layer set to all `OutlineEffect` instances:
@@ -113,25 +115,63 @@ outlineBehaviour.OutlineIntensity = 10;
There are a number of helper classes that can be used for writing highly customized outline implementations (if neither `OutlineBehaviour` nor `OutlineEffect` does not suit your needs).
All outline implementations use following helpers:
- `OutlineRenderer` is basically a wrapper around `CommandBuffer` for low-level outline rendering.
-- `OutlineMaterialSet` is a set of materials used by `OutlineRenderer` for rendering.
+- `OutlineSettings` is a set of outline settings.
Using these helpers is quite easy to create new outline tools. For instance, the following code renders a blue outline around object the script is attached to in `myCamera`:
```csharp
var commandBuffer = new CommandBuffer();
var renderers = GetComponentsInChildren();
-var materials = outlineResources.CreateMaterialSet();
-materials.OutlineColor = Color.blue;
+// Any implementation of `IOutlineSettings` interface can be used here instead of `OutlineSettings`.
+var settings = ScriptableObject.CreateInstance();
+
+settings.OutlineColor = Color.blue;
+settings.OutlineWidth = 12;
+
+// Get outline assets instance. In real app this usually comes from MonoBehaviour's serialized fields.
+var resources = GetMyResources();
using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget))
{
- renderer.RenderSingleObject(renderers, materials);
+ renderer.Render(renderers, resources, settings);
}
myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer);
```
+### Integration with Unity post-processing.
+
+The outline effect can easily be added to [Post-processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2). A minimal integration example is shown below:
+```csharp
+using System;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+using UnityFx.Outline;
+
+[Serializable]
+[PostProcess(typeof(OutlineEffectRenderer), PostProcessEvent.BeforeStack, "MyOutline", false)]
+public sealed class Outline : PostProcessEffectSettings
+{
+ public OutlineResources OutlineResources;
+ public OutlineLayers OutlineLayers;
+}
+
+public sealed class OutlineEffectRenderer : PostProcessEffectRenderer
+{
+ public override void Render(PostProcessRenderContext context)
+ {
+ using (var renderer = new OutlineRenderer(context.command, context.source, context.destination))
+ {
+ settings.OutlineLayers.Render(renderer, settings.OutlineResources);
+ }
+ }
+}
+```
+For the sake of simplicity the sample does not include any kind of error checking and no editor integration provided. In real world app the `Outline` class should expose its data to Unity editor either via custom inspector or using parameter overrides. Also, there are quite a few optimizations missing (for example, resusing `RuntimeUtilities.fullscreenTriangle` value as `OutlineResources.FullscreenTriangleMesh`).
+
+More info on writing custom post processing effects can be found [here](https://docs.unity3d.com/Packages/com.unity.postprocessing@2.2/manual/Writing-Custom-Effects.html).
+
## Motivation
The project was initially created to help author with his [Unity3d](https://unity3d.com) projects. There are not many reusable open-source examples of it, so here it is. Hope it will be useful for someone.
@@ -145,6 +185,7 @@ Please see the links below for extended information on the product:
- [A great outline tutorial](https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/).
- [Command buffers tutorial](https://lindenreid.wordpress.com/2018/09/13/using-command-buffers-in-unity-selective-bloom/).
- [Gaussian blur tutorial](https://www.ronja-tutorials.com/2018/08/27/postprocessing-blur.html).
+- [Excellent post-processing tutorial](https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/post-processing/).
## Contributing
Please see [contributing guide](.github/CONTRIBUTING.md) for details.