Search Unity

Bug Bloom postprocess effect artifacts (Volume Profile)

Discussion in 'Universal Render Pipeline' started by AlexVillalba, Dec 23, 2020.

  1. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    PLEASE VOTE TO FIX: https://issuetracker.unity3d.com/is...-flickers-when-object-moves-in-the-view-space

    Hi everyone, I would like to report an undesired and ugly behavior of the Bloom postprocess FX that happens when moving the camera, I show it in the following video, pay attention to how the halo that surrounds every light flickers:


    • I'm using Unity 2020.2.
    • It is a build, not in-editor (it occurs in both, although it is more noticiable in editor).
    • Using URP 10.2.2, the 2D Renderer.
    • Using Bloom effect (intensity = 11, scatter = 0.5).
    • Using URP pixel perfect component (experimental).
    • White lines are square sprites.
    Has this ever happened to you? Does it have to do with how the postprocess effect stack is implemented?
    Is there a workaround?

    Thanks in advance.
     
    Last edited: Jan 26, 2021
  2. spryx

    spryx

    Joined:
    Jul 23, 2013
    Posts:
    557
    I think it's most likely due to the pixel-snapping of the 2D renderer (just a guess)... By chance, have you tried it with just URP fwd?
     
  3. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Yes I've only tried with the 2D Renderer of the URP, as I'm using the 2D lights too.
     
  4. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    I've also tried disabling the Pixel Perfect Camera component. Same result.
     
  5. spryx

    spryx

    Joined:
    Jul 23, 2013
    Posts:
    557
    If you manually move the camera transform in the editor do you still see the same effect?
     
  6. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    I've just tried after removing all components but the camera and pausing the game, the same happens.
     
  7. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Curiously enough, it only happens when moving vertically.
     
  8. funkysandwich

    funkysandwich

    Joined:
    Oct 31, 2018
    Posts:
    5
    Is High Quality Filtering enabled under the bloom effect?
     
  9. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    I've just tried enabling that but it does not affect the result.
     
  10. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    I consider this a very important issue because I cannot use it as it is, it looks soooo bad. And I don't have a clue about what can be the origin of the problem. You can watch in the attached video how I manually move the camera, a camera with no components, just me changing the position property.
    Please just focus on the EEI neon only.
     

    Attached Files:

  11. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    I've attached a sample project to reproduce the issue.
     

    Attached Files:

  12. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
  13. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
  14. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
    Thank you <3 What was the ID number?
     
  15. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Case 1304185
     
    UnityMaru likes this.
  16. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    I don't think this one is actually a bug, it's looks like a fairly normal sampling artefact that is common with bloom. You may have just run into a particularly noticeable case.

    Very small+bright objects tend to cause some amount of bloom shimmering, and it's not unique to Unity's bloom implementation.

    Imagine a very tiny quad with no antialiasing being moved across the screen. As it moves across the screen it might be rendered as 1 pixel tall on some frames but 2 pixels tall on other. This greatly affects the amount of bloom that it generates (especially when dealing with HDR, and emissive pixels much brighter than 1.0)

    This is further complicated by the blur process used by bloom effects using downscaled buffers - so even if your rendering is pixel-perfect, it may not guaranteed perfectly shimmer-free bloom. You'll probably find that the shimmer mostly goes away if you make the lights taller.

    The easiest fix for those lights is to not rely on bloom. You could fake the glows using a sprite with additive blending.
     
  17. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
  18. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    The bug has been closed:

    This is by design as the mesh simply too thin and takes only one pixel of width. After bloom downscaling pass linear filtering blends it with the background depending on the position, this way losing its intensity. As result, it is no longer strong enough to contribute to the bloom effect (In this particular case its intensity drops from 1 to 0.0103)

    So I will have to do it with freeform lights or using cookies. 2D materials do not allow to choose the blending mode so that option is discarded. I asked for it here https://forum.unity.com/threads/blend-mode-in-sprite-lit-shaders-in-shadergraph.1028935/
     
    Last edited: Feb 4, 2021
  19. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    you could sample your filter render texture with an increase uv.y texel size, causing all bloom to be stretched slightly on the y axis. might look neat?
     
  20. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Is that feasible with the 2D renderer?
     
  21. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    Yes, you would just need to write your own custom render pass to write a bloom pass that uses a custom material/shader.

    This is a long and slippery slope of undocumented practices to learn.

    You would also need to make sure you stretch the texture before you filter it in the bloomFilterPass
     
  22. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Mmm maybe I'm missing something, or I'm not understanding your suggestion, but the 2D Renderer does not have custom render passes yet.
     
  23. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    Ah I see, I haven't used the 2D Renderer so I made the assumption that it did.
     
  24. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Depending on the performance in low-end hardware, I may solve this by rendering in 4K and then downscaling. I guess there is no way (and there won't) to modify the behaviour of the Bloom fx to make a x2, x4, x16... rescaling. Maybe when custom post-process steps are available in the 2D Renderer I will be able to code my own bloom fx.
     
  25. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    BTW, there are no artifacts when using OpenGL Core instead of DirectX.
     
  26. AlexVillalba

    AlexVillalba

    Joined:
    Feb 7, 2017
    Posts:
    346
    Hi again and sorry for resurrecting this thread, but there are news I want to share with you. In my last comment, 2 years ago, I said there were no artifacts but it was not totally true. At that moment, the way I had setup postprocessing effects made it look like the flickering artifacts were gone. And it's true that, for some reason, using OpenGL makes them quite less visible. But artifacts are still there.

    Fortunately, today I "fixed" it. This means that, in the case of my game, artifacts are practically imperceptible. I think it's impossible to get rid of what may be intrinsic to every Bloom technique, so I prefer to be prudent.

    First, the result:

    (Using DirectX, in Unity 2020.3.4)

    How

    To achieve this I had to change the code of the URP, so you would need to fork the Graphics code repository of Unity (the full source code of the URP), import it into your project replacing the built-in package and change the code.

    The changes I did were few and simple. In PostProcessPass.cs, search for the SetupBloom() method. In the first 2 lines, remove the ">> 1", so the size that is stored in tw and th is the source texture's instead of its half.
    That's it. Compile. Enjoy.

    Code (CSharp):
    1. void SetupBloom(CommandBuffer cmd, int source, Material uberMaterial)
    2. {
    3.       // Start at half-res
    4.       int tw = m_Descriptor.width;// >> 1;
    5.       int th = m_Descriptor.height;// >> 1;
    Why

    The value stored in the variables tw and th is used to generate temporary render targets to perform the Bloom technique (downsampling first, then upsampling, applying gaussian blur). Before this happens, the algorithm in SetupBloom() performs an operation they call "prefilter", which copies the content of the source texture (the texture used while rendering geometry, where the color and brightness related to the Bloom FX are stored) to the first texture that feeds the downsampling loop.

    Code (CSharp):
    1. // Prefilter
    2. var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
    3. cmd.GetTemporaryRT(ShaderConstants._BloomMipDown[0], desc, FilterMode.Bilinear);
    4. cmd.GetTemporaryRT(ShaderConstants._BloomMipUp[0], desc, FilterMode.Bilinear);
    5. Blit(cmd, source, ShaderConstants._BloomMipDown[0], bloomMaterial, 0);
    In the loop, the content of the texture is processed and copied to another texture whose size is half of the previous, and this reduction happens N times (which depends on the original value of tw and th). Without our changes, in the "prefilter" step the algorithm mixes the preparation of the content of the first texture with a first downsampling (halving), saving some GPU power, instead of copying first and downsampling afterwards.

    The format of the source texture (R8G8B8A8_UNORM) is different from the format of the textures used in the process (R11G11B10_FLOAT).
    The shader used in the process is called "Bloom.shader", which is stored in the bloomMaterial variable, and contains 4 passes: Prefilter (0), Blur horizontal (1), Blur vertical (2) (both used in the downsampling step) and Upsample (3).
    The content of the Prefilter pass and the blur passes is obviously not the same. Apart from the maths used in the code, the difference is that it is sampling texels from a texture with a different format (less precise) than the destination texture's, applying a bilinear filter (as in the other steps). Somehow, when we get rid of the bilinear filtering (as both textures are equal in size, thanks to our changes) the texels are read and converted properly, and then the Bloom process continues without problem. In other words, the value of each texel of the source texture is not interpolated; since source texture doubled the size of the destination, the UV of the texel [2, 4] in the destination corresponded to the texel[4,8] in the source texture (skipping texels in the column 3 and row 7), but the final value was interpolated among the 8 texels surrounding [4, 8], deforming it and, I guess, losing information.
    Honestly, I haven't studied the code of the shader deeper to fully understand how is the data lost, since I don't have more time for this.
    Feel free to add your ideas and conclusions.
     
    Last edited: Mar 18, 2023
    yeyekopi, pahe and minsumandoo like this.