|
2 | 2 |
|
3 | 3 | namespace UnityEngine.Rendering.PostProcessing |
4 | 4 | { |
| 5 | + public interface IAmbientOcclusionMethod |
| 6 | + { |
| 7 | + DepthTextureMode GetCameraFlags(); |
| 8 | + bool IsSupported(PostProcessRenderContext context); |
| 9 | + void RenderAfterOpaque(PostProcessRenderContext context); |
| 10 | + void RenderAmbientOnly(PostProcessRenderContext context); |
| 11 | + void CompositeAmbientOnly(PostProcessRenderContext context); |
| 12 | + void Release(); |
| 13 | + } |
| 14 | + |
5 | 15 | [Serializable] |
6 | 16 | public sealed class AmbientOcclusion |
7 | 17 | { |
8 | | - // Unity sorts enums by value in the editor (and doesn't handle same-values enums very well |
9 | | - // so we won't use enum values as sample counts this time |
10 | | - public enum Quality |
| 18 | + public enum Mode |
11 | 19 | { |
12 | | - Lowest, |
13 | | - Low, |
14 | | - Medium, |
15 | | - High, |
16 | | - Ultra |
| 20 | + SAO, |
| 21 | + MSVO |
17 | 22 | } |
18 | 23 |
|
19 | 24 | [Tooltip("Enables ambient occlusion.")] |
20 | 25 | public bool enabled = false; |
21 | 26 |
|
22 | | - [Range(0f, 4f), Tooltip("Degree of darkness produced by the effect.")] |
23 | | - public float intensity = 0.5f; |
24 | | - |
25 | | - [Tooltip("Radius of sample points, which affects extent of darkened areas.")] |
26 | | - public float radius = 0.25f; |
27 | | - |
28 | | - [Tooltip("Number of sample points, which affects quality and performance. Lowest, Low & Medium passes are downsampled. High and Ultra are not and should only be used on high-end hardware.")] |
29 | | - public Quality quality = Quality.Medium; |
| 27 | + public Mode mode = Mode.MSVO; |
30 | 28 |
|
31 | 29 | [Tooltip("Only affects ambient lighting. This mode is only available with the Deferred rendering path and HDR rendering. Objects rendered with the Forward rendering path won't get any ambient occlusion.")] |
32 | 30 | public bool ambientOnly = false; |
33 | 31 |
|
34 | | - readonly RenderTargetIdentifier[] m_MRT = |
35 | | - { |
36 | | - BuiltinRenderTextureType.GBuffer0, // Albedo, Occ |
37 | | - BuiltinRenderTextureType.CameraTarget // Ambient |
38 | | - }; |
| 32 | + // Polymorphism doesn't play well with serialization in Unity so we have to keep explicit |
| 33 | + // references... Would be nice to have this more dynamic to allow user-custom AO methods. |
| 34 | + public ScalableAO scalableAO; |
| 35 | + public MultiScaleVO multiScaleVO; |
39 | 36 |
|
40 | | - readonly int[] m_SampleCount = { 4, 6, 10, 8, 12 }; |
| 37 | + IAmbientOcclusionMethod[] m_Methods; |
41 | 38 |
|
42 | | - enum Pass |
| 39 | + public AmbientOcclusion() |
43 | 40 | { |
44 | | - OcclusionEstimationForward, |
45 | | - OcclusionEstimationDeferred, |
46 | | - HorizontalBlurForward, |
47 | | - HorizontalBlurDeferred, |
48 | | - VerticalBlur, |
49 | | - CompositionForward, |
50 | | - CompositionDeferred |
| 41 | + if (scalableAO == null) scalableAO = new ScalableAO(); |
| 42 | + if (multiScaleVO == null) multiScaleVO = new MultiScaleVO(); |
| 43 | + |
| 44 | + m_Methods = new IAmbientOcclusionMethod[] { scalableAO, multiScaleVO }; |
51 | 45 | } |
52 | 46 |
|
53 | | - internal DepthTextureMode GetCameraFlags() |
| 47 | + public bool IsEnabledAndSupported(PostProcessRenderContext context) |
54 | 48 | { |
55 | | - return DepthTextureMode.Depth | DepthTextureMode.DepthNormals; |
| 49 | + return enabled && Get().IsSupported(context); |
56 | 50 | } |
57 | 51 |
|
58 | | - internal bool IsAmbientOnly(PostProcessRenderContext context) |
| 52 | + public bool IsAmbientOnly(PostProcessRenderContext context) |
59 | 53 | { |
60 | 54 | var camera = context.camera; |
61 | 55 | return ambientOnly |
62 | 56 | && camera.actualRenderingPath == RenderingPath.DeferredShading |
63 | 57 | && camera.allowHDR; |
64 | 58 | } |
65 | 59 |
|
66 | | - internal bool IsEnabledAndSupported(PostProcessRenderContext context) |
67 | | - { |
68 | | - return enabled |
69 | | - && intensity > 0f |
70 | | - && !RuntimeUtilities.scriptableRenderPipelineActive; |
71 | | - } |
72 | | - |
73 | | - PropertySheet PreRender(PostProcessRenderContext context, int occlusionSource) |
74 | | - { |
75 | | - radius = Mathf.Max(radius, 1e-4f); |
76 | | - var cmd = context.command; |
77 | | - |
78 | | - // Material setup |
79 | | - // Always use a quater-res AO buffer unless High/Ultra quality is set. |
80 | | - bool downsampling = (int)quality < (int)Quality.High; |
81 | | - float px = intensity; |
82 | | - float py = radius; |
83 | | - float pz = downsampling ? 0.5f : 1f; |
84 | | - float pw = m_SampleCount[(int)quality]; |
85 | | - |
86 | | - var sheet = context.propertySheets.Get(context.resources.shaders.ambientOcclusion); |
87 | | - sheet.ClearKeywords(); |
88 | | - sheet.properties.SetVector(ShaderIDs.AOParams, new Vector4(px, py, pz, pw)); |
89 | | - |
90 | | - // In forward fog is applied at the object level in the grometry pass so we need to |
91 | | - // apply it to AO as well or it'll drawn on top of the fog effect. |
92 | | - // Not needed in Deferred. |
93 | | - if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog) |
94 | | - { |
95 | | - sheet.properties.SetVector(ShaderIDs.FogParams, new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance)); |
96 | | - |
97 | | - switch (RenderSettings.fogMode) |
98 | | - { |
99 | | - case FogMode.Linear: |
100 | | - sheet.EnableKeyword("FOG_LINEAR"); |
101 | | - break; |
102 | | - case FogMode.Exponential: |
103 | | - sheet.EnableKeyword("FOG_EXP"); |
104 | | - break; |
105 | | - case FogMode.ExponentialSquared: |
106 | | - sheet.EnableKeyword("FOG_EXP2"); |
107 | | - break; |
108 | | - } |
109 | | - } |
110 | | - |
111 | | - // Texture setup |
112 | | - int tw = context.width; |
113 | | - int th = context.height; |
114 | | - int ts = downsampling ? 2 : 1; |
115 | | - const RenderTextureFormat kFormat = RenderTextureFormat.ARGB32; |
116 | | - const RenderTextureReadWrite kRWMode = RenderTextureReadWrite.Linear; |
117 | | - const FilterMode kFilter = FilterMode.Bilinear; |
118 | | - |
119 | | - // AO buffer |
120 | | - var rtMask = ShaderIDs.OcclusionTexture1; |
121 | | - cmd.GetTemporaryRT(rtMask, tw / ts, th / ts, 0, kFilter, kFormat, kRWMode); |
122 | | - |
123 | | - // AO estimation |
124 | | - cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, rtMask, sheet, (int)Pass.OcclusionEstimationForward + occlusionSource); |
125 | | - |
126 | | - // Blur buffer |
127 | | - var rtBlur = ShaderIDs.OcclusionTexture2; |
128 | | - |
129 | | - // Separable blur (horizontal pass) |
130 | | - cmd.GetTemporaryRT(rtBlur, tw, th, 0, kFilter, kFormat, kRWMode); |
131 | | - cmd.BlitFullscreenTriangle(rtMask, rtBlur, sheet, (int)Pass.HorizontalBlurForward + occlusionSource); |
132 | | - cmd.ReleaseTemporaryRT(rtMask); |
133 | | - |
134 | | - // Separable blur (vertical pass) |
135 | | - rtMask = ShaderIDs.OcclusionTexture; |
136 | | - cmd.GetTemporaryRT(rtMask, tw, th, 0, kFilter, kFormat, kRWMode); |
137 | | - cmd.BlitFullscreenTriangle(rtBlur, rtMask, sheet, (int)Pass.VerticalBlur); |
138 | | - cmd.ReleaseTemporaryRT(rtBlur); |
139 | | - |
140 | | - return sheet; |
141 | | - } |
142 | | - |
143 | | - internal void RenderAfterOpaque(PostProcessRenderContext context) |
| 60 | + public IAmbientOcclusionMethod Get() |
144 | 61 | { |
145 | | - var cmd = context.command; |
146 | | - cmd.BeginSample("Ambient Occlusion"); |
147 | | - var sheet = PreRender(context, 0); // Forward |
148 | | - cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.CompositionForward); |
149 | | - cmd.EndSample("Ambient Occlusion"); |
| 62 | + return m_Methods[(int)mode]; |
150 | 63 | } |
151 | 64 |
|
152 | | - internal void RenderAmbientOnly(PostProcessRenderContext context) |
| 65 | + public void Release() |
153 | 66 | { |
154 | | - var cmd = context.command; |
155 | | - cmd.BeginSample("Ambient Occlusion"); |
156 | | - var sheet = PreRender(context, 1); // Deferred |
157 | | - cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_MRT, BuiltinRenderTextureType.CameraTarget, sheet, (int)Pass.CompositionDeferred); |
158 | | - cmd.EndSample("Ambient Occlusion"); |
| 67 | + foreach (var m in m_Methods) |
| 68 | + m.Release(); |
159 | 69 | } |
160 | 70 | } |
161 | 71 | } |
0 commit comments