372 lines
9.2 KiB
C#
372 lines
9.2 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using System;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace EPOOutline
|
|
{
|
|
public enum DilateRenderMode
|
|
{
|
|
PostProcessing,
|
|
EdgeShift
|
|
}
|
|
|
|
public enum RenderStyle
|
|
{
|
|
Single = 1,
|
|
FrontBack = 2
|
|
}
|
|
|
|
[Flags]
|
|
public enum OutlinableDrawingMode
|
|
{
|
|
Normal = 1,
|
|
ZOnly = 2,
|
|
GenericMask = 4,
|
|
Obstacle = 8,
|
|
Mask = 16
|
|
}
|
|
|
|
[Flags]
|
|
public enum RenderersAddingMode
|
|
{
|
|
All = -1,
|
|
None = 0,
|
|
MeshRenderer = 1,
|
|
SkinnedMeshRenderer = 2,
|
|
SpriteRenderer = 4,
|
|
Others = 4096
|
|
}
|
|
|
|
public enum BoundsMode
|
|
{
|
|
Default,
|
|
ForceRecalculate,
|
|
Manual
|
|
}
|
|
|
|
public enum ComplexMaskingMode
|
|
{
|
|
None,
|
|
ObstaclesMode,
|
|
MaskingMode
|
|
}
|
|
|
|
[ExecuteAlways]
|
|
public class Outlinable : MonoBehaviour
|
|
{
|
|
private static HashSet<Outlinable> outlinables = new HashSet<Outlinable>();
|
|
|
|
private static Plane[] frustrumPlanes = new Plane[6];
|
|
|
|
[System.Serializable]
|
|
public class OutlineProperties
|
|
{
|
|
#pragma warning disable CS0649
|
|
[SerializeField]
|
|
private bool enabled = true;
|
|
|
|
public bool Enabled
|
|
{
|
|
get
|
|
{
|
|
return enabled;
|
|
}
|
|
|
|
set
|
|
{
|
|
enabled = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private Color color = Color.yellow;
|
|
|
|
public Color Color
|
|
{
|
|
get
|
|
{
|
|
return color;
|
|
}
|
|
|
|
set
|
|
{
|
|
color = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0.0f, 1.0f)]
|
|
private float dilateShift = 1.0f;
|
|
|
|
public float DilateShift
|
|
{
|
|
get
|
|
{
|
|
return dilateShift;
|
|
}
|
|
|
|
set
|
|
{
|
|
dilateShift = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0.0f, 1.0f)]
|
|
private float blurShift = 1.0f;
|
|
|
|
public float BlurShift
|
|
{
|
|
get
|
|
{
|
|
return blurShift;
|
|
}
|
|
|
|
set
|
|
{
|
|
blurShift = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField, SerializedPassInfo("Fill style", "Hidden/EPO/Fill/")]
|
|
private SerializedPass fillPass = new SerializedPass();
|
|
|
|
public SerializedPass FillPass
|
|
{
|
|
get
|
|
{
|
|
return fillPass;
|
|
}
|
|
}
|
|
#pragma warning restore CS0649
|
|
}
|
|
|
|
[SerializeField]
|
|
private ComplexMaskingMode complexMaskingMode;
|
|
|
|
[SerializeField]
|
|
private OutlinableDrawingMode drawingMode = OutlinableDrawingMode.Normal;
|
|
|
|
[SerializeField]
|
|
private int outlineLayer = 0;
|
|
|
|
[SerializeField]
|
|
private List<OutlineTarget> outlineTargets = new List<OutlineTarget>();
|
|
|
|
[SerializeField]
|
|
private RenderStyle renderStyle = RenderStyle.Single;
|
|
|
|
#pragma warning disable CS0649
|
|
[SerializeField]
|
|
private OutlineProperties outlineParameters = new OutlineProperties();
|
|
|
|
[SerializeField]
|
|
private OutlineProperties backParameters = new OutlineProperties();
|
|
|
|
[SerializeField]
|
|
private OutlineProperties frontParameters = new OutlineProperties();
|
|
|
|
#pragma warning restore CS0649
|
|
|
|
public RenderStyle RenderStyle
|
|
{
|
|
get
|
|
{
|
|
return renderStyle;
|
|
}
|
|
|
|
set
|
|
{
|
|
renderStyle = value;
|
|
}
|
|
}
|
|
|
|
public ComplexMaskingMode ComplexMaskingMode
|
|
{
|
|
get
|
|
{
|
|
return complexMaskingMode;
|
|
}
|
|
|
|
set
|
|
{
|
|
complexMaskingMode = value;
|
|
}
|
|
}
|
|
|
|
public bool ComplexMaskingEnabled
|
|
{
|
|
get
|
|
{
|
|
return complexMaskingMode != ComplexMaskingMode.None;
|
|
}
|
|
}
|
|
|
|
public OutlinableDrawingMode DrawingMode
|
|
{
|
|
get
|
|
{
|
|
return drawingMode;
|
|
}
|
|
|
|
set
|
|
{
|
|
drawingMode = value;
|
|
}
|
|
}
|
|
|
|
public int OutlineLayer
|
|
{
|
|
get
|
|
{
|
|
return outlineLayer;
|
|
}
|
|
|
|
set
|
|
{
|
|
outlineLayer = value;
|
|
}
|
|
}
|
|
|
|
|
|
public List<OutlineTarget> OutlineTargets
|
|
{
|
|
get
|
|
{
|
|
return outlineTargets;
|
|
}
|
|
}
|
|
|
|
public OutlineProperties OutlineParameters
|
|
{
|
|
get
|
|
{
|
|
return outlineParameters;
|
|
}
|
|
}
|
|
|
|
public OutlineProperties BackParameters
|
|
{
|
|
get
|
|
{
|
|
return backParameters;
|
|
}
|
|
}
|
|
|
|
public OutlineProperties FrontParameters
|
|
{
|
|
get
|
|
{
|
|
return frontParameters;
|
|
}
|
|
}
|
|
|
|
public bool IsObstacle
|
|
{
|
|
get
|
|
{
|
|
return (drawingMode & OutlinableDrawingMode.Obstacle) != 0;
|
|
}
|
|
}
|
|
|
|
private bool IsVisible(Plane[] planes)
|
|
{
|
|
var visibleCount = 0;
|
|
foreach (var target in outlineTargets)
|
|
{
|
|
if (target.Renderer != null && GeometryUtility.TestPlanesAABB(planes, target.Renderer.bounds))
|
|
visibleCount++;
|
|
}
|
|
|
|
return visibleCount > 0;
|
|
}
|
|
|
|
private void Reset()
|
|
{
|
|
AddAllChildRenderersToRenderingList(RenderersAddingMode.SkinnedMeshRenderer | RenderersAddingMode.MeshRenderer | RenderersAddingMode.SpriteRenderer);
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
outlineLayer = Mathf.Clamp(outlineLayer, 0, 63);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
outlinables.Add(this);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
outlinables.Remove(this);
|
|
}
|
|
|
|
public static void GetAllActiveOutlinables(Camera camera, List<Outlinable> outlinablesList)
|
|
{
|
|
outlinablesList.Clear();
|
|
GeometryUtility.CalculateFrustumPlanes(camera, frustrumPlanes);
|
|
foreach (var outlinable in outlinables)
|
|
if (outlinable.IsVisible(frustrumPlanes))
|
|
outlinablesList.Add(outlinable);
|
|
}
|
|
|
|
private int GetSubmeshCount(Renderer renderer)
|
|
{
|
|
if (renderer is MeshRenderer)
|
|
return renderer.GetComponent<MeshFilter>().sharedMesh.subMeshCount;
|
|
else if (renderer is SkinnedMeshRenderer)
|
|
return (renderer as SkinnedMeshRenderer).sharedMesh.subMeshCount;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
public void AddAllChildRenderersToRenderingList(RenderersAddingMode renderersAddingMode = RenderersAddingMode.All)
|
|
{
|
|
outlineTargets.Clear();
|
|
var renderers = GetComponentsInChildren<Renderer>(true);
|
|
foreach (var renderer in renderers)
|
|
{
|
|
if (!MatchingMode(renderer, renderersAddingMode))
|
|
continue;
|
|
|
|
var submeshesCount = GetSubmeshCount(renderer);
|
|
for (var index = 0; index < submeshesCount; index++)
|
|
outlineTargets.Add(new OutlineTarget(renderer, index));
|
|
}
|
|
}
|
|
|
|
private bool MatchingMode(Renderer renderer, RenderersAddingMode mode)
|
|
{
|
|
return
|
|
(!(renderer is MeshRenderer) && !(renderer is SkinnedMeshRenderer) && !(renderer is SpriteRenderer) && (mode & RenderersAddingMode.Others) != RenderersAddingMode.None) ||
|
|
(renderer is MeshRenderer && (mode & RenderersAddingMode.MeshRenderer) != RenderersAddingMode.None) ||
|
|
(renderer is SpriteRenderer && (mode & RenderersAddingMode.SpriteRenderer) != RenderersAddingMode.None) ||
|
|
(renderer is SkinnedMeshRenderer && (mode & RenderersAddingMode.SkinnedMeshRenderer) != RenderersAddingMode.None);
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public void OnDrawGizmosSelected()
|
|
{
|
|
foreach (var target in outlineTargets)
|
|
{
|
|
if (target.Renderer == null || target.BoundsMode != BoundsMode.Manual)
|
|
continue;
|
|
|
|
Gizmos.matrix = target.Renderer.transform.localToWorldMatrix;
|
|
|
|
Gizmos.color = new Color(1.0f, 0.5f, 0.0f, 0.2f);
|
|
var size = target.Bounds.size;
|
|
var scale = target.Renderer.transform.localScale;
|
|
size.x /= scale.x;
|
|
size.y /= scale.y;
|
|
size.z /= scale.z;
|
|
|
|
Gizmos.DrawCube(target.Bounds.center, size);
|
|
Gizmos.DrawWireCube(target.Bounds.center, size);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
} |