3 namespace UnityEngine
.Rendering
.PostProcessing
5 // Multi-scale volumetric obscurance
6 // TODO: Fix VR support
8 #if UNITY_2017_1_OR_NEWER
9 [UnityEngine
.Scripting
.Preserve
]
11 internal sealed class MultiScaleVO
: IAmbientOcclusionMethod
13 internal enum MipLevel { Original, L1, L2, L3, L4, L5, L6 }
23 // The arrays below are reused between frames to reduce GC allocation.
24 readonly float[] m_SampleThickness
=
26 Mathf
.Sqrt(1f
- 0.2f
* 0.2f
),
27 Mathf
.Sqrt(1f
- 0.4f
* 0.4f
),
28 Mathf
.Sqrt(1f
- 0.6f
* 0.6f
),
29 Mathf
.Sqrt(1f
- 0.8f
* 0.8f
),
30 Mathf
.Sqrt(1f
- 0.2f
* 0.2f
- 0.2f
* 0.2f
),
31 Mathf
.Sqrt(1f
- 0.2f
* 0.2f
- 0.4f
* 0.4f
),
32 Mathf
.Sqrt(1f
- 0.2f
* 0.2f
- 0.6f
* 0.6f
),
33 Mathf
.Sqrt(1f
- 0.2f
* 0.2f
- 0.8f
* 0.8f
),
34 Mathf
.Sqrt(1f
- 0.4f
* 0.4f
- 0.4f
* 0.4f
),
35 Mathf
.Sqrt(1f
- 0.4f
* 0.4f
- 0.6f
* 0.6f
),
36 Mathf
.Sqrt(1f
- 0.4f
* 0.4f
- 0.8f
* 0.8f
),
37 Mathf
.Sqrt(1f
- 0.6f
* 0.6f
- 0.6f
* 0.6f
)
40 readonly float[] m_InvThicknessTable
= new float[12];
41 readonly float[] m_SampleWeightTable
= new float[12];
43 readonly int[] m_Widths
= new int[7];
44 readonly int[] m_Heights
= new int[7];
46 AmbientOcclusion m_Settings
;
47 PropertySheet m_PropertySheet
;
48 PostProcessResources m_Resources
;
50 // Can't use a temporary because we need to share it between cmdbuffers - also fixes a weird
51 // command buffer warning
52 RenderTexture m_AmbientOnlyAO
;
54 readonly RenderTargetIdentifier
[] m_MRT
=
56 BuiltinRenderTextureType
.GBuffer0
, // Albedo, Occ
57 BuiltinRenderTextureType
.CameraTarget
// Ambient
60 public MultiScaleVO(AmbientOcclusion settings
)
62 m_Settings
= settings
;
65 public DepthTextureMode
GetCameraFlags()
67 return DepthTextureMode
.Depth
;
70 // Special case for AO [because SRPs], please don't do this in other effects, it's bad
71 // practice in this framework
72 public void SetResources(PostProcessResources resources
)
74 m_Resources
= resources
;
77 void Alloc(CommandBuffer cmd
, int id
, MipLevel size
, RenderTextureFormat format
, bool uav
)
79 int sizeId
= (int)size
;
80 cmd
.GetTemporaryRT(id
, new RenderTextureDescriptor
82 width
= m_Widths
[sizeId
],
83 height
= m_Heights
[sizeId
],
87 autoGenerateMips
= false,
89 enableRandomWrite
= uav
,
90 dimension
= TextureDimension
.Tex2D
,
95 void AllocArray(CommandBuffer cmd
, int id
, MipLevel size
, RenderTextureFormat format
, bool uav
)
97 int sizeId
= (int)size
;
98 cmd
.GetTemporaryRT(id
, new RenderTextureDescriptor
100 width
= m_Widths
[sizeId
],
101 height
= m_Heights
[sizeId
],
102 colorFormat
= format
,
105 autoGenerateMips
= false,
107 enableRandomWrite
= uav
,
108 dimension
= TextureDimension
.Tex2DArray
,
110 }, FilterMode
.Point
);
113 void Release(CommandBuffer cmd
, int id
)
115 cmd
.ReleaseTemporaryRT(id
);
118 // Calculate values in _ZBuferParams (built-in shader variable)
119 // We can't use _ZBufferParams in compute shaders, so this function is
120 // used to give the values in it to compute shaders.
121 Vector4
CalculateZBufferParams(Camera camera
)
123 float fpn
= camera
.farClipPlane
/ camera
.nearClipPlane
;
125 if (SystemInfo
.usesReversedZBuffer
)
126 return new Vector4(fpn
- 1f
, 1f
, 0f
, 0f
);
128 return new Vector4(1f
- fpn
, fpn
, 0f
, 0f
);
131 float CalculateTanHalfFovHeight(Camera camera
)
133 return 1f
/ camera
.projectionMatrix
[0, 0];
136 Vector2
GetSize(MipLevel mip
)
138 return new Vector2(m_Widths
[(int)mip
], m_Heights
[(int)mip
]);
141 Vector3
GetSizeArray(MipLevel mip
)
143 return new Vector3(m_Widths
[(int)mip
], m_Heights
[(int)mip
], 16);
146 public void GenerateAOMap(CommandBuffer cmd
, Camera camera
, RenderTargetIdentifier destination
, RenderTargetIdentifier
? depthMap
, bool invert
, bool isMSAA
)
149 m_Widths
[0] = camera
.pixelWidth
* (RuntimeUtilities
.isSinglePassStereoEnabled
? 2 : 1);
150 m_Heights
[0] = camera
.pixelHeight
;
153 for (int i
= 1; i
< 7; i
++)
156 m_Widths
[i
] = (m_Widths
[0] + (div
- 1)) / div
;
157 m_Heights
[i
] = (m_Heights
[0] + (div
- 1)) / div
;
160 // Allocate temporary textures
161 PushAllocCommands(cmd
, isMSAA
);
164 PushDownsampleCommands(cmd
, camera
, depthMap
, isMSAA
);
166 float tanHalfFovH
= CalculateTanHalfFovHeight(camera
);
167 PushRenderCommands(cmd
, ShaderIDs
.TiledDepth1
, ShaderIDs
.Occlusion1
, GetSizeArray(MipLevel
.L3
), tanHalfFovH
, isMSAA
);
168 PushRenderCommands(cmd
, ShaderIDs
.TiledDepth2
, ShaderIDs
.Occlusion2
, GetSizeArray(MipLevel
.L4
), tanHalfFovH
, isMSAA
);
169 PushRenderCommands(cmd
, ShaderIDs
.TiledDepth3
, ShaderIDs
.Occlusion3
, GetSizeArray(MipLevel
.L5
), tanHalfFovH
, isMSAA
);
170 PushRenderCommands(cmd
, ShaderIDs
.TiledDepth4
, ShaderIDs
.Occlusion4
, GetSizeArray(MipLevel
.L6
), tanHalfFovH
, isMSAA
);
172 PushUpsampleCommands(cmd
, ShaderIDs
.LowDepth4
, ShaderIDs
.Occlusion4
, ShaderIDs
.LowDepth3
, ShaderIDs
.Occlusion3
, ShaderIDs
.Combined3
, GetSize(MipLevel
.L4
), GetSize(MipLevel
.L3
), isMSAA
);
173 PushUpsampleCommands(cmd
, ShaderIDs
.LowDepth3
, ShaderIDs
.Combined3
, ShaderIDs
.LowDepth2
, ShaderIDs
.Occlusion2
, ShaderIDs
.Combined2
, GetSize(MipLevel
.L3
), GetSize(MipLevel
.L2
), isMSAA
);
174 PushUpsampleCommands(cmd
, ShaderIDs
.LowDepth2
, ShaderIDs
.Combined2
, ShaderIDs
.LowDepth1
, ShaderIDs
.Occlusion1
, ShaderIDs
.Combined1
, GetSize(MipLevel
.L2
), GetSize(MipLevel
.L1
), isMSAA
);
175 PushUpsampleCommands(cmd
, ShaderIDs
.LowDepth1
, ShaderIDs
.Combined1
, ShaderIDs
.LinearDepth
, null, destination
, GetSize(MipLevel
.L1
), GetSize(MipLevel
.Original
), isMSAA
, invert
);
178 PushReleaseCommands(cmd
);
181 void PushAllocCommands(CommandBuffer cmd
, bool isMSAA
)
185 Alloc(cmd
, ShaderIDs
.LinearDepth
, MipLevel
.Original
, RenderTextureFormat
.RGHalf
, true);
187 Alloc(cmd
, ShaderIDs
.LowDepth1
, MipLevel
.L1
, RenderTextureFormat
.RGFloat
, true);
188 Alloc(cmd
, ShaderIDs
.LowDepth2
, MipLevel
.L2
, RenderTextureFormat
.RGFloat
, true);
189 Alloc(cmd
, ShaderIDs
.LowDepth3
, MipLevel
.L3
, RenderTextureFormat
.RGFloat
, true);
190 Alloc(cmd
, ShaderIDs
.LowDepth4
, MipLevel
.L4
, RenderTextureFormat
.RGFloat
, true);
192 AllocArray(cmd
, ShaderIDs
.TiledDepth1
, MipLevel
.L3
, RenderTextureFormat
.RGHalf
, true);
193 AllocArray(cmd
, ShaderIDs
.TiledDepth2
, MipLevel
.L4
, RenderTextureFormat
.RGHalf
, true);
194 AllocArray(cmd
, ShaderIDs
.TiledDepth3
, MipLevel
.L5
, RenderTextureFormat
.RGHalf
, true);
195 AllocArray(cmd
, ShaderIDs
.TiledDepth4
, MipLevel
.L6
, RenderTextureFormat
.RGHalf
, true);
197 Alloc(cmd
, ShaderIDs
.Occlusion1
, MipLevel
.L1
, RenderTextureFormat
.RG16
, true);
198 Alloc(cmd
, ShaderIDs
.Occlusion2
, MipLevel
.L2
, RenderTextureFormat
.RG16
, true);
199 Alloc(cmd
, ShaderIDs
.Occlusion3
, MipLevel
.L3
, RenderTextureFormat
.RG16
, true);
200 Alloc(cmd
, ShaderIDs
.Occlusion4
, MipLevel
.L4
, RenderTextureFormat
.RG16
, true);
202 Alloc(cmd
, ShaderIDs
.Combined1
, MipLevel
.L1
, RenderTextureFormat
.RG16
, true);
203 Alloc(cmd
, ShaderIDs
.Combined2
, MipLevel
.L2
, RenderTextureFormat
.RG16
, true);
204 Alloc(cmd
, ShaderIDs
.Combined3
, MipLevel
.L3
, RenderTextureFormat
.RG16
, true);
208 Alloc(cmd
, ShaderIDs
.LinearDepth
, MipLevel
.Original
, RenderTextureFormat
.RHalf
, true);
210 Alloc(cmd
, ShaderIDs
.LowDepth1
, MipLevel
.L1
, RenderTextureFormat
.RFloat
, true);
211 Alloc(cmd
, ShaderIDs
.LowDepth2
, MipLevel
.L2
, RenderTextureFormat
.RFloat
, true);
212 Alloc(cmd
, ShaderIDs
.LowDepth3
, MipLevel
.L3
, RenderTextureFormat
.RFloat
, true);
213 Alloc(cmd
, ShaderIDs
.LowDepth4
, MipLevel
.L4
, RenderTextureFormat
.RFloat
, true);
215 AllocArray(cmd
, ShaderIDs
.TiledDepth1
, MipLevel
.L3
, RenderTextureFormat
.RHalf
, true);
216 AllocArray(cmd
, ShaderIDs
.TiledDepth2
, MipLevel
.L4
, RenderTextureFormat
.RHalf
, true);
217 AllocArray(cmd
, ShaderIDs
.TiledDepth3
, MipLevel
.L5
, RenderTextureFormat
.RHalf
, true);
218 AllocArray(cmd
, ShaderIDs
.TiledDepth4
, MipLevel
.L6
, RenderTextureFormat
.RHalf
, true);
220 Alloc(cmd
, ShaderIDs
.Occlusion1
, MipLevel
.L1
, RenderTextureFormat
.R8
, true);
221 Alloc(cmd
, ShaderIDs
.Occlusion2
, MipLevel
.L2
, RenderTextureFormat
.R8
, true);
222 Alloc(cmd
, ShaderIDs
.Occlusion3
, MipLevel
.L3
, RenderTextureFormat
.R8
, true);
223 Alloc(cmd
, ShaderIDs
.Occlusion4
, MipLevel
.L4
, RenderTextureFormat
.R8
, true);
225 Alloc(cmd
, ShaderIDs
.Combined1
, MipLevel
.L1
, RenderTextureFormat
.R8
, true);
226 Alloc(cmd
, ShaderIDs
.Combined2
, MipLevel
.L2
, RenderTextureFormat
.R8
, true);
227 Alloc(cmd
, ShaderIDs
.Combined3
, MipLevel
.L3
, RenderTextureFormat
.R8
, true);
231 void PushDownsampleCommands(CommandBuffer cmd
, Camera camera
, RenderTargetIdentifier
? depthMap
, bool isMSAA
)
233 RenderTargetIdentifier depthMapId
;
234 bool needDepthMapRelease
= false;
236 if (depthMap
!= null)
238 depthMapId
= depthMap
.Value
;
242 // Make a copy of the depth texture, or reuse the resolved depth
243 // buffer (it's only available in some specific situations).
244 if (!RuntimeUtilities
.IsResolvedDepthAvailable(camera
))
246 Alloc(cmd
, ShaderIDs
.DepthCopy
, MipLevel
.Original
, RenderTextureFormat
.RFloat
, false);
247 depthMapId
= new RenderTargetIdentifier(ShaderIDs
.DepthCopy
);
248 cmd
.BlitFullscreenTriangle(BuiltinRenderTextureType
.None
, depthMapId
, m_PropertySheet
, (int)Pass
.DepthCopy
);
249 needDepthMapRelease
= true;
253 depthMapId
= BuiltinRenderTextureType
.ResolvedDepth
;
257 // 1st downsampling pass.
258 var cs
= m_Resources
.computeShaders
.multiScaleAODownsample1
;
259 int kernel
= cs
.FindKernel(isMSAA
? "MultiScaleVODownsample1_MSAA" : "MultiScaleVODownsample1");
261 cmd
.SetComputeTextureParam(cs
, kernel
, "LinearZ", ShaderIDs
.LinearDepth
);
262 cmd
.SetComputeTextureParam(cs
, kernel
, "DS2x", ShaderIDs
.LowDepth1
);
263 cmd
.SetComputeTextureParam(cs
, kernel
, "DS4x", ShaderIDs
.LowDepth2
);
264 cmd
.SetComputeTextureParam(cs
, kernel
, "DS2xAtlas", ShaderIDs
.TiledDepth1
);
265 cmd
.SetComputeTextureParam(cs
, kernel
, "DS4xAtlas", ShaderIDs
.TiledDepth2
);
266 cmd
.SetComputeVectorParam(cs
, "ZBufferParams", CalculateZBufferParams(camera
));
267 cmd
.SetComputeTextureParam(cs
, kernel
, "Depth", depthMapId
);
269 cmd
.DispatchCompute(cs
, kernel
, m_Widths
[(int)MipLevel
.L4
], m_Heights
[(int)MipLevel
.L4
], 1);
271 if (needDepthMapRelease
)
272 Release(cmd
, ShaderIDs
.DepthCopy
);
274 // 2nd downsampling pass.
275 cs
= m_Resources
.computeShaders
.multiScaleAODownsample2
;
276 kernel
= isMSAA
? cs
.FindKernel("MultiScaleVODownsample2_MSAA") : cs
.FindKernel("MultiScaleVODownsample2");
278 cmd
.SetComputeTextureParam(cs
, kernel
, "DS4x", ShaderIDs
.LowDepth2
);
279 cmd
.SetComputeTextureParam(cs
, kernel
, "DS8x", ShaderIDs
.LowDepth3
);
280 cmd
.SetComputeTextureParam(cs
, kernel
, "DS16x", ShaderIDs
.LowDepth4
);
281 cmd
.SetComputeTextureParam(cs
, kernel
, "DS8xAtlas", ShaderIDs
.TiledDepth3
);
282 cmd
.SetComputeTextureParam(cs
, kernel
, "DS16xAtlas", ShaderIDs
.TiledDepth4
);
284 cmd
.DispatchCompute(cs
, kernel
, m_Widths
[(int)MipLevel
.L6
], m_Heights
[(int)MipLevel
.L6
], 1);
287 void PushRenderCommands(CommandBuffer cmd
, int source
, int destination
, Vector3 sourceSize
, float tanHalfFovH
, bool isMSAA
)
289 // Here we compute multipliers that convert the center depth value into (the reciprocal
290 // of) sphere thicknesses at each sample location. This assumes a maximum sample radius
291 // of 5 units, but since a sphere has no thickness at its extent, we don't need to
292 // sample that far out. Only samples whole integer offsets with distance less than 25
293 // are used. This means that there is no sample at (3, 4) because its distance is
294 // exactly 25 (and has a thickness of 0.)
296 // The shaders are set up to sample a circular region within a 5-pixel radius.
297 const float kScreenspaceDiameter
= 10f
;
299 // SphereDiameter = CenterDepth * ThicknessMultiplier. This will compute the thickness
300 // of a sphere centered at a specific depth. The ellipsoid scale can stretch a sphere
301 // into an ellipsoid, which changes the characteristics of the AO.
302 // TanHalfFovH: Radius of sphere in depth units if its center lies at Z = 1
303 // ScreenspaceDiameter: Diameter of sample sphere in pixel units
304 // ScreenspaceDiameter / BufferWidth: Ratio of the screen width that the sphere actually covers
305 float thicknessMultiplier
= 2f
* tanHalfFovH
* kScreenspaceDiameter
/ sourceSize
.x
;
306 if (RuntimeUtilities
.isSinglePassStereoEnabled
)
307 thicknessMultiplier
*= 2f
;
309 // This will transform a depth value from [0, thickness] to [0, 1].
310 float inverseRangeFactor
= 1f
/ thicknessMultiplier
;
312 // The thicknesses are smaller for all off-center samples of the sphere. Compute
313 // thicknesses relative to the center sample.
314 for (int i
= 0; i
< 12; i
++)
315 m_InvThicknessTable
[i
] = inverseRangeFactor
/ m_SampleThickness
[i
];
317 // These are the weights that are multiplied against the samples because not all samples
318 // are equally important. The farther the sample is from the center location, the less
319 // they matter. We use the thickness of the sphere to determine the weight. The scalars
320 // in front are the number of samples with this weight because we sum the samples
321 // together before multiplying by the weight, so as an aggregate all of those samples
322 // matter more. After generating this table, the weights are normalized.
323 m_SampleWeightTable
[ 0] = 4 * m_SampleThickness
[ 0]; // Axial
324 m_SampleWeightTable
[ 1] = 4 * m_SampleThickness
[ 1]; // Axial
325 m_SampleWeightTable
[ 2] = 4 * m_SampleThickness
[ 2]; // Axial
326 m_SampleWeightTable
[ 3] = 4 * m_SampleThickness
[ 3]; // Axial
327 m_SampleWeightTable
[ 4] = 4 * m_SampleThickness
[ 4]; // Diagonal
328 m_SampleWeightTable
[ 5] = 8 * m_SampleThickness
[ 5]; // L-shaped
329 m_SampleWeightTable
[ 6] = 8 * m_SampleThickness
[ 6]; // L-shaped
330 m_SampleWeightTable
[ 7] = 8 * m_SampleThickness
[ 7]; // L-shaped
331 m_SampleWeightTable
[ 8] = 4 * m_SampleThickness
[ 8]; // Diagonal
332 m_SampleWeightTable
[ 9] = 8 * m_SampleThickness
[ 9]; // L-shaped
333 m_SampleWeightTable
[10] = 8 * m_SampleThickness
[10]; // L-shaped
334 m_SampleWeightTable
[11] = 4 * m_SampleThickness
[11]; // Diagonal
336 // Zero out the unused samples.
337 // FIXME: should we support SAMPLE_EXHAUSTIVELY mode?
338 m_SampleWeightTable
[0] = 0;
339 m_SampleWeightTable
[2] = 0;
340 m_SampleWeightTable
[5] = 0;
341 m_SampleWeightTable
[7] = 0;
342 m_SampleWeightTable
[9] = 0;
344 // Normalize the weights by dividing by the sum of all weights
345 var totalWeight
= 0f
;
347 foreach (float w
in m_SampleWeightTable
)
350 for (int i
= 0; i
< m_SampleWeightTable
.Length
; i
++)
351 m_SampleWeightTable
[i
] /= totalWeight
;
353 // Set the arguments for the render kernel.
354 var cs
= m_Resources
.computeShaders
.multiScaleAORender
;
355 int kernel
= isMSAA
? cs
.FindKernel("MultiScaleVORender_MSAA_interleaved") : cs
.FindKernel("MultiScaleVORender_interleaved");
357 cmd
.SetComputeFloatParams(cs
, "gInvThicknessTable", m_InvThicknessTable
);
358 cmd
.SetComputeFloatParams(cs
, "gSampleWeightTable", m_SampleWeightTable
);
359 cmd
.SetComputeVectorParam(cs
, "gInvSliceDimension", new Vector2(1f
/ sourceSize
.x
, 1f
/ sourceSize
.y
));
360 cmd
.SetComputeVectorParam(cs
, "AdditionalParams", new Vector2(-1f
/ m_Settings
.thicknessModifier
.value, m_Settings
.intensity
.value));
361 cmd
.SetComputeTextureParam(cs
, kernel
, "DepthTex", source
);
362 cmd
.SetComputeTextureParam(cs
, kernel
, "Occlusion", destination
);
364 // Calculate the thread group count and add a dispatch command with them.
365 uint xsize
, ysize
, zsize
;
366 cs
.GetKernelThreadGroupSizes(kernel
, out xsize
, out ysize
, out zsize
);
370 ((int)sourceSize
.x
+ (int)xsize
- 1) / (int)xsize
,
371 ((int)sourceSize
.y
+ (int)ysize
- 1) / (int)ysize
,
372 ((int)sourceSize
.z
+ (int)zsize
- 1) / (int)zsize
376 void PushUpsampleCommands(CommandBuffer cmd
, int lowResDepth
, int interleavedAO
, int highResDepth
, int? highResAO
, RenderTargetIdentifier dest
, Vector3 lowResDepthSize
, Vector2 highResDepthSize
, bool isMSAA
, bool invert
= false)
378 var cs
= m_Resources
.computeShaders
.multiScaleAOUpsample
;
382 kernel
= cs
.FindKernel(highResAO
== null ? invert
383 ? "MultiScaleVOUpSample_invert"
384 : "MultiScaleVOUpSample"
385 : "MultiScaleVOUpSample_blendout");
389 kernel
= cs
.FindKernel(highResAO
== null ? invert
390 ? "MultiScaleVOUpSample_MSAA_invert"
391 : "MultiScaleVOUpSample_MSAA"
392 : "MultiScaleVOUpSample_MSAA_blendout");
396 float stepSize
= 1920f
/ lowResDepthSize
.x
;
397 float bTolerance
= 1f
- Mathf
.Pow(10f
, m_Settings
.blurTolerance
.value) * stepSize
;
398 bTolerance
*= bTolerance
;
399 float uTolerance
= Mathf
.Pow(10f
, m_Settings
.upsampleTolerance
.value);
400 float noiseFilterWeight
= 1f
/ (Mathf
.Pow(10f
, m_Settings
.noiseFilterTolerance
.value) + uTolerance
);
402 cmd
.SetComputeVectorParam(cs
, "InvLowResolution", new Vector2(1f
/ lowResDepthSize
.x
, 1f
/ lowResDepthSize
.y
));
403 cmd
.SetComputeVectorParam(cs
, "InvHighResolution", new Vector2(1f
/ highResDepthSize
.x
, 1f
/ highResDepthSize
.y
));
404 cmd
.SetComputeVectorParam(cs
, "AdditionalParams", new Vector4(noiseFilterWeight
, stepSize
, bTolerance
, uTolerance
));
406 cmd
.SetComputeTextureParam(cs
, kernel
, "LoResDB", lowResDepth
);
407 cmd
.SetComputeTextureParam(cs
, kernel
, "HiResDB", highResDepth
);
408 cmd
.SetComputeTextureParam(cs
, kernel
, "LoResAO1", interleavedAO
);
410 if (highResAO
!= null)
411 cmd
.SetComputeTextureParam(cs
, kernel
, "HiResAO", highResAO
.Value
);
413 cmd
.SetComputeTextureParam(cs
, kernel
, "AoResult", dest
);
415 int xcount
= ((int)highResDepthSize
.x
+ 17) / 16;
416 int ycount
= ((int)highResDepthSize
.y
+ 17) / 16;
417 cmd
.DispatchCompute(cs
, kernel
, xcount
, ycount
, 1);
420 void PushReleaseCommands(CommandBuffer cmd
)
422 Release(cmd
, ShaderIDs
.LinearDepth
);
424 Release(cmd
, ShaderIDs
.LowDepth1
);
425 Release(cmd
, ShaderIDs
.LowDepth2
);
426 Release(cmd
, ShaderIDs
.LowDepth3
);
427 Release(cmd
, ShaderIDs
.LowDepth4
);
429 Release(cmd
, ShaderIDs
.TiledDepth1
);
430 Release(cmd
, ShaderIDs
.TiledDepth2
);
431 Release(cmd
, ShaderIDs
.TiledDepth3
);
432 Release(cmd
, ShaderIDs
.TiledDepth4
);
434 Release(cmd
, ShaderIDs
.Occlusion1
);
435 Release(cmd
, ShaderIDs
.Occlusion2
);
436 Release(cmd
, ShaderIDs
.Occlusion3
);
437 Release(cmd
, ShaderIDs
.Occlusion4
);
439 Release(cmd
, ShaderIDs
.Combined1
);
440 Release(cmd
, ShaderIDs
.Combined2
);
441 Release(cmd
, ShaderIDs
.Combined3
);
444 void PreparePropertySheet(PostProcessRenderContext context
)
446 var sheet
= context
.propertySheets
.Get(m_Resources
.shaders
.multiScaleAO
);
447 sheet
.ClearKeywords();
448 sheet
.properties
.SetVector(ShaderIDs
.AOColor
, Color
.white
- m_Settings
.color
.value);
449 m_PropertySheet
= sheet
;
452 void CheckAOTexture(PostProcessRenderContext context
)
454 if (m_AmbientOnlyAO
== null || !m_AmbientOnlyAO
.IsCreated() || m_AmbientOnlyAO
.width
!= context
.width
|| m_AmbientOnlyAO
.height
!= context
.height
)
456 RuntimeUtilities
.Destroy(m_AmbientOnlyAO
);
458 m_AmbientOnlyAO
= new RenderTexture(context
.width
, context
.height
, 0, RenderTextureFormat
.R8
, RenderTextureReadWrite
.Linear
)
460 hideFlags
= HideFlags
.DontSave
,
461 filterMode
= FilterMode
.Point
,
462 enableRandomWrite
= true
464 m_AmbientOnlyAO
.Create();
468 void PushDebug(PostProcessRenderContext context
)
470 if (context
.IsDebugOverlayEnabled(DebugOverlay
.AmbientOcclusion
))
471 context
.PushDebugOverlay(context
.command
, m_AmbientOnlyAO
, m_PropertySheet
, (int)Pass
.DebugOverlay
);
474 public void RenderAfterOpaque(PostProcessRenderContext context
)
476 var cmd
= context
.command
;
477 cmd
.BeginSample("Ambient Occlusion");
478 SetResources(context
.resources
);
479 PreparePropertySheet(context
);
480 CheckAOTexture(context
);
482 // In Forward mode, fog is applied at the object level in the grometry pass so we need
483 // to apply it to AO as well or it'll drawn on top of the fog effect.
484 if (context
.camera
.actualRenderingPath
== RenderingPath
.Forward
&& RenderSettings
.fog
)
486 m_PropertySheet
.EnableKeyword("APPLY_FORWARD_FOG");
487 m_PropertySheet
.properties
.SetVector(
489 new Vector3(RenderSettings
.fogDensity
, RenderSettings
.fogStartDistance
, RenderSettings
.fogEndDistance
)
493 GenerateAOMap(cmd
, context
.camera
, m_AmbientOnlyAO
, null, false, false);
495 cmd
.SetGlobalTexture(ShaderIDs
.MSVOcclusionTexture
, m_AmbientOnlyAO
);
496 cmd
.BlitFullscreenTriangle(BuiltinRenderTextureType
.None
, BuiltinRenderTextureType
.CameraTarget
, m_PropertySheet
, (int)Pass
.CompositionForward
, RenderBufferLoadAction
.Load
);
497 cmd
.EndSample("Ambient Occlusion");
500 public void RenderAmbientOnly(PostProcessRenderContext context
)
502 var cmd
= context
.command
;
503 cmd
.BeginSample("Ambient Occlusion Render");
504 SetResources(context
.resources
);
505 PreparePropertySheet(context
);
506 CheckAOTexture(context
);
507 GenerateAOMap(cmd
, context
.camera
, m_AmbientOnlyAO
, null, false, false);
509 cmd
.EndSample("Ambient Occlusion Render");
512 public void CompositeAmbientOnly(PostProcessRenderContext context
)
514 var cmd
= context
.command
;
515 cmd
.BeginSample("Ambient Occlusion Composite");
516 cmd
.SetGlobalTexture(ShaderIDs
.MSVOcclusionTexture
, m_AmbientOnlyAO
);
517 cmd
.BlitFullscreenTriangle(BuiltinRenderTextureType
.None
, m_MRT
, BuiltinRenderTextureType
.CameraTarget
, m_PropertySheet
, (int)Pass
.CompositionDeferred
);
518 cmd
.EndSample("Ambient Occlusion Composite");
521 public void Release()
523 RuntimeUtilities
.Destroy(m_AmbientOnlyAO
);
524 m_AmbientOnlyAO
= null;
529 public sealed class MultiScaleVO
: IAmbientOcclusionMethod
531 public MultiScaleVO(AmbientOcclusion settings
)
535 public void SetResources(PostProcessResources resources
)
539 public DepthTextureMode
GetCameraFlags()
541 return DepthTextureMode
.None
;
544 public void GenerateAOMap(CommandBuffer cmd
, Camera camera
, RenderTargetIdentifier destination
, RenderTargetIdentifier
? depthMap
, bool invert
, bool isMSAA
)
548 public void RenderAfterOpaque(PostProcessRenderContext context
)
552 public void RenderAmbientOnly(PostProcessRenderContext context
)
556 public void CompositeAmbientOnly(PostProcessRenderContext context
)
560 public void Release()