Skip to content

Reduce bloom flickering #2035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added the usage of SSAO for shadow matte unlit shader graph.
- Added a new volume component parameter to control the max ray length of directional lights(case 1279849).
- Added support for 'Pyramid' and 'Box' spot light shapes in path tracing.
- Added high quality prefiltering option for Bloom.

### Fixed
- Fixed several issues with physically-based DoF (TAA ghosting of the CoC buffer, smooth layer transitions, etc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Bloom includes [more options](More-Options.md) that you must manually expose.
| **Property** | **Description** |
| -------------------------- | ------------------------------------------------------------ |
| **Resolution** | Use the drop-down to set the resolution at which HDRP processes the Bloom effect. If you target consoles that use a very high resolution (for example, 4k), select **Quarter,** because it is less resource-intensive.<br />&#8226; **Quarter**: Uses quarter the screen resolution.<br />&#8226; **Half**: Uses half the screen resolution. This property only appears when you enable [more options](More-Options.md). |
| **High Quality Prefiltering** | Enable the checkbox to make HDRP use 13 samples instead of 4 during the prefiltering pass. This increases the resource intensity of the Bloom effect, but results in less flickering by small and bright objects like the sun.<br />This property only appears when you enable [more options](More-Options.md). |
| **High Quality Filtering** | Enable the checkbox to make HDRP use bicubic filtering instead of bilinear filtering. This increases the resource intensity of the Bloom effect, but results in smoother visuals.<br />This property only appears when you enable [more options](More-Options.md). |
| **Anamorphic** | Enable the checkbox to make the bloom effect take the **Anamorphism** property of the Camera into account. This stretches the bloom horizontally or vertically like it would on anamorphic sensors.<br />This property only appears when you enable [more options](More-Options.md). |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sealed class BloomEditor : VolumeComponentWithQualityEditor
SerializedDataParameter m_DirtIntensity;

// Advanced settings
SerializedDataParameter m_HighQualityPrefiltering;
SerializedDataParameter m_HighQualityFiltering;
SerializedDataParameter m_Resolution;
SerializedDataParameter m_Anamorphic;
Expand All @@ -34,6 +35,7 @@ public override void OnEnable()
m_DirtTexture = Unpack(o.Find(x => x.dirtTexture));
m_DirtIntensity = Unpack(o.Find(x => x.dirtIntensity));

m_HighQualityPrefiltering = Unpack(o.Find("m_HighQualityPrefiltering"));
m_HighQualityFiltering = Unpack(o.Find("m_HighQualityFiltering"));
m_Resolution = Unpack(o.Find("m_Resolution"));
m_Anamorphic = Unpack(o.Find(x => x.anamorphic));
Expand All @@ -59,6 +61,7 @@ public override void OnInspectorGUI()
using (new EditorGUI.DisabledScope(!useCustomValue))
{
PropertyField(m_Resolution);
PropertyField(m_HighQualityPrefiltering);
PropertyField(m_HighQualityFiltering);
}
PropertyField(m_Anamorphic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class GeneralSection
public static readonly GUIContent maxRadiusQuality = EditorGUIUtility.TrTextContent("Max Radius");
public static readonly GUIContent sampleCountQuality = EditorGUIUtility.TrTextContent("Sample Count");
public static readonly GUIContent resolutionQuality = EditorGUIUtility.TrTextContent("Resolution");
public static readonly GUIContent highQualityPrefiltering = EditorGUIUtility.TrTextContent("High Quality Filtering");
public static readonly GUIContent highQualityFiltering = EditorGUIUtility.TrTextContent("High Quality Filtering");
public static readonly GUIContent dofPhysicallyBased = EditorGUIUtility.TrTextContent("Physically Based");
public static readonly GUIContent maxSamplesQuality = EditorGUIUtility.TrTextContent("Max Samples");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ static void Drawer_SectionMotionBlurQualitySettings(SerializedHDRenderPipelineAs
static void DrawBloomQualitySetting(SerializedHDRenderPipelineAsset serialized, int tier)
{
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.postProcessQualitySettings.BloomRes.GetArrayElementAtIndex(tier), Styles.resolutionQuality);
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.postProcessQualitySettings.BloomHighPrefilteringQuality.GetArrayElementAtIndex(tier), Styles.highQualityPrefiltering);
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.postProcessQualitySettings.BloomHighFilteringQuality.GetArrayElementAtIndex(tier), Styles.highQualityFiltering);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SerializedPostProcessingQualitySettings
// Bloom
public SerializedProperty BloomRes;
public SerializedProperty BloomHighFilteringQuality;
public SerializedProperty BloomHighPrefilteringQuality;

// Chromatic Aberration
public SerializedProperty ChromaticAbMaxSamples;
Expand All @@ -45,6 +46,7 @@ public SerializedPostProcessingQualitySettings(SerializedProperty root)
// Bloom
BloomRes = root.Find((GlobalPostProcessingQualitySettings s) => s.BloomRes);
BloomHighFilteringQuality = root.Find((GlobalPostProcessingQualitySettings s) => s.BloomHighQualityFiltering);
BloomHighPrefilteringQuality= root.Find((GlobalPostProcessingQualitySettings s) => s.BloomHighQualityPrefiltering);

// Chromatic Aberration
ChromaticAbMaxSamples = root.Find((GlobalPostProcessingQualitySettings s) => s.ChromaticAberrationMaxSamples);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ public BloomResolution resolution
set { m_Resolution.value = value; }
}

/// <summary>
/// When enabled, bloom uses bicubic sampling instead of bilinear sampling for the upsampling passes.
/// </summary>
public bool highQualityPrefiltering
{
get
{
if (!UsesQualitySettings())
{
return m_HighQualityPrefiltering.value;
}
else
{
int qualityLevel = (int)quality.levelAndOverride.level;
return GetPostProcessingQualitySettings().BloomHighQualityPrefiltering[qualityLevel];
}
}
set { m_HighQualityPrefiltering.value = value; }
}

/// <summary>
/// When enabled, bloom uses bicubic sampling instead of bilinear sampling for the upsampling passes.
/// </summary>
Expand All @@ -114,6 +134,10 @@ public bool highQualityFiltering
[SerializeField, FormerlySerializedAs("resolution")]
private BloomResolutionParameter m_Resolution = new BloomResolutionParameter(BloomResolution.Half);

[Tooltip("When enabled, bloom uses multiple bilinear samples for the prefiltering pass.")]
[SerializeField]
private BoolParameter m_HighQualityPrefiltering = new BoolParameter(false);

[Tooltip("When enabled, bloom uses bicubic sampling instead of bilinear sampling for the upsampling passes.")]
[SerializeField, FormerlySerializedAs("highQualityFiltering")]
private BoolParameter m_HighQualityFiltering = new BoolParameter(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3041,6 +3041,12 @@ BloomParameters PrepareBloomParameters(HDCamera camera)
parameters.bloomPrefilterCS = m_Resources.shaders.bloomPrefilterCS;
parameters.bloomPrefilterKernel = parameters.bloomPrefilterCS.FindKernel("KMain");

parameters.bloomPrefilterCS.shaderKeywords = null;
if (m_Bloom.highQualityPrefiltering)
parameters.bloomPrefilterCS.EnableKeyword("HIGH_QUALITY");
else
parameters.bloomPrefilterCS.EnableKeyword("LOW_QUALITY");

parameters.bloomBlurCS = m_Resources.shaders.bloomBlurCS;
parameters.bloomBlurKernel = parameters.bloomBlurCS.FindKernel("KMain");
parameters.bloomDownsampleKernel = parameters.bloomBlurCS.FindKernel("KDownsample");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@

#pragma only_renderers d3d11 playstation xboxone vulkan metal switch

#pragma kernel KMain MAIN=KMain
#pragma kernel KMain MAIN=KMain
#pragma kernel KDownsample MAIN=KDownsample DOWNSAMPLE


TEXTURE2D_X(_InputTexture);

RW_TEXTURE2D_X(float3, _OutputTexture);

SAMPLER(sampler_LinearClamp);

CBUFFER_START(cb0)
float4 _TexelSize; // xy: size, zw: texel size
CBUFFER_END
Expand Down Expand Up @@ -113,10 +111,10 @@ void MAIN(uint2 groupId : SV_GroupID, uint2 groupThreadId : SV_GroupThreadID, ui
#if DOWNSAMPLE
float2 offset = float2(threadUL);
float2 maxCoord = 1.0 - 0.5f *_TexelSize.zw;
float3 p00 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear((offset + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p10 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear((offset + float2(1.0, 0.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p01 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear((offset + float2(0.0, 1.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p11 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear((offset + float2(1.0, 1.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p00 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, s_linear_clamp_sampler, ClampAndScaleUVForBilinear((offset + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p10 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, s_linear_clamp_sampler, ClampAndScaleUVForBilinear((offset + float2(1.0, 0.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p01 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, s_linear_clamp_sampler, ClampAndScaleUVForBilinear((offset + float2(0.0, 1.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
float3 p11 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, s_linear_clamp_sampler, ClampAndScaleUVForBilinear((offset + float2(1.0, 1.0) + 0.5) * _TexelSize.zw, _TexelSize.zw), 0.0).xyz;
#else
uint2 uthreadUL = uint2(max(0, threadUL));
uint2 size = uint2(_TexelSize.xy) - 1u;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,31 @@

#pragma kernel KMain

#pragma multi_compile LOW_QUALITY HIGH_QUALITY

TEXTURE2D_X(_InputTexture);

RW_TEXTURE2D_X(float3, _OutputTexture);

SAMPLER(sampler_LinearClamp);

CBUFFER_START(cb0)
float4 _TexelSize;
float4 _BloomThreshold;
CBUFFER_END

float3 BilinearSample(float2 uv, float2 offset, out float weight)
{
float3 c = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, s_linear_clamp_sampler, ClampAndScaleUVForBilinear(uv + offset * _ScreenSize.zw), 0.0).xyz;
c = QuadraticThreshold(c, _BloomThreshold.x, _BloomThreshold.yzw);

weight = 1.0 / (Luminance(c) + 1.0);
return c;
}

float3 PartialAverage(float3 c0, float3 c1, float3 c2, float3 c3, float w0, float w1, float w2, float w3)
{
return (c0*w0 + c1*w1 + c2*w2 + c3*w3) / (w0 + w1 + w2 + w3);
}

#define GROUP_SIZE 8

[numthreads(GROUP_SIZE, GROUP_SIZE, 1)]
Expand All @@ -27,6 +41,7 @@ void KMain(uint3 dispatchThreadId : SV_DispatchThreadID)
PositionInputs posInputs = GetPositionInput(float2(dispatchThreadId.xy), _TexelSize.zw, uint2(GROUP_SIZE, GROUP_SIZE));
float2 uv = posInputs.positionNDC;

#if LOW_QUALITY
// Use a rotated grid to minimize artifacts coming from horizontal and vertical boundaries
// "High Quality Antialiasing" [Lorach07]
const float2 kTaps[] = {
Expand All @@ -37,24 +52,14 @@ void KMain(uint3 dispatchThreadId : SV_DispatchThreadID)
float2(-0.4, -0.9)
};

float3 color0 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear(_TexelSize.zw * kTaps[0] + uv, _TexelSize.zw), 0.0).xyz;
float3 color1 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear(_TexelSize.zw * kTaps[1] + uv, _TexelSize.zw), 0.0).xyz;
float3 color2 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear(_TexelSize.zw * kTaps[2] + uv, _TexelSize.zw), 0.0).xyz;
float3 color3 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear(_TexelSize.zw * kTaps[3] + uv, _TexelSize.zw), 0.0).xyz;
float3 color4 = SAMPLE_TEXTURE2D_X_LOD(_InputTexture, sampler_LinearClamp, ClampAndScaleUVForBilinear(_TexelSize.zw * kTaps[4] + uv, _TexelSize.zw), 0.0).xyz;

color0 = QuadraticThreshold(color0, _BloomThreshold.x, _BloomThreshold.yzw);
color1 = QuadraticThreshold(color1, _BloomThreshold.x, _BloomThreshold.yzw);
color2 = QuadraticThreshold(color2, _BloomThreshold.x, _BloomThreshold.yzw);
color3 = QuadraticThreshold(color3, _BloomThreshold.x, _BloomThreshold.yzw);
color4 = QuadraticThreshold(color4, _BloomThreshold.x, _BloomThreshold.yzw);
float w0, w1, w2, w3, w4;
float3 color0 = BilinearSample(uv, kTaps[0], w0);
float3 color1 = BilinearSample(uv, kTaps[1], w1);
float3 color2 = BilinearSample(uv, kTaps[2], w2);
float3 color3 = BilinearSample(uv, kTaps[3], w3);
float3 color4 = BilinearSample(uv, kTaps[4], w4);

// Luma weighted average [Karis13]
float w0 = 1.0 / (Luminance(color0) + 1.0);
float w1 = 1.0 / (Luminance(color1) + 1.0);
float w2 = 1.0 / (Luminance(color2) + 1.0);
float w3 = 1.0 / (Luminance(color3) + 1.0);
float w4 = 1.0 / (Luminance(color4) + 1.0);
float wSum = w0 + w1 + w2 + w3 + w4;

color0 *= w0;
Expand All @@ -65,6 +70,30 @@ void KMain(uint3 dispatchThreadId : SV_DispatchThreadID)

float3 acc = color0 + color1 + color2 + color3 + color4;
float3 output = acc / wSum;
#else
// "Post-Processing in CoD Advanced Warfare" [Jimenez14]
float wA, wB, wC, wD, wE, wF, wG, wH, wI, wJ, wK, wL, wM;
float3 A = BilinearSample(uv, float2(-1.0, -1.0), wA);
float3 B = BilinearSample(uv, float2( 0.0, -1.0), wB);
float3 C = BilinearSample(uv, float2( 1.0, -1.0), wC);
float3 D = BilinearSample(uv, float2(-0.5, -0.5), wD);
float3 E = BilinearSample(uv, float2( 0.5, -0.5), wE);
float3 F = BilinearSample(uv, float2(-1.0, 0.0), wF);
float3 G = BilinearSample(uv, float2( 0.0, 0.0), wG);
float3 H = BilinearSample(uv, float2( 1.0, 0.0), wH);
float3 I = BilinearSample(uv, float2(-0.5, 0.5), wI);
float3 J = BilinearSample(uv, float2( 0.5, 0.5), wJ);
float3 K = BilinearSample(uv, float2(-1.0, 1.0), wK);
float3 L = BilinearSample(uv, float2( 0.0, 1.0), wL);
float3 M = BilinearSample(uv, float2( 1.0, 1.0), wM);

float3 output = 0;
output += PartialAverage(D, E, I, J, wD, wE, wI, wJ) * 0.5;
output += PartialAverage(A, B, F, G, wA, wB, wF, wG) * 0.125;
output += PartialAverage(B, C, G, H, wB, wC, wG, wH) * 0.125;
output += PartialAverage(F, G, K, L, wF, wG, wK, wL) * 0.125;
output += PartialAverage(G, H, L, M, wG, wH, wL, wM) * 0.125;
#endif

// Guard bands
output *= all(dispatchThreadId.xy <= uint2(_TexelSize.xy));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#pragma only_renderers d3d11 playstation xboxone vulkan metal switch

#pragma kernel KMain
#pragma kernel KMain

#pragma multi_compile LOW_QUALITY HIGH_QUALITY

Expand All @@ -13,8 +13,6 @@ TEXTURE2D_X(_InputHighTexture);

RW_TEXTURE2D_X(float3, _OutputTexture);

SAMPLER(sampler_LinearClamp);

CBUFFER_START(cb0)
float4 _Params; // x: scatter, yzw: unused
float4 _BloomBicubicParams; // xy: low src size, zw: low src texel size
Expand All @@ -34,10 +32,10 @@ void KMain(uint3 dispatchThreadId : SV_DispatchThreadID)
float3 highRes = LOAD_TEXTURE2D_X(_InputHighTexture, clamp(posInputs.positionSS, 0, _TexelSize.xy - 1)).xyz;

#if LOW_QUALITY
float3 lowRes = SAMPLE_TEXTURE2D_X_LOD(_InputLowTexture, sampler_LinearClamp, uv, 0.0).xyz;
float3 lowRes = SAMPLE_TEXTURE2D_X_LOD(_InputLowTexture, s_linear_clamp_sampler, uv, 0.0).xyz;
#else // HIGH_QUALITY
float2 maxCoord = (1.0f - _TexelSize.zw) * _RTHandleScale.xy;
float3 lowRes = SampleTexture2DBicubic(TEXTURE2D_X_ARGS(_InputLowTexture, sampler_LinearClamp), uv, _BloomBicubicParams, maxCoord, unity_StereoEyeIndex).xyz;
float3 lowRes = SampleTexture2DBicubic(TEXTURE2D_X_ARGS(_InputLowTexture, s_linear_clamp_sampler), uv, _BloomBicubicParams, maxCoord, unity_StereoEyeIndex).xyz;
#endif

float3 output = lerp(highRes, lowRes, Scatter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ internal GlobalPostProcessingQualitySettings()
BloomHighQualityFiltering[(int)ScalableSettingLevelParameter.Level.Medium] = true;
BloomHighQualityFiltering[(int)ScalableSettingLevelParameter.Level.High] = true;

BloomHighQualityPrefiltering[(int)ScalableSettingLevelParameter.Level.Low] = false;
BloomHighQualityPrefiltering[(int)ScalableSettingLevelParameter.Level.Medium] = false;
BloomHighQualityPrefiltering[(int)ScalableSettingLevelParameter.Level.High] = true;

/* Chromatic Aberration */
ChromaticAberrationMaxSamples[(int)ScalableSettingLevelParameter.Level.Low] = 3;
ChromaticAberrationMaxSamples[(int)ScalableSettingLevelParameter.Level.Medium] = 6;
Expand Down Expand Up @@ -132,8 +136,10 @@ internal GlobalPostProcessingQualitySettings()
/* Bloom */
/// <summary>Bloom resolution for each quality level.</summary>
public BloomResolution[] BloomRes = new BloomResolution[s_QualitySettingCount];
/// <summary>Use bloom high quality filtering for each quality level.</summary>
/// <summary>Bloom high quality filtering for each quality level.</summary>
public bool[] BloomHighQualityFiltering = new bool[s_QualitySettingCount];
/// <summary>Bloom high quality prefiltering for each quality level.</summary>
public bool[] BloomHighQualityPrefiltering = new bool[s_QualitySettingCount];

/* Chromatic Aberration */
/// <summary>Chromatic aberration maximum sample count for each quality level.</summary>
Expand Down