TurnBasedStrategyCourse/Library/PackageCache/com.unity.render-pipelines..../Runtime/RendererFeatures/FullScreenPassRendererFeatu...

212 lines
9.1 KiB
C#

using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
/// <summary>
/// FullScreenPass is a renderer feature used to change screen appearance such as post processing effect. This implementation
/// lets it's user create an effect with minimal code involvement.
/// </summary>
[URPHelpURL("renderer-features/renderer-feature-full-screen-pass")]
public class FullScreenPassRendererFeature : ScriptableRendererFeature
{
/// <summary>
/// An injection point for the full screen pass. This is similar to RenderPassEvent enum but limits to only supported events.
/// </summary>
public enum InjectionPoint
{
/// <summary>
/// Inject a full screen pass before transparents are rendered
/// </summary>
BeforeRenderingTransparents = RenderPassEvent.BeforeRenderingTransparents,
/// <summary>
/// Inject a full screen pass before post processing is rendered
/// </summary>
BeforeRenderingPostProcessing = RenderPassEvent.BeforeRenderingPostProcessing,
/// <summary>
/// Inject a full screen pass after post processing is rendered
/// </summary>
AfterRenderingPostProcessing = RenderPassEvent.AfterRenderingPostProcessing
}
/// <summary>
/// Material the Renderer Feature uses to render the effect.
/// </summary>
public Material passMaterial;
/// <summary>
/// Selection for when the effect is rendered.
/// </summary>
public InjectionPoint injectionPoint = InjectionPoint.AfterRenderingPostProcessing;
/// <summary>
/// One or more requirements for pass. Based on chosen flags certain passes will be added to the pipeline.
/// </summary>
public ScriptableRenderPassInput requirements = ScriptableRenderPassInput.Color;
/// <summary>
/// An index that tells renderer feature which pass to use if passMaterial contains more than one. Default is 0.
/// We draw custom pass index entry with the custom dropdown inside FullScreenPassRendererFeatureEditor that sets this value.
/// Setting it directly will be overridden by the editor class.
/// </summary>
[HideInInspector]
public int passIndex = 0;
private FullScreenRenderPass fullScreenPass;
private bool requiresColor;
private bool injectedBeforeTransparents;
/// <inheritdoc/>
public override void Create()
{
fullScreenPass = new FullScreenRenderPass();
fullScreenPass.renderPassEvent = (RenderPassEvent)injectionPoint;
// This copy of requirements is used as a parameter to configure input in order to avoid copy color pass
ScriptableRenderPassInput modifiedRequirements = requirements;
requiresColor = (requirements & ScriptableRenderPassInput.Color) != 0;
injectedBeforeTransparents = injectionPoint <= InjectionPoint.BeforeRenderingTransparents;
if (requiresColor && !injectedBeforeTransparents)
{
// Removing Color flag in order to avoid unnecessary CopyColor pass
// Does not apply to before rendering transparents, due to how depth and color are being handled until
// that injection point.
modifiedRequirements ^= ScriptableRenderPassInput.Color;
}
fullScreenPass.ConfigureInput(modifiedRequirements);
}
/// <inheritdoc/>
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (passMaterial == null)
{
Debug.LogWarningFormat("Missing Post Processing effect Material. {0} Fullscreen pass will not execute. Check for missing reference in the assigned renderer.", GetType().Name);
return;
}
fullScreenPass.Setup(passMaterial, passIndex, requiresColor, injectedBeforeTransparents, "FullScreenPassRendererFeature", renderingData);
renderer.EnqueuePass(fullScreenPass);
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
fullScreenPass.Dispose();
}
class FullScreenRenderPass : ScriptableRenderPass
{
private static Material s_PassMaterial;
private int m_PassIndex;
private bool m_RequiresColor;
private bool m_IsBeforeTransparents;
private PassData m_PassData;
private ProfilingSampler m_ProfilingSampler;
private RTHandle m_CopiedColor;
private static readonly int m_BlitTextureShaderID = Shader.PropertyToID("_BlitTexture");
public void Setup(Material mat, int index, bool requiresColor, bool isBeforeTransparents, string featureName, in RenderingData renderingData)
{
s_PassMaterial = mat;
m_PassIndex = index;
m_RequiresColor = requiresColor;
m_IsBeforeTransparents = isBeforeTransparents;
m_ProfilingSampler ??= new ProfilingSampler(featureName);
var colorCopyDescriptor = renderingData.cameraData.cameraTargetDescriptor;
colorCopyDescriptor.depthBufferBits = (int) DepthBits.None;
RenderingUtils.ReAllocateIfNeeded(ref m_CopiedColor, colorCopyDescriptor, name: "_FullscreenPassColorCopy");
m_PassData ??= new PassData();
}
public void Dispose()
{
m_CopiedColor?.Release();
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
ref var cameraData = ref renderingData.cameraData;
var cmd = renderingData.commandBuffer;
// ExecutePass(m_PassData, renderingData.cameraData, renderingData.commandBuffer);
if (s_PassMaterial == null)
{
// should not happen as we check it in feature
return;
}
if (cameraData.isPreviewCamera)
{
return;
}
using (new ProfilingScope(cmd, profilingSampler))
{
if (m_RequiresColor)
{
// For some reason BlitCameraTexture(cmd, dest, dest) scenario (as with before transparents effects) blitter fails to correctly blit the data
// Sometimes it copies only one effect out of two, sometimes second, sometimes data is invalid (as if sampling failed?).
// Adding RTHandle in between solves this issue.
var source = m_IsBeforeTransparents ? cameraData.renderer.GetCameraColorBackBuffer(cmd) : cameraData.renderer.cameraColorTargetHandle;
Blitter.BlitCameraTexture(cmd, source, m_CopiedColor);
s_PassMaterial.SetTexture(m_BlitTextureShaderID, m_CopiedColor);
}
CoreUtils.SetRenderTarget(cmd, cameraData.renderer.GetCameraColorBackBuffer(cmd));
CoreUtils.DrawFullScreen(cmd, s_PassMaterial);
}
}
public override void RecordRenderGraph(RenderGraph renderGraph, FrameResources frameResources, ref RenderingData renderingData)
{
UniversalRenderer renderer = (UniversalRenderer) renderingData.cameraData.renderer;
var colorCopyDescriptor = renderingData.cameraData.cameraTargetDescriptor;
colorCopyDescriptor.depthBufferBits = (int) DepthBits.None;
TextureHandle copiedColor = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorCopyDescriptor, "_FullscreenPassColorCopy", false);
if (m_RequiresColor)
{
using (var builder = renderGraph.AddRasterRenderPass<PassData>("CustomPostPro_ColorPass", out var passData, m_ProfilingSampler))
{
passData.source = builder.UseTexture(renderer.activeColorTexture, IBaseRenderGraphBuilder.AccessFlags.Read);
passData.copiedColor = builder.UseTextureFragment(copiedColor, 0, IBaseRenderGraphBuilder.AccessFlags.Write);
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) =>
{
Blitter.BlitTexture(rgContext.cmd, data.source, new Vector4(1, 1, 0, 0), 0.0f, false);
});
}
}
using (var builder = renderGraph.AddRasterRenderPass<PassData>("CustomPostPro_FullScreenPass", out var passData, m_ProfilingSampler))
{
passData.passIndex = m_PassIndex;
if (m_RequiresColor)
passData.copiedColor = builder.UseTexture(copiedColor, IBaseRenderGraphBuilder.AccessFlags.Read);
passData.source = builder.UseTextureFragment(renderer.activeColorTexture, 0, IBaseRenderGraphBuilder.AccessFlags.Write);
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) =>
{
Blitter.BlitTexture(rgContext.cmd, data.copiedColor, new Vector4(1, 1, 0, 0), s_PassMaterial, data.passIndex);
});
}
}
private class PassData
{
internal Material effectMaterial;
internal int passIndex;
internal TextureHandle source;
public TextureHandle copiedColor;
}
}
}