Announcement

Collapse
No announcement yet.

Weird Opacity jumps when increasing the alpha value of an Albedo Color

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Weird Opacity jumps when increasing the alpha value of an Albedo Color

    Windows / Delphi / Version 3

    When I implemented an opacity setting in my editor for models I noticed weird jumps where the opacity changes. At 4 points from 0 to 1 alpha the opacity changes in a big chunk. In order to test out that I didnt just made some stupid mistakes I took the Cube demo from the framework and changed it to this :

    Code:
        if FTextured then
        begin
          LMaterial.AmbientColor := FloatColorRGB($00404040);
          LMaterial.AlbedoColor.Red := 1;
          LMaterial.AlbedoColor.Green := 1;
          LMaterial.AlbedoColor.Blue := 1;
          LMaterial.AlbedoColor.Alpha := FAlpha;
        end
        else
        begin
          LMaterial.AmbientColor := FloatColorRGB($004000);
          LMaterial.AlbedoColor.Red := 0.5;
          LMaterial.AlbedoColor.Green := 0.3;
          LMaterial.AlbedoColor.Blue := 0.0;
          LMaterial.AlbedoColor.Alpha := FAlpha;
        end;​
    Here is a recording of the effect. You can see the alpha value on top increasing smoothly.
    I directly changed the float color values but it also happens when I convert an Intcolor with floatcolor ()


  • #2
    Normally, Alpha value of Albedo color is actually considered a Bloom (or "Glare") factor. Bloom is applied by taking a certain threshold before tone-mapping is applied. What you see is probably effect of bloom getting amplified as you change its strength. You can control different bloom options by adjusting "ToneMappingBloom" structure from texture cabinet, where you can adjust the actual threshold, gamma, etc.

    Only in "glassy" (a shorter alias for Order-Independent Transparency) scene, alpha value of Albedo color is considered as transparency factor.

    Comment


    • #3
      I didnt consider glassy so far because I misunderstood the concept. That order independent put me off because I thought you couldnt adjust the transparency.
      I also thought so because I remember trying to set the alpha in the Object picking demo to 1 and the glasses were still fully seethrough. Just saw that it multiplies with the alpha from the material which is 0.25 dooh.

      Comment


      • #4
        Normally, the transparency is order-dependent. This means that you have to literally sort all triangles from back to front to get the transparency right. Typical techniques are based on "depth peeling", where you render the same object many times, each time processing a single visible transparent layer, from back to front. This is quite inefficient and slow, especially for complex objects and/or many objects behind each other.

        Order-Independent Transparency means that you can render semi-transparent objects in a single pass. This is significantly more efficient and allows you to render everything using the same approach as you would do for non-transparent objects. Afterwarp supports both an approximated and accurate modes using modern state-of-the-art techniques. It can also optionally add "frosted glass" effect to the transparency, so the objects behind transparent object would appear blurred. The transparency for each object is taken from vertex colors and object materials.

        Comment


        • #5
          Hey there. Ive run into another problem of the same kind.
          I have implemented a HUD that is drawn over the 3d scene. It basically works like this:

          Texturecabinet begin
          render 3d scene stuff
          Texturecabinet end

          DrawableTexture begin
          render 2d canvas stuff
          drawable texture end

          swapchain begin
          texturecabinet present
          draw quad with drawable
          swapchain end

          With this I got the exact same weird jumps in transparency but not in the 3d scene as before but for a 2d image within the drawable texture. To illustrate it better I looked for a PNG with a smooth alpha gradient and it ended up like Image 1. It has the same jumps in alpha visible that I also get when I try to fade in and out an image on time.
          However when I change the render order to :

          DrawableTexture begin
          render 2d canvas stuff
          drawable texture end​​

          Texturecabinet begin
          render 3d scene stuff
          Texturecabinet end

          swapchain begin
          texturecabinet present
          draw quad with drawable
          swapchain end​

          Then I end up with a correct alpha gradient see Image 2.
          This surprised me since the drawable texture with the HUD elements is not part of the TextureCabinet and 3d Scene but it still changes the outcome of it when it was rendered before.

          ---
          So, ok. By using this order I can solve the problem with the HUD elements, but then I wondered about using that PNG as a texture IN a 3d scene. One thing that I absolutely want for my game engine are 2.5D elements like sprites like in Doom. 2D characters walking around in 3D, sprite animations like explosions ect using single planes. So of course I would like these to have a smooth alpha gradient.
          And it seems that I get the same problem, see Image 3.

          So, how can I fix this? I tried toggling premultipliedalpha on the textures. Different Pixelformats... MSAA on off...
          Do I have to use glassy render mode for every texture that has transparent areas in order to get a smooth result?
          If yes, would you be so kind to provide a simple example? I tried adding the previous mentioned texture to your "object picking example", on the parts that use glassy rendering, but I wasnt able to make it work. the texture simply didnt appear.
          I also added the gradient png here too.
          Attached Files

          Comment


          • #6
            In Afterwarp, when rendering opaque scene, alpha-channel is actually considered bloom/glare factor. So your vertex alpha gets multiplied by texture alpha, then by albedo color alpha, and that turns out to be bloom/glare factor. If you use "glassy" scene, which is meant for rendering semi-transparent objects correctly, alpha-channel gets correctly used as transparency, and this includes texture's alpha.

            However, if you want "crude" transparency without using "glassy" scene (although I don't understand why you are struggling not to use it), you can still achieve transparency, using the same workaround as in "NightBridge" example, where car's windshield is rendered. Basically, you have to setup your rendering state like this (code taken directly from NightBridge example):

            Code:
              // Retrieve current rendering state.
              LInitialState := FDevice.RenderingState;
            
              // Simulate some sort of transparency without resorting to more complex techniques by using alpha-
              // blending and alpha-to-coverage mode. As this is done during HDR rendering, it would be inaccurate.
              // However, vehicle windshield is a minor detail, so simplicity is a reasonable compromise.
            
              LRenderingState := LInitialState;
              LRenderingState.States := LRenderingState.States or TRenderingState.State.BlendEnable;
              LRenderingState.BlendColor.Source := TBlendFactor.One;
              LRenderingState.BlendColor.Dest := TBlendFactor.Zero;
              // Destination alpha-channel actually contains bloom factors, so reduce it based on source alpha values.
              LRenderingState.BlendAlpha.Source := TBlendFactor.Zero;
              LRenderingState.BlendAlpha.Dest := TBlendFactor.InvSourceAlpha;
            
              if not LMultisampling then
              begin
                LRenderingState.BlendColor.Source := TBlendFactor.SourceAlpha;
                LRenderingState.BlendColor.Dest := TBlendFactor.InvSourceAlpha;
              end
              else
                LRenderingState.States := LRenderingState.States or TRenderingState.State.AlphaToCoverage;
            
              // Depth clip negative behavior only occurs under older OpenGL implementations that do not support clip
              // control either under normal API or through extension. It has significantly less depth precision.
              if LDepthClipNegative then
                LRenderingState.DepthFunc := TComparisonFunc.LessEqual
              else
                LRenderingState.DepthFunc := TComparisonFunc.GreaterEqual;
            
              FDevice.RenderingState := LRenderingState;
            In above, when multi-sampling is enabled, we use "alpha-to-coverage" trick, which basically means each pixel gets samples "dithered" according to alpha-channel, and when multisample texture is resolved, this results in portions appearing semi-transparent. An analogy to this would be old DOS tricks, where to render something semi-transparent, you would draw an image in checkboard pattern, having half of the pixels from background, and half pixels from the image. The tradeoff is that you have only as much transparent levels as the numbers of samples and it looks like on your screenshots you have 4 multisamples, so 4 levels of transparency. The benefit of this technique is simplicity and that it is also sort of "OIT", so you don't have to worry about sorting triangles by depth.

            In above code, you can also remove "alpha-to-coverage" code-path and just use alpha-blending, which should give you full levels of transparency, but this will only work as long as the semi-transparent surface is alone; that is, there are no other semi-transparent surfaces that you can see through this surface. If there are, you will see incorrect transparency depending on the viewed order and the order in which you draw them.

            Both of the above approaches, in addition to the tradeoffs that I've mentioned, also suffer from the fact that they are not HDR accurate. In other words, if you have a very bright object, it'll still appear behind semi-transparent object no matter how opaque the last one is (even if your alpha is, for example, 0.99 or almost completely opaque).

            A better alternative is to use "glassy" scene, where you can draw as many semi-transparent objects as you want, in any order of your convenience, and they will look correctly from any angle (hence "order-independent transparency"), HDR correct AND with multisampling. In "glassy" scene, you can pick the desired technique: a normal accurate technique requires certain GPU work, whereas "fast" technique is lightweight, but it is an approximation. A limitation of "fast" technique is that it doesn't work for low transparency levels (almost opaque), so again, it is a tradeoff.

            Comment


            • #7
              It is really not that I fight against using glassy mode. I was simply too stupid so far to get it to work with textures applied
              Thanks again for elaborating how this works under the hood. I will sit down with enough time and a clear head and figure out a clear way to seperate the rendering for objects. Basically adding a checkmark in the editor that will specify a model to be rendered through the glassy mode.

              Comment


              • #8
                I have attached an example project (Transparency.zip) that shows all techniques I've mentioned. Note that "alpha-blending" does not yield correct results, unless you separate every plane into a separate object - in this case, "auto-draw helper" will sort objects from back to front when you specify "transparency" flag, so the overall effect will look correct (uncomment dot in conditional define to try it).

                Click image for larger version  Name:	Image00 - Accurate.png Views:	0 Size:	521.8 KB ID:	490 Click image for larger version  Name:	Image01 - Approximate.png Views:	0 Size:	588.0 KB ID:	493 Click image for larger version  Name:	Image02 - AlphaToCoverage.png Views:	0 Size:	540.7 KB ID:	491 Click image for larger version  Name:	Image03 - AlphaBlending.png Views:	0 Size:	570.4 KB ID:	492

                Comment


                • #9
                  These are screenshots, when using texture with linear alpha and color gradients. Note that alpha-to-coverage trick doesn't work well with such gradients.
                  Click image for larger version

Name:	Image10 - Accurate.png
Views:	132
Size:	93.1 KB
ID:	495 Click image for larger version

Name:	Image11 - Approximate.png
Views:	106
Size:	98.5 KB
ID:	496 Click image for larger version

Name:	Image12 - AlphaToCoverage.png
Views:	89
Size:	123.4 KB
ID:	498 Click image for larger version

Name:	Image13 - AlphaBlending.png
Views:	108
Size:	95.9 KB
ID:	497

                  Comment


                  • #10
                    In the example that I've attached, you can rotate the camera around and see that when viewed from behind, the transparency looks correct even when alpha-blending. This is because I create quads in FOR loop. Maybe I'll modify this example later on to create quads in random order, this will illustrate better the problem.

                    An approximated order-independent transparency is very fast technique, but it is meant when objects are semi-transparent with the transparency around 0.5; it is very useful for glass, windows and windshields; it is also accurate for HDR (not seen in this example).

                    So, generally, I would use alpha-to-coverage when multisampling is enabled as a quick and simple approach; otherwise, I'd use approximate technique for most applications, resorting to accurate technique when such accuracy is really needed.

                    Comment


                    • #11
                      Originally posted by lifepower View Post
                      I have attached an example project (Transparency.zip) that shows all techniques I've mentioned. Note that "alpha-blending" does not yield correct results, unless you separate every plane into a separate object - in this case, "auto-draw helper" will sort objects from back to front when you specify "transparency" flag, so the overall effect will look correct (uncomment dot in conditional define to try it).

                      Click image for larger version Name:	Image00 - Accurate.png Views:	0 Size:	521.8 KB ID:	490 Click image for larger version Name:	Image01 - Approximate.png Views:	0 Size:	588.0 KB ID:	493 Click image for larger version Name:	Image02 - AlphaToCoverage.png Views:	0 Size:	540.7 KB ID:	491 Click image for larger version Name:	Image03 - AlphaBlending.png Views:	0 Size:	570.4 KB ID:	492
                      A thousand thanks for your effort!

                      Comment


                      • #12
                        Click image for larger version

Name:	image.png
Views:	43
Size:	476.4 KB
ID:	502
                        Click image for larger version

Name:	image.png
Views:	32
Size:	606.1 KB
ID:	503

                        Thanks again for your effort and patience. Wouldnt be able to do this without you
                        The HasAlpha Checkbox or an Opacity Setting below 255 will now sort a model to the glassy path.

                        Comment


                        • #13
                          Great, I'm glad you got it working!

                          Comment


                          • #14
                            Just a quick follow up question. Glassy and Bloom do not work together right? In all examples that use glassy the Bloom filter is always applied before the glassy pass. And when I tried to apply Bloom after the glassy pass it just messed up the depth order of the glassy models.

                            It is not really a big deal practically as it only catches your eyes when you switch from full opaque to transparent and back and the bloom filter for that model disappears and reappears. Not really something you would do in an actual game scene anyway. Just want to make sure I understood this right.

                            Comment


                            • #15
                              Bloom only works for opaque part of the scene, because at this point the rendering is still HDR. Glassy scene uses a finally composed non-HDR texture from 3D scene so that transparency would be accurate. As I've explained earlier, HDR does not really work directly with transparency.

                              Comment

                              Working...
                              X