Uploaded image for project: 'Qt 3D Studio'
  1. Qt 3D Studio
  2. QT3DS-727

Advanced blend mode fallback shaders are wrong once < 1 alphas are involved

    XMLWordPrintable

Details

    •  14f585e6453161ac4531cdd62810bddf1a9bb982

    Description

      As discussed in QT3DS-657, the fallback advanced blend shaders themselves are incorrect. For opaque objects the output is good since the base formulas themselves are good, but once there are semi-transparent objects involved, the results go haywire.

      We now have working versions in the new Runtime that produce identical results to what the editor shows with the NV or KHR extension present.

      For reference, here are the revised fragment shaders we are using. These follow https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_blend_equation_advanced.txt properly.

      overlay
      
      uniform sampler2D base_layer;
      uniform sampler2D blend_layer;
      void main() {
          vec4 base = texture2D( base_layer, uv_coords );
          if (base.a != 0.0) base.rgb /= base.a; else base = vec4(0.0);
          vec4 blend = texture2D( blend_layer, uv_coords );
          if (blend.a != 0.0) blend.rgb /= blend.a; else blend = vec4(0.0);
          vec4 res = vec4(0.0);
          float p0 = base.a * blend.a; float p1 = base.a * (1 - blend.a); float p2 = blend.a * (1 - base.a);
          res.a = p0 + p1 + p2;
          // overlay = 2 * bottom * top if bottom < 0.5, 1 - 2 * (1 - bottom) * (1 - top) otherwise
          float f_rs_rd = (base.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)));
          float f_gs_gd = (base.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)));
          float f_bs_bd = (base.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b)));
          res.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;
          res.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;
          res.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;
          fragOutput = vec4(res.rgb * res.a, res.a);
      }
      
      color burn
      
      uniform sampler2D base_layer;
      uniform sampler2D blend_layer;
      void main() {
          vec4 base = texture2D( base_layer, uv_coords );
          if (base.a != 0.0) base.rgb /= base.a; else base = vec4(0.0);
          vec4 blend = texture2D( blend_layer, uv_coords );
          if (blend.a != 0.0) blend.rgb /= blend.a; else blend = vec4(0.0);
          vec4 res = vec4(0.0);
          float p0 = base.a * blend.a; float p1 = base.a * (1 - blend.a); float p2 = blend.a * (1 - base.a);
          res.a = p0 + p1 + p2;
          // color burn = invert the bottom layer, divide it by the top layer, then invert
          float f_rs_rd = ((base.r == 1.0) ? 1.0 : (blend.r == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.r) / blend.r)));
          float f_gs_gd = ((base.g == 1.0) ? 1.0 : (blend.g == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.g) / blend.g)));
          float f_bs_bd = ((base.b == 1.0) ? 1.0 : (blend.b == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.b) / blend.b)));
          res.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;
          res.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;
          res.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;
          fragOutput = vec4(res.rgb * res.a, res.a);
      }
      
      color dodge
      
      uniform sampler2D base_layer;
      uniform sampler2D blend_layer;
      void main() {
          vec4 base = texture2D( base_layer, uv_coords );
          if (base.a != 0.0) base.rgb /= base.a; else base = vec4(0.0);
          vec4 blend = texture2D( blend_layer, uv_coords );
          if (blend.a != 0.0) blend.rgb /= blend.a; else blend = vec4(0.0);
          vec4 res = vec4(0.0);
          float p0 = base.a * blend.a; float p1 = base.a * (1 - blend.a); float p2 = blend.a * (1 - base.a);
          res.a = p0 + p1 + p2;
          // color dodge = divide bottom layer by inverted top layer
          float f_rs_rd = ((base.r == 0.0) ? 0.0 : (blend.r == 1.0) ? 1.0 : min(base.r / (1.0 - blend.r), 1.0));
          float f_gs_gd = ((base.g == 0.0) ? 0.0 : (blend.g == 1.0) ? 1.0 : min(base.g / (1.0 - blend.g), 1.0));
          float f_bs_bd = ((base.b == 0.0) ? 0.0 : (blend.b == 1.0) ? 1.0 : min(base.b / (1.0 - blend.b), 1.0));
          res.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;
          res.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;
          res.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;
          fragOutput = vec4(res.rgb * res.a, res.a);
      }
      

      Attachments

        Issue Links

          Activity

            People

              myrjana Marianne Yrjänä
              lagocs Laszlo Agocs
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: