Files
2024-11-20 15:21:28 +01:00

230 lines
8.1 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using EPOOutline;
using System;
#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();
}
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);
var targetTexture = camera.targetTexture == null ? camera.activeTexture : camera.targetTexture;
if (UnityEngine.XR.XRSettings.enabled
&& !Parameters.IsEditorCamera
&& Parameters.EyeMask != StereoTargetEyeMask.None)
{
var descriptor = UnityEngine.XR.XRSettings.eyeTextureDesc;
Parameters.TargetWidth = descriptor.width;
Parameters.TargetHeight = descriptor.height;
}
else
{
Parameters.TargetWidth = targetTexture != null ? targetTexture.width : (int)(camera.scaledPixelWidth * renderingData.cameraData.renderScale);
Parameters.TargetHeight = targetTexture != null ? targetTexture.height : (int)(camera.scaledPixelHeight * renderingData.cameraData.renderScale);
}
Parameters.Antialiasing = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
var useCustomRenderTarget = Outliner.HasCutomRenderTarget && !renderingData.cameraData.isSceneViewCamera;
Parameters.Target = RenderTargetUtility.ComposeTarget(Parameters, useCustomRenderTarget ? Outliner.GetRenderTarget(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, UseColorTargetForDepth ? Renderer.cameraColorTarget :
#if UNITY_2020_2_OR_NEWER
Renderer.cameraDepthTarget);
#else
Renderer.cameraDepth);
#endif
#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
var shouldUseDepthTarget = renderingData.cameraData.requiresDepthTexture && renderingData.cameraData.cameraTargetDescriptor.msaaSamples <= 1 && !renderingData.cameraData.isSceneViewCamera;
foreach (var outliner in outliners)
{
var outline = outlinePool.Get();
outline.Outliner = outliner;
outline.UseColorTargetForDepth =
#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
(additionalCameraData == null || activeStackCount == 0 && additionalCameraData.renderType != CameraRenderType.Overlay) &&
#endif
!shouldUseDepthTarget;
outline.Renderer = renderer;
outline.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
renderer.EnqueuePass(outline);
}
outlinePool.ReleaseAll();
}
public override void Create()
{
}
}
#endif