// Copyright (C) 2019-2021 Alexander Bogarsukov. All rights reserved.
// See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
using UnityEngine.XR;
namespace UnityFx.Outline.URP
{
internal class OutlinePass : ScriptableRenderPass
{
//private const string _profilerTag = "OutlinePass";
//private static readonly ProfilingSampler _profilingSampler = new ProfilingSampler(_profilerTag);
private readonly OutlineFeature _feature;
private readonly List<OutlineRenderObject> _renderObjects = new List<OutlineRenderObject>();
private readonly List<ShaderTagId> _shaderTagIdList = new List<ShaderTagId>();
private ScriptableRenderer _renderer;
public OutlinePass(OutlineFeature feature, string[] shaderTags)
{
_feature = feature;
if (shaderTags != null && shaderTags.Length > 0)
{
foreach (var passName in shaderTags)
{
_shaderTagIdList.Add(new ShaderTagId(passName));
}
}
else
{
_shaderTagIdList.Add(new ShaderTagId("UniversalForward"));
_shaderTagIdList.Add(new ShaderTagId("LightweightForward"));
_shaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
}
}
public void Setup(ScriptableRenderer renderer)
{
_renderer = renderer;
}
public class PassData {
internal RendererListHandle rendererListHandle;
internal IOutlineSettings outlineSettings;
internal OutlineResources outlineResources;
internal OutlineLayerCollection outlineLayers;
internal int outlineLayerMask;
internal uint outlineRenderingLayerMask;
internal ScriptableRenderer renderer;
internal List<OutlineRenderObject> renderObjects;
internal TextureHandle cameraColorTarget;
internal RenderTextureDescriptor targetDescriptor;
}
static void ExecuteDrawPass(PassData data, UnsafeGraphContext context)
{
if (data.outlineLayerMask != 0)
{
var depthTexture = new RenderTargetIdentifier("_CameraDepthTexture");
if (data.outlineSettings.IsAlphaTestingEnabled())
{
context.cmd.SetGlobalFloat(data.outlineResources.AlphaCutoffId, data.outlineSettings.OutlineAlphaCutoff);
}
using (var renderer = new OutlineRenderer(CommandBufferHelpers.GetNativeCommandBuffer(context.cmd), data.outlineResources, data.cameraColorTarget, depthTexture, data.targetDescriptor))
{
renderer.RenderObjectClear(data.outlineSettings.OutlineRenderMode);
context.cmd.DrawRendererList(data.rendererListHandle);
renderer.RenderOutline(data.outlineSettings);
}
}
if (data.outlineLayers)
{
var depthTexture = new RenderTargetIdentifier("_CameraDepthTexture");
using (var renderer = new OutlineRenderer(CommandBufferHelpers.GetNativeCommandBuffer(context.cmd), data.outlineResources, data.cameraColorTarget, depthTexture, data.targetDescriptor))
{
data.renderObjects.Clear();
data.outlineLayers.GetRenderObjects(data.renderObjects);
renderer.Render(data.renderObjects);
}
}
//context.cmd.DrawRendererList(data.rendererListHandle);
}
private void InitRendererLists(ContextContainer frameData, ref PassData passData, RenderGraph renderGraph)
{
UniversalRenderingData universalRenderingData = frameData.Get<UniversalRenderingData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
UniversalLightData lightData = frameData.Get<UniversalLightData>();
SortingCriteria sortFlags = cameraData.defaultOpaqueSortFlags;
RenderQueueRange renderQueueRange = RenderQueueRange.opaque;
/* // or for transparents :
sortFlags = SortingCriteria.CommonTransparent;
renderQueueRange = RenderQueueRange.transparent;
*/
FilteringSettings filterSettings = new FilteringSettings(renderQueueRange, _feature.OutlineLayerMask);
DrawingSettings drawSettings = RenderingUtils.CreateDrawingSettings(_shaderTagIdList, universalRenderingData, cameraData, lightData, sortFlags);
drawSettings.overrideMaterialPassIndex = _feature.OutlineSettings.IsAlphaTestingEnabled()?
OutlineResources.RenderShaderAlphaTestPassId :
OutlineResources.RenderShaderDefaultPassId;
var param = new RendererListParams(universalRenderingData.cullResults, drawSettings, filterSettings);
passData.rendererListHandle = renderGraph.CreateRendererList(param);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
// Draw Renderers
using (var builder = renderGraph.AddUnsafePass<PassData>("Custom DrawRendererList Pass", out var passData))
{
// Init PassData
InitRendererLists(frameData, ref passData, renderGraph);
if (!passData.rendererListHandle.IsValid()) return;
passData.outlineSettings = _feature.OutlineSettings;
passData.outlineResources = _feature.OutlineResources;
passData.outlineLayers = _feature.OutlineLayers;
passData.outlineLayerMask = _feature.OutlineLayerMask;
passData.outlineRenderingLayerMask = _feature.OutlineRenderingLayerMask;
passData.cameraColorTarget = resourceData.cameraColor;
passData.targetDescriptor = cameraData.cameraTargetDescriptor;
passData.renderer = _renderer;
passData.renderObjects = _renderObjects;
// Declare Inputs
builder.UseRendererList(passData.rendererListHandle);
// Set Render Target
//builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
//builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture);
// Assign ExecutePass
builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => ExecuteDrawPass(data, context));
}
}
}
}