237 lines
7.6 KiB
C#
237 lines
7.6 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using EPOOutline;
|
|
using System;
|
|
using System.Reflection;
|
|
|
|
#if URP_OUTLINE && UNITY_2019_1_OR_NEWER
|
|
#if UNITY_2019_3_OR_NEWER
|
|
using UnityEngine.Rendering.Universal;
|
|
#else
|
|
using UnityEngine.Rendering.LWRP;
|
|
#endif
|
|
|
|
public class URPOutlineFeature : ScriptableRendererFeature
|
|
{
|
|
private class SRPOutline : ScriptableRenderPass
|
|
{
|
|
private static List<Outlinable> temporaryOutlinables = new List<Outlinable>();
|
|
|
|
public ScriptableRenderer Renderer;
|
|
|
|
public bool UseColorTargetForDepth;
|
|
|
|
public Outliner Outliner;
|
|
|
|
public OutlineParameters Parameters = new OutlineParameters();
|
|
|
|
private List<Outliner> outliners = new List<Outliner>();
|
|
|
|
public SRPOutline()
|
|
{
|
|
Parameters.CheckInitialization();
|
|
}
|
|
|
|
private FieldInfo nameId = typeof(RenderTargetIdentifier).GetField("m_NameID", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
|
private bool IsDepthTextureAvailable(ScriptableRenderer renderer)
|
|
{
|
|
#if UNITY_2022_1_OR_NEWER
|
|
return renderer.cameraDepthTargetHandle.rt != null;
|
|
#else
|
|
return (int)nameId.GetValue(GetDepthTarget(renderer)) != -1;
|
|
#endif
|
|
}
|
|
|
|
private RenderTargetIdentifier GetDepthTarget(ScriptableRenderer renderer)
|
|
{
|
|
return
|
|
#if UNITY_2022_1_OR_NEWER
|
|
Renderer.cameraDepthTargetHandle;
|
|
#elif UNITY_2020_2_OR_NEWER
|
|
Renderer.cameraDepthTarget;
|
|
#else
|
|
Renderer.cameraDepth;
|
|
#endif
|
|
}
|
|
|
|
private RenderTargetIdentifier GetColorTarget(ScriptableRenderer renderer)
|
|
{
|
|
#if UNITY_2022_1_OR_NEWER
|
|
return renderer.cameraColorTargetHandle;
|
|
#else
|
|
return renderer.cameraColorTarget;
|
|
#endif
|
|
}
|
|
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
var camera = renderingData.cameraData.camera;
|
|
|
|
var outlineEffect = Outliner;
|
|
if (outlineEffect == null || !outlineEffect.enabled)
|
|
return;
|
|
|
|
#if UNITY_EDITOR
|
|
Parameters.Buffer.name = renderingData.cameraData.camera.name;
|
|
#endif
|
|
|
|
Outlinable.GetAllActiveOutlinables(renderingData.cameraData.camera, Parameters.OutlinablesToRender);
|
|
|
|
Outliner.UpdateSharedParameters(Parameters, renderingData.cameraData.camera, renderingData.cameraData.isSceneViewCamera);
|
|
|
|
RendererFilteringUtility.Filter(renderingData.cameraData.camera, Parameters);
|
|
|
|
Parameters.TargetWidth = renderingData.cameraData.cameraTargetDescriptor.width;
|
|
Parameters.TargetHeight = renderingData.cameraData.cameraTargetDescriptor.height;
|
|
|
|
Parameters.Antialiasing = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
|
|
|
|
Parameters.Target = RenderTargetUtility.ComposeTarget(Parameters, Renderer.cameraColorTarget);
|
|
Parameters.DepthTarget =
|
|
#if UNITY_2019_3_OR_NEWER && !UNITY_2019_3_0 && !UNITY_2019_3_1 && !UNITY_2019_3_2 && !UNITY_2019_3_3 && !UNITY_2019_3_4 && !UNITY_2019_3_5 && !UNITY_2019_3_6 && !UNITY_2019_3_7 && !UNITY_2019_3_8
|
|
RenderTargetUtility.ComposeTarget(Parameters, !IsDepthTextureAvailable(Renderer) ? GetColorTarget(Renderer) :
|
|
GetDepthTarget(Renderer));
|
|
#else
|
|
RenderTargetUtility.ComposeTarget(Parameters, Renderer.cameraColorTarget);
|
|
#endif
|
|
|
|
Parameters.Buffer.Clear();
|
|
if (Outliner.RenderingStrategy == OutlineRenderingStrategy.Default)
|
|
{
|
|
OutlineEffect.SetupOutline(Parameters);
|
|
Parameters.BlitMesh = null;
|
|
Parameters.MeshPool.ReleaseAllMeshes();
|
|
}
|
|
else
|
|
{
|
|
temporaryOutlinables.Clear();
|
|
temporaryOutlinables.AddRange(Parameters.OutlinablesToRender);
|
|
|
|
Parameters.OutlinablesToRender.Clear();
|
|
Parameters.OutlinablesToRender.Add(null);
|
|
|
|
foreach (var outlinable in temporaryOutlinables)
|
|
{
|
|
Parameters.OutlinablesToRender[0] = outlinable;
|
|
OutlineEffect.SetupOutline(Parameters);
|
|
Parameters.BlitMesh = null;
|
|
}
|
|
|
|
Parameters.MeshPool.ReleaseAllMeshes();
|
|
}
|
|
|
|
context.ExecuteCommandBuffer(Parameters.Buffer);
|
|
}
|
|
}
|
|
|
|
private class Pool
|
|
{
|
|
private Stack<SRPOutline> outlines = new Stack<SRPOutline>();
|
|
|
|
private List<SRPOutline> createdOutlines = new List<SRPOutline>();
|
|
|
|
public SRPOutline Get()
|
|
{
|
|
if (outlines.Count == 0)
|
|
{
|
|
outlines.Push(new SRPOutline());
|
|
createdOutlines.Add(outlines.Peek());
|
|
}
|
|
|
|
return outlines.Pop();
|
|
}
|
|
|
|
public void ReleaseAll()
|
|
{
|
|
outlines.Clear();
|
|
foreach (var outline in createdOutlines)
|
|
outlines.Push(outline);
|
|
}
|
|
}
|
|
|
|
private GameObject lastSelectedCamera;
|
|
|
|
private Pool outlinePool = new Pool();
|
|
|
|
private List<Outliner> outliners = new List<Outliner>();
|
|
|
|
private bool GetOutlinersToRenderWith(RenderingData renderingData, List<Outliner> outliners)
|
|
{
|
|
outliners.Clear();
|
|
var camera = renderingData.cameraData.camera.gameObject;
|
|
camera.GetComponents(outliners);
|
|
if (outliners.Count == 0)
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (renderingData.cameraData.isSceneViewCamera)
|
|
{
|
|
var foundObject = Array.Find(
|
|
Array.ConvertAll(UnityEditor.Selection.gameObjects, x => x.GetComponent<Outliner>()),
|
|
x => x != null);
|
|
|
|
camera = foundObject?.gameObject ?? lastSelectedCamera;
|
|
|
|
if (camera == null)
|
|
return false;
|
|
else
|
|
camera.GetComponents(outliners);
|
|
}
|
|
else
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
var hasOutliners = outliners.Count > 0;
|
|
if (hasOutliners)
|
|
lastSelectedCamera = camera;
|
|
|
|
return hasOutliners;
|
|
}
|
|
|
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
|
{
|
|
if (!GetOutlinersToRenderWith(renderingData, outliners))
|
|
return;
|
|
|
|
#if UNITY_2019_3_OR_NEWER && !UNITY_2019_3_0 && !UNITY_2019_3_1 && !UNITY_2019_3_2 && !UNITY_2019_3_3 && !UNITY_2019_3_4 && !UNITY_2019_3_5 && !UNITY_2019_3_6 && !UNITY_2019_3_7 && !UNITY_2019_3_8
|
|
var additionalCameraData = renderingData.cameraData.camera.GetUniversalAdditionalCameraData();
|
|
var activeStackCount = 0;
|
|
if (additionalCameraData != null)
|
|
{
|
|
var stack = additionalCameraData.renderType == CameraRenderType.Overlay ? null : additionalCameraData.cameraStack;
|
|
if (stack != null)
|
|
{
|
|
foreach (var camera in stack)
|
|
{
|
|
if (camera != null && camera.isActiveAndEnabled)
|
|
activeStackCount++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
foreach (var outliner in outliners)
|
|
{
|
|
var outline = outlinePool.Get();
|
|
|
|
outline.Outliner = outliner;
|
|
|
|
outline.Renderer = renderer;
|
|
|
|
outline.renderPassEvent = outliner.RenderStage == RenderStage.AfterTransparents ? RenderPassEvent.AfterRenderingTransparents : RenderPassEvent.AfterRenderingOpaques;
|
|
|
|
renderer.EnqueuePass(outline);
|
|
}
|
|
|
|
outlinePool.ReleaseAll();
|
|
}
|
|
|
|
public override void Create()
|
|
{
|
|
}
|
|
}
|
|
#endif |