230 lines
11 KiB
C#
230 lines
11 KiB
C#
|
|
using System;
|
||
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
||
|
|
using System.Runtime.CompilerServices; // AggressiveInlining
|
||
|
|
|
||
|
|
namespace UnityEngine.Rendering.Universal
|
||
|
|
{
|
||
|
|
internal sealed class SmaaPostProcessPass : PostProcessPass
|
||
|
|
{
|
||
|
|
public const string k_TargetName = "_SMAATarget";
|
||
|
|
|
||
|
|
Material m_Material;
|
||
|
|
bool m_IsValid;
|
||
|
|
|
||
|
|
// Static resource textures for SMAA technique
|
||
|
|
Texture2D m_AreaTexture;
|
||
|
|
Texture2D m_SearchTexture;
|
||
|
|
|
||
|
|
Experimental.Rendering.GraphicsFormat m_SMAAEdgeFormat;
|
||
|
|
|
||
|
|
AntialiasingQuality m_AntiAliasingQuality;
|
||
|
|
|
||
|
|
public SmaaPostProcessPass(Shader shader, Texture2D smaaAreaTexture, Texture2D smaaSearchTexture)
|
||
|
|
{
|
||
|
|
this.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing - 1;
|
||
|
|
this.profilingSampler = null;
|
||
|
|
|
||
|
|
m_Material = PostProcessUtils.LoadShader(shader, passName);
|
||
|
|
m_IsValid = m_Material != null;
|
||
|
|
|
||
|
|
m_AreaTexture = smaaAreaTexture;
|
||
|
|
m_SearchTexture = smaaSearchTexture;
|
||
|
|
|
||
|
|
// SMAA
|
||
|
|
// Only two components are needed for edge render texture, but on some vendors four components may be faster.
|
||
|
|
if (SystemInfo.IsFormatSupported(Experimental.Rendering.GraphicsFormat.R8G8_UNorm, Experimental.Rendering.GraphicsFormatUsage.Render) && SystemInfo.graphicsDeviceVendor.ToLowerInvariant().Contains("arm"))
|
||
|
|
m_SMAAEdgeFormat = Experimental.Rendering.GraphicsFormat.R8G8_UNorm;
|
||
|
|
else
|
||
|
|
m_SMAAEdgeFormat = Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm;
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void Dispose()
|
||
|
|
{
|
||
|
|
CoreUtils.Destroy(m_Material);
|
||
|
|
m_IsValid = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Setup(AntialiasingQuality antialiasingQuality)
|
||
|
|
{
|
||
|
|
m_AntiAliasingQuality = antialiasingQuality;
|
||
|
|
}
|
||
|
|
|
||
|
|
private class SMAASetupPassData
|
||
|
|
{
|
||
|
|
internal Vector4 metrics;
|
||
|
|
internal Texture2D areaTexture;
|
||
|
|
internal Texture2D searchTexture;
|
||
|
|
internal float stencilRef;
|
||
|
|
internal float stencilMask;
|
||
|
|
internal AntialiasingQuality antialiasingQuality;
|
||
|
|
internal Material material;
|
||
|
|
internal TextureHandle sourceTexture;
|
||
|
|
}
|
||
|
|
|
||
|
|
private class SMAAPassData
|
||
|
|
{
|
||
|
|
internal TextureHandle sourceTexture;
|
||
|
|
internal TextureHandle blendTexture;
|
||
|
|
internal Material material;
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
||
|
|
{
|
||
|
|
if (!m_IsValid)
|
||
|
|
return;
|
||
|
|
|
||
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
||
|
|
|
||
|
|
var sourceTexture = resourceData.cameraColor;
|
||
|
|
|
||
|
|
var destDesc = renderGraph.GetTextureDesc(sourceTexture);
|
||
|
|
var destinationTexture = PostProcessUtils.CreateCompatibleTexture(renderGraph, destDesc, k_TargetName, true, FilterMode.Bilinear);
|
||
|
|
|
||
|
|
destDesc.clearColor = Color.black;
|
||
|
|
destDesc.clearColor.a = 0.0f;
|
||
|
|
|
||
|
|
var edgeTextureDesc = destDesc;
|
||
|
|
edgeTextureDesc.format = m_SMAAEdgeFormat;
|
||
|
|
var edgeTexture = PostProcessUtils.CreateCompatibleTexture(renderGraph, edgeTextureDesc, "_EdgeStencilTexture", true, FilterMode.Bilinear);
|
||
|
|
|
||
|
|
var edgeTextureStencilDesc = destDesc;
|
||
|
|
edgeTextureStencilDesc.format = Experimental.Rendering.GraphicsFormatUtility.GetDepthStencilFormat(24);
|
||
|
|
var edgeTextureStencil = PostProcessUtils.CreateCompatibleTexture(renderGraph, edgeTextureStencilDesc, "_EdgeTexture", true, FilterMode.Bilinear);
|
||
|
|
|
||
|
|
var blendTextureDesc = destDesc;
|
||
|
|
blendTextureDesc.format = Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm;
|
||
|
|
var blendTexture = PostProcessUtils.CreateCompatibleTexture(renderGraph, blendTextureDesc, "_BlendTexture", true, FilterMode.Point);
|
||
|
|
|
||
|
|
using (var builder = renderGraph.AddRasterRenderPass<SMAASetupPassData>("SMAA Edge Detection", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAAEdgeDetection)))
|
||
|
|
{
|
||
|
|
// Material setup
|
||
|
|
const int kStencilBit = 64;
|
||
|
|
// TODO RENDERGRAPH: handle dynamic scaling
|
||
|
|
passData.metrics = new Vector4(1f / destDesc.width, 1f / destDesc.height, destDesc.width, destDesc.height);
|
||
|
|
|
||
|
|
// TODO: These are constant for every frame
|
||
|
|
passData.areaTexture = m_AreaTexture;
|
||
|
|
passData.searchTexture = m_SearchTexture;
|
||
|
|
passData.stencilRef = (float)kStencilBit;
|
||
|
|
passData.stencilMask = (float)kStencilBit;
|
||
|
|
|
||
|
|
passData.antialiasingQuality = m_AntiAliasingQuality;
|
||
|
|
passData.material = m_Material;
|
||
|
|
|
||
|
|
builder.SetRenderAttachment(edgeTexture, 0, AccessFlags.Write);
|
||
|
|
builder.SetRenderAttachmentDepth(edgeTextureStencil, AccessFlags.Write);
|
||
|
|
passData.sourceTexture = sourceTexture;
|
||
|
|
builder.UseTexture(sourceTexture, AccessFlags.Read);
|
||
|
|
builder.UseTexture(resourceData.cameraDepth ,AccessFlags.Read);
|
||
|
|
|
||
|
|
builder.SetRenderFunc(static (SMAASetupPassData data, RasterGraphContext context) =>
|
||
|
|
{
|
||
|
|
var SMAAMaterial = data.material;
|
||
|
|
var cmd = context.cmd;
|
||
|
|
RTHandle sourceTextureHdl = data.sourceTexture;
|
||
|
|
|
||
|
|
// Pass 0: Material Setup
|
||
|
|
SetupMaterial(data);
|
||
|
|
|
||
|
|
// Pass 1: Edge detection
|
||
|
|
Vector2 viewportScale = sourceTextureHdl.useScaling ? new Vector2(sourceTextureHdl.rtHandleProperties.rtHandleScale.x, sourceTextureHdl.rtHandleProperties.rtHandleScale.y) : Vector2.one;
|
||
|
|
Blitter.BlitTexture(cmd, sourceTextureHdl, viewportScale, SMAAMaterial, ShaderPass.k_EdgeDetection);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
using (var builder = renderGraph.AddRasterRenderPass<SMAAPassData>("SMAA Blend weights", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAABlendWeight)))
|
||
|
|
{
|
||
|
|
builder.SetRenderAttachment(blendTexture, 0, AccessFlags.Write);
|
||
|
|
builder.SetRenderAttachmentDepth(edgeTextureStencil, AccessFlags.Read);
|
||
|
|
passData.sourceTexture = edgeTexture;
|
||
|
|
builder.UseTexture(edgeTexture, AccessFlags.Read);
|
||
|
|
passData.material = m_Material;
|
||
|
|
|
||
|
|
builder.SetRenderFunc(static (SMAAPassData data, RasterGraphContext context) =>
|
||
|
|
{
|
||
|
|
var SMAAMaterial = data.material;
|
||
|
|
var cmd = context.cmd;
|
||
|
|
RTHandle sourceTextureHdl = data.sourceTexture;
|
||
|
|
|
||
|
|
// Pass 2: Blend weights
|
||
|
|
Vector2 viewportScale = sourceTextureHdl.useScaling ? new Vector2(sourceTextureHdl.rtHandleProperties.rtHandleScale.x, sourceTextureHdl.rtHandleProperties.rtHandleScale.y) : Vector2.one;
|
||
|
|
Blitter.BlitTexture(cmd, sourceTextureHdl, viewportScale, SMAAMaterial, ShaderPass.k_BlendWeightsCalculation);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
using (var builder = renderGraph.AddRasterRenderPass<SMAAPassData>("SMAA Neighborhood blending", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAANeighborhoodBlend)))
|
||
|
|
{
|
||
|
|
builder.SetRenderAttachment(destinationTexture, 0, AccessFlags.Write);
|
||
|
|
passData.sourceTexture = sourceTexture;
|
||
|
|
builder.UseTexture(sourceTexture, AccessFlags.Read);
|
||
|
|
passData.blendTexture = blendTexture;
|
||
|
|
builder.UseTexture(blendTexture, AccessFlags.Read);
|
||
|
|
passData.material = m_Material;
|
||
|
|
|
||
|
|
builder.SetRenderFunc(static (SMAAPassData data, RasterGraphContext context) =>
|
||
|
|
{
|
||
|
|
var SMAAMaterial = data.material;
|
||
|
|
var cmd = context.cmd;
|
||
|
|
RTHandle sourceTextureHdl = data.sourceTexture;
|
||
|
|
|
||
|
|
// Pass 3: Neighborhood blending
|
||
|
|
SMAAMaterial.SetTexture(ShaderConstants._BlendTexture, data.blendTexture);
|
||
|
|
Vector2 viewportScale = sourceTextureHdl.useScaling ? new Vector2(sourceTextureHdl.rtHandleProperties.rtHandleScale.x, sourceTextureHdl.rtHandleProperties.rtHandleScale.y) : Vector2.one;
|
||
|
|
Blitter.BlitTexture(cmd, sourceTextureHdl, viewportScale, SMAAMaterial, ShaderPass.k_NeighborhoodBlending);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
resourceData.cameraColor = destinationTexture;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void SetupMaterial(SMAASetupPassData data)
|
||
|
|
{
|
||
|
|
using (new ProfilingScope(ProfilingSampler.Get(URPProfileId.RG_SMAAMaterialSetup)))
|
||
|
|
{
|
||
|
|
// Common for all passes
|
||
|
|
data.material.SetVector(ShaderConstants._Metrics, data.metrics);
|
||
|
|
data.material.SetTexture(ShaderConstants._AreaTexture, data.areaTexture);
|
||
|
|
data.material.SetTexture(ShaderConstants._SearchTexture, data.searchTexture);
|
||
|
|
data.material.SetFloat(ShaderConstants._StencilRef, data.stencilRef);
|
||
|
|
data.material.SetFloat(ShaderConstants._StencilMask, data.stencilMask);
|
||
|
|
|
||
|
|
// Quality presets
|
||
|
|
data.material.shaderKeywords = null;
|
||
|
|
|
||
|
|
switch (data.antialiasingQuality)
|
||
|
|
{
|
||
|
|
case AntialiasingQuality.Low:
|
||
|
|
data.material.EnableKeyword(ShaderKeywordStrings.SmaaLow);
|
||
|
|
break;
|
||
|
|
case AntialiasingQuality.Medium:
|
||
|
|
data.material.EnableKeyword(ShaderKeywordStrings.SmaaMedium);
|
||
|
|
break;
|
||
|
|
case AntialiasingQuality.High:
|
||
|
|
data.material.EnableKeyword(ShaderKeywordStrings.SmaaHigh);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Precomputed shader ids to same some CPU cycles (mostly affects mobile)
|
||
|
|
public static class ShaderConstants
|
||
|
|
{
|
||
|
|
public static readonly int _Metrics = Shader.PropertyToID("_Metrics");
|
||
|
|
public static readonly int _AreaTexture = Shader.PropertyToID("_AreaTexture");
|
||
|
|
public static readonly int _SearchTexture = Shader.PropertyToID("_SearchTexture");
|
||
|
|
public static readonly int _BlendTexture = Shader.PropertyToID("_BlendTexture");
|
||
|
|
//public static readonly int _EdgeTexture = Shader.PropertyToID("_EdgeTexture");
|
||
|
|
|
||
|
|
public static readonly int _StencilRef = Shader.PropertyToID("_StencilRef");
|
||
|
|
public static readonly int _StencilMask = Shader.PropertyToID("_StencilMask");
|
||
|
|
}
|
||
|
|
|
||
|
|
public static class ShaderPass
|
||
|
|
{
|
||
|
|
public const int k_EdgeDetection = 0;
|
||
|
|
public const int k_BlendWeightsCalculation = 1;
|
||
|
|
public const int k_NeighborhoodBlending = 2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|