post processing
[WindSway-HDRP.git] / Library / PackageCache / com.unity.postprocessing@2.1.6 / PostProcessing / Runtime / Effects / Bloom.cs
blob49879a8b975e9c655862c891557e923ab29d56c7
1 using System;
2 using UnityEngine.Serialization;
4 namespace UnityEngine.Rendering.PostProcessing
6 // For now and by popular request, this bloom effect is geared toward artists so they have full
7 // control over how it looks at the expense of physical correctness.
8 // Eventually we will need a "true" natural bloom effect with proper energy conservation.
10 /// <summary>
11 /// This class holds settings for the Bloom effect.
12 /// </summary>
13 [Serializable]
14 [PostProcess(typeof(BloomRenderer), "Unity/Bloom")]
15 public sealed class Bloom : PostProcessEffectSettings
17 /// <summary>
18 /// The strength of the bloom filter.
19 /// </summary>
20 [Min(0f), Tooltip("Strength of the bloom filter. Values higher than 1 will make bloom contribute more energy to the final render.")]
21 public FloatParameter intensity = new FloatParameter { value = 0f };
23 /// <summary>
24 /// Filters out pixels under this level of brightness. This value is expressed in
25 /// gamma-space.
26 /// </summary>
27 [Min(0f), Tooltip("Filters out pixels under this level of brightness. Value is in gamma-space.")]
28 public FloatParameter threshold = new FloatParameter { value = 1f };
30 /// <summary>
31 /// Makes transition between under/over-threshold gradual (0 = hard threshold, 1 = soft
32 /// threshold).
33 /// </summary>
34 [Range(0f, 1f), Tooltip("Makes transitions between under/over-threshold gradual. 0 for a hard threshold, 1 for a soft threshold).")]
35 public FloatParameter softKnee = new FloatParameter { value = 0.5f };
37 /// <summary>
38 /// Clamps pixels to control the bloom amount. This value is expressed in gamma-space.
39 /// </summary>
40 [Tooltip("Clamps pixels to control the bloom amount. Value is in gamma-space.")]
41 public FloatParameter clamp = new FloatParameter { value = 65472f };
43 /// <summary>
44 /// Changes extent of veiling effects in a screen resolution-independent fashion. For
45 /// maximum quality stick to integer values. Because this value changes the internal
46 /// iteration count, animating it isn't recommended as it may introduce small hiccups in
47 /// the perceived radius.
48 /// </summary>
49 [Range(1f, 10f), Tooltip("Changes the extent of veiling effects. For maximum quality, use integer values. Because this value changes the internal iteration count, You should not animating it as it may introduce issues with the perceived radius.")]
50 public FloatParameter diffusion = new FloatParameter { value = 7f };
52 /// <summary>
53 /// Distorts the bloom to give an anamorphic look. Negative values distort vertically,
54 /// positive values distort horizontally.
55 /// </summary>
56 [Range(-1f, 1f), Tooltip("Distorts the bloom to give an anamorphic look. Negative values distort vertically, positive values distort horizontally.")]
57 public FloatParameter anamorphicRatio = new FloatParameter { value = 0f };
59 /// <summary>
60 /// The tint of the Bloom filter.
61 /// </summary>
62 #if UNITY_2018_1_OR_NEWER
63 [ColorUsage(false, true), Tooltip("Global tint of the bloom filter.")]
64 #else
65 [ColorUsage(false, true, 0f, 8f, 0.125f, 3f), Tooltip("Global tint of the bloom filter.")]
66 #endif
67 public ColorParameter color = new ColorParameter { value = Color.white };
69 /// <summary>
70 /// Boost performances by lowering the effect quality.
71 /// </summary>
72 [FormerlySerializedAs("mobileOptimized")]
73 [Tooltip("Boost performance by lowering the effect quality. This settings is meant to be used on mobile and other low-end platforms but can also provide a nice performance boost on desktops and consoles.")]
74 public BoolParameter fastMode = new BoolParameter { value = false };
76 /// <summary>
77 /// The dirtiness texture to add smudges or dust to the lens.
78 /// </summary>
79 [Tooltip("The lens dirt texture used to add smudges or dust to the bloom effect."), DisplayName("Texture")]
80 public TextureParameter dirtTexture = new TextureParameter { value = null };
82 /// <summary>
83 /// The amount of lens dirtiness.
84 /// </summary>
85 [Min(0f), Tooltip("The intensity of the lens dirtiness."), DisplayName("Intensity")]
86 public FloatParameter dirtIntensity = new FloatParameter { value = 0f };
88 /// <inheritdoc />
89 public override bool IsEnabledAndSupported(PostProcessRenderContext context)
91 return enabled.value
92 && intensity.value > 0f;
96 #if UNITY_2017_1_OR_NEWER
97 [UnityEngine.Scripting.Preserve]
98 #endif
99 internal sealed class BloomRenderer : PostProcessEffectRenderer<Bloom>
101 enum Pass
103 Prefilter13,
104 Prefilter4,
105 Downsample13,
106 Downsample4,
107 UpsampleTent,
108 UpsampleBox,
109 DebugOverlayThreshold,
110 DebugOverlayTent,
111 DebugOverlayBox
114 // [down,up]
115 Level[] m_Pyramid;
116 const int k_MaxPyramidSize = 16; // Just to make sure we handle 64k screens... Future-proof!
118 struct Level
120 internal int down;
121 internal int up;
124 public override void Init()
126 m_Pyramid = new Level[k_MaxPyramidSize];
128 for (int i = 0; i < k_MaxPyramidSize; i++)
130 m_Pyramid[i] = new Level
132 down = Shader.PropertyToID("_BloomMipDown" + i),
133 up = Shader.PropertyToID("_BloomMipUp" + i)
138 public override void Render(PostProcessRenderContext context)
140 var cmd = context.command;
141 cmd.BeginSample("BloomPyramid");
143 var sheet = context.propertySheets.Get(context.resources.shaders.bloom);
145 // Apply auto exposure adjustment in the prefiltering pass
146 sheet.properties.SetTexture(ShaderIDs.AutoExposureTex, context.autoExposureTexture);
148 // Negative anamorphic ratio values distort vertically - positive is horizontal
149 float ratio = Mathf.Clamp(settings.anamorphicRatio, -1, 1);
150 float rw = ratio < 0 ? -ratio : 0f;
151 float rh = ratio > 0 ? ratio : 0f;
153 // Do bloom on a half-res buffer, full-res doesn't bring much and kills performances on
154 // fillrate limited platforms
155 int tw = Mathf.FloorToInt(context.screenWidth / (2f - rw));
156 int th = Mathf.FloorToInt(context.screenHeight / (2f - rh));
157 bool singlePassDoubleWide = (context.stereoActive && (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass) && (context.camera.stereoTargetEye == StereoTargetEyeMask.Both));
158 int tw_stereo = singlePassDoubleWide ? tw * 2 : tw;
160 // Determine the iteration count
161 int s = Mathf.Max(tw, th);
162 float logs = Mathf.Log(s, 2f) + Mathf.Min(settings.diffusion.value, 10f) - 10f;
163 int logs_i = Mathf.FloorToInt(logs);
164 int iterations = Mathf.Clamp(logs_i, 1, k_MaxPyramidSize);
165 float sampleScale = 0.5f + logs - logs_i;
166 sheet.properties.SetFloat(ShaderIDs.SampleScale, sampleScale);
168 // Prefiltering parameters
169 float lthresh = Mathf.GammaToLinearSpace(settings.threshold.value);
170 float knee = lthresh * settings.softKnee.value + 1e-5f;
171 var threshold = new Vector4(lthresh, lthresh - knee, knee * 2f, 0.25f / knee);
172 sheet.properties.SetVector(ShaderIDs.Threshold, threshold);
173 float lclamp = Mathf.GammaToLinearSpace(settings.clamp.value);
174 sheet.properties.SetVector(ShaderIDs.Params, new Vector4(lclamp, 0f, 0f, 0f));
176 int qualityOffset = settings.fastMode ? 1 : 0;
178 // Downsample
179 var lastDown = context.source;
180 for (int i = 0; i < iterations; i++)
182 int mipDown = m_Pyramid[i].down;
183 int mipUp = m_Pyramid[i].up;
184 int pass = i == 0
185 ? (int)Pass.Prefilter13 + qualityOffset
186 : (int)Pass.Downsample13 + qualityOffset;
188 context.GetScreenSpaceTemporaryRT(cmd, mipDown, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
189 context.GetScreenSpaceTemporaryRT(cmd, mipUp, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
190 cmd.BlitFullscreenTriangle(lastDown, mipDown, sheet, pass);
192 lastDown = mipDown;
193 tw_stereo = (singlePassDoubleWide && ((tw_stereo / 2) % 2 > 0)) ? 1 + tw_stereo / 2 : tw_stereo / 2;
194 tw_stereo = Mathf.Max(tw_stereo, 1);
195 th = Mathf.Max(th / 2, 1);
198 // Upsample
199 int lastUp = m_Pyramid[iterations - 1].down;
200 for (int i = iterations - 2; i >= 0; i--)
202 int mipDown = m_Pyramid[i].down;
203 int mipUp = m_Pyramid[i].up;
204 cmd.SetGlobalTexture(ShaderIDs.BloomTex, mipDown);
205 cmd.BlitFullscreenTriangle(lastUp, mipUp, sheet, (int)Pass.UpsampleTent + qualityOffset);
206 lastUp = mipUp;
209 var linearColor = settings.color.value.linear;
210 float intensity = RuntimeUtilities.Exp2(settings.intensity.value / 10f) - 1f;
211 var shaderSettings = new Vector4(sampleScale, intensity, settings.dirtIntensity.value, iterations);
213 // Debug overlays
214 if (context.IsDebugOverlayEnabled(DebugOverlay.BloomThreshold))
216 context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlayThreshold);
218 else if (context.IsDebugOverlayEnabled(DebugOverlay.BloomBuffer))
220 sheet.properties.SetVector(ShaderIDs.ColorIntensity, new Vector4(linearColor.r, linearColor.g, linearColor.b, intensity));
221 context.PushDebugOverlay(cmd, m_Pyramid[0].up, sheet, (int)Pass.DebugOverlayTent + qualityOffset);
224 // Lens dirtiness
225 // Keep the aspect ratio correct & center the dirt texture, we don't want it to be
226 // stretched or squashed
227 var dirtTexture = settings.dirtTexture.value == null
228 ? RuntimeUtilities.blackTexture
229 : settings.dirtTexture.value;
231 var dirtRatio = (float)dirtTexture.width / (float)dirtTexture.height;
232 var screenRatio = (float)context.screenWidth / (float)context.screenHeight;
233 var dirtTileOffset = new Vector4(1f, 1f, 0f, 0f);
235 if (dirtRatio > screenRatio)
237 dirtTileOffset.x = screenRatio / dirtRatio;
238 dirtTileOffset.z = (1f - dirtTileOffset.x) * 0.5f;
240 else if (screenRatio > dirtRatio)
242 dirtTileOffset.y = dirtRatio / screenRatio;
243 dirtTileOffset.w = (1f - dirtTileOffset.y) * 0.5f;
246 // Shader properties
247 var uberSheet = context.uberSheet;
248 if (settings.fastMode)
249 uberSheet.EnableKeyword("BLOOM_LOW");
250 else
251 uberSheet.EnableKeyword("BLOOM");
252 uberSheet.properties.SetVector(ShaderIDs.Bloom_DirtTileOffset, dirtTileOffset);
253 uberSheet.properties.SetVector(ShaderIDs.Bloom_Settings, shaderSettings);
254 uberSheet.properties.SetColor(ShaderIDs.Bloom_Color, linearColor);
255 uberSheet.properties.SetTexture(ShaderIDs.Bloom_DirtTex, dirtTexture);
256 cmd.SetGlobalTexture(ShaderIDs.BloomTex, lastUp);
258 // Cleanup
259 for (int i = 0; i < iterations; i++)
261 if (m_Pyramid[i].down != lastUp)
262 cmd.ReleaseTemporaryRT(m_Pyramid[i].down);
263 if (m_Pyramid[i].up != lastUp)
264 cmd.ReleaseTemporaryRT(m_Pyramid[i].up);
267 cmd.EndSample("BloomPyramid");
269 context.bloomBufferNameID = lastUp;