-
Notifications
You must be signed in to change notification settings - Fork 136
/
SlightBlur.cs
189 lines (166 loc) · 8.41 KB
/
SlightBlur.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Profiling;
class SlightBlur : CustomPass
{
[Range(0, 16)]
public float radius = 4;
public bool useMask = false;
public LayerMask maskLayer = 0;
public bool invertMask = false;
Material compositeMaterial;
Material whiteRenderersMaterial;
RTHandle downSampleBuffer;
RTHandle blurBuffer;
RTHandle maskBuffer;
RTHandle maskDepthBuffer;
RTHandle colorCopy;
ShaderTagId[] shaderTags;
// Trick to always include these shaders in build
[SerializeField, HideInInspector]
Shader compositeShader;
[SerializeField, HideInInspector]
Shader whiteRenderersShader;
static class ShaderID
{
public static readonly int _BlitTexture = Shader.PropertyToID("_BlitTexture");
public static readonly int _BlitScaleBias = Shader.PropertyToID("_BlitScaleBias");
public static readonly int _BlitMipLevel = Shader.PropertyToID("_BlitMipLevel");
public static readonly int _Radius = Shader.PropertyToID("_Radius");
public static readonly int _Source = Shader.PropertyToID("_Source");
public static readonly int _ColorBufferCopy = Shader.PropertyToID("_ColorBufferCopy");
public static readonly int _Mask = Shader.PropertyToID("_Mask");
public static readonly int _MaskDepth = Shader.PropertyToID("_MaskDepth");
public static readonly int _InvertMask = Shader.PropertyToID("_InvertMask");
public static readonly int _ViewPortSize = Shader.PropertyToID("_ViewPortSize");
}
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in an performance manner.
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
if (compositeShader == null)
compositeShader = Resources.Load<Shader>("CompositeBlur");
if (whiteRenderersShader == null)
whiteRenderersShader = Shader.Find("Hidden/Renderers/WhiteRenderers");
compositeMaterial = CoreUtils.CreateEngineMaterial(compositeShader);
whiteRenderersMaterial = CoreUtils.CreateEngineMaterial(whiteRenderersShader);
// Allocate the buffers used for the blur in half resolution to save some memory
downSampleBuffer = RTHandles.Alloc(
Vector2.one * 0.5f, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: GraphicsFormat.B10G11R11_UFloatPack32, // We don't need alpha in the blur
useDynamicScale: true, name: "DownSampleBuffer"
);
blurBuffer = RTHandles.Alloc(
Vector2.one * 0.5f, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: GraphicsFormat.B10G11R11_UFloatPack32, // We don't need alpha in the blur
useDynamicScale: true, name: "BlurBuffer"
);
shaderTags = new ShaderTagId[4]
{
new ShaderTagId("Forward"),
new ShaderTagId("ForwardOnly"),
new ShaderTagId("SRPDefaultUnlit"),
new ShaderTagId("FirstPass"),
};
}
void AllocateMaskBuffersIfNeeded()
{
if (useMask)
{
if (colorCopy?.rt == null || !colorCopy.rt.IsCreated())
{
var hdrpAsset = (GraphicsSettings.renderPipelineAsset as HDRenderPipelineAsset);
var colorBufferFormat = hdrpAsset.currentPlatformRenderPipelineSettings.colorBufferFormat;
colorCopy = RTHandles.Alloc(
Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: (GraphicsFormat)colorBufferFormat,
useDynamicScale: true, name: "Color Copy"
);
}
if (maskBuffer?.rt == null || !maskBuffer.rt.IsCreated())
{
maskBuffer = RTHandles.Alloc(
Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: GraphicsFormat.R8_UNorm, // We only need a 1 channel mask to composite the blur and color buffer copy
useDynamicScale: true, name: "Blur Mask"
);
}
if (maskDepthBuffer?.rt == null || !maskDepthBuffer.rt.IsCreated())
{
maskDepthBuffer = RTHandles.Alloc(
Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: GraphicsFormat.R16_UInt, useDynamicScale: true,
name: "Blur Depth Mask", depthBufferBits: DepthBits.Depth16
);
}
}
}
protected override void Execute(CustomPassContext ctx)
{
AllocateMaskBuffersIfNeeded();
if (compositeMaterial != null && radius > 0)
{
if (useMask)
{
CoreUtils.SetRenderTarget(ctx.cmd, maskBuffer, maskDepthBuffer, ClearFlag.All);
CustomPassUtils.DrawRenderers(ctx, maskLayer, overrideRenderState: new RenderStateBlock(RenderStateMask.Depth){ depthState = new DepthState(true, CompareFunction.LessEqual)});
// DrawMaskObjects(renderContext, cmd, hdCamera, cullingResult);
}
GenerateGaussianMips(ctx);
}
}
protected override void AggregateCullingParameters(ref ScriptableCullingParameters cullingParameters, HDCamera hdCamera)
=> cullingParameters.cullingMask |= (uint)maskLayer.value;
// We need the viewport size in our shader because we're using half resolution render targets (and so the _ScreenSize
// variable in the shader does not match the viewport).
void SetViewPortSize(CommandBuffer cmd, MaterialPropertyBlock block, RTHandle target)
{
Vector2Int scaledViewportSize = target.GetScaledSize(target.rtHandleProperties.currentViewportSize);
block.SetVector(ShaderID._ViewPortSize, new Vector4(scaledViewportSize.x, scaledViewportSize.y, 1.0f / (float)scaledViewportSize.x, 1.0f / (float)scaledViewportSize.y));
}
void GenerateGaussianMips(CustomPassContext ctx)
{
RTHandle source = (targetColorBuffer == TargetBuffer.Camera) ? ctx.cameraColorBuffer : ctx.customColorBuffer.Value;
// Save the non blurred color into a copy if the mask is enabled:
if (useMask)
{
for (int i = 0; i < source.rt.volumeDepth; i++)
{
ctx.cmd.CopyTexture(source, i, colorCopy, i);
}
}
var targetBuffer = (useMask) ? downSampleBuffer : source;
CustomPassUtils.GaussianBlur(ctx, source, targetBuffer, blurBuffer, radius: radius);
if (useMask)
{
// Merge the non blur copy and the blurred version using the mask buffers
using (new ProfilingScope(ctx.cmd, new ProfilingSampler("Compose Mask Blur")))
{
var compositingProperties = new MaterialPropertyBlock();
compositingProperties.SetFloat(ShaderID._Radius, radius / 4f); // The blur is 4 pixel wide in the shader
compositingProperties.SetTexture(ShaderID._Source, downSampleBuffer);
compositingProperties.SetTexture(ShaderID._ColorBufferCopy, colorCopy);
compositingProperties.SetTexture(ShaderID._Mask, maskBuffer);
compositingProperties.SetTexture(ShaderID._MaskDepth, maskDepthBuffer);
compositingProperties.SetFloat(ShaderID._InvertMask, invertMask ? 1 : 0);
SetViewPortSize(ctx.cmd, compositingProperties, source);
HDUtils.DrawFullScreen(ctx.cmd, compositeMaterial, source, compositingProperties, shaderPassId: 0); // Do not forget the shaderPassId! otherwise it won't work
}
}
}
// release all resources
protected override void Cleanup()
{
CoreUtils.Destroy(compositeMaterial);
CoreUtils.Destroy(whiteRenderersMaterial);
downSampleBuffer.Release();
blurBuffer.Release();
maskDepthBuffer?.Release();
maskBuffer?.Release();
colorCopy?.Release();
}
}