Exact calculation when borderline is trasluency 05/264705/5
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 28 Sep 2021 10:24:11 +0000 (19:24 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 5 Oct 2021 05:53:52 +0000 (14:53 +0900)
Update exact formula when borderline is transluency.
This patch will fix so many visual defects

TODO : If there is a good way to calculate result without division, change it.
TODO : Visual defect occur when BorderlineWidth is 0.0f.
       Not related with this patch but anyway we need to fix some other patch.

Change-Id: Ic14f18eb508dc488a95cdb8f0eff4f615a78629b
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
dali-toolkit/internal/visuals/visual-base-impl.cpp

index cf1eb08..ca94a2e 100644 (file)
@@ -124,30 +124,49 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
   }
 
-  lowp vec3  BorderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
-  lowp float BorderlineColorAlpha = borderlineColor.a * uActorColor.a;
-
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  // NOTE : color-visual is always not preMultiplied.
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
   {
     mediump float tCornerRadius = -gCenterPosition;
     mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
     mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
     if(potential > MaxTexturelinePotential)
     {
-      // potential is out of texture range. use borderline color instead of texture
-      textureColor = vec4(BorderlineColorRGB, 0.0);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= textureColor.a;
     }
-    // TODO : need to fix here when uColor.a = 0.0 and uActorColor.a != 0
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
+
+    // NOTE : color-visual is always not preMultiplied.
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= borderlineColorAlpha;
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    // TODO : Need to find some way without division
+    return vec4(finalMultipliedRGB / finalAlpha, finalAlpha);
   }
-  return mix(textureColor, vec4(BorderlineColorRGB, BorderlineColorAlpha), borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
index 78f8f22..892035e 100644 (file)
@@ -123,33 +123,49 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
   }
 
-  lowp vec3  BorderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
-  lowp float BorderlineColorAlpha = borderlineColor.a * uActorColor.a;
-  // Gradient is always preMultiplied.
-  BorderlineColorRGB *= BorderlineColorAlpha;
-
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  // NOTE : gradient-visual is always preMultiplied.
+  borderlineColorRGB *= borderlineColorAlpha;
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
   {
     mediump float tCornerRadius = -gCenterPosition;
     mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
     mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
-    lowp vec3 BorderlineColorRGB = borderlineColor.xyz * borderlineColor.a;
     if(potential > MaxTexturelinePotential)
     {
-      // potential is out of texture range. use borderline color instead of texture
-      textureColor = vec4(BorderlineColorRGB, 0.0);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= textureAlphaScale;
     }
-    // TODO : need to fix here when uColor.a = 0.0 and uActorColor.a != 0
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
+
+    // NOTE : gradient-visual is always preMultiplied.
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= borderlineOpacity;
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    return vec4(finalMultipliedRGB, finalAlpha);
   }
-  return mix(textureColor, vec4(BorderlineColorRGB, BorderlineColorAlpha), borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
index f9e80fe..edaf643 100644 (file)
@@ -61,8 +61,10 @@ vec4 ComputeVertexPosition()
   vOptRectSize -= 0.2929 * maxRadius + 1.0;
 #endif
 
+  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
 #if IS_REQUIRED_BORDERLINE
   vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vertexPosition.xy *= (1.0 + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth / visualSize);
   vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
 #elif IS_REQUIRED_ROUNDED_CORNER
   vPosition = aPosition * visualSize;
@@ -70,15 +72,16 @@ vec4 ComputeVertexPosition()
   mediump vec2 vPosition = aPosition * visualSize;
 #endif
 
+#if USER_SPACE
+  vertexPosition.xyz *= uSize;
+#endif
+
+  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
+
   return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
 }
 
 void main()
 {
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
   gl_Position = uMvpMatrix * ComputeVertexPosition();
-#if USER_SPACE
-  vertexPosition.xyz *= uSize;
-#endif
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
 }
index 676c02b..fe6469b 100644 (file)
@@ -145,31 +145,48 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
   }
 
-  lowp vec3  BorderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
-  lowp float BorderlineColorAlpha = borderlineColor.a * uActorColor.a;
-  BorderlineColorRGB *= mix(1.0, BorderlineColorAlpha, preMultipliedAlpha);
-
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  borderlineColorRGB *= mix(1.0, borderlineColorAlpha, preMultipliedAlpha);
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
   {
     mediump float tCornerRadius = -gCenterPosition;
     mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
     mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
     if(potential > MaxTexturelinePotential)
     {
-      // potential is out of texture range. use borderline color instead of texture
-      textureColor = vec4(BorderlineColorRGB, 0.0);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= mix(textureColor.a, textureAlphaScale, preMultipliedAlpha);
     }
-    // TODO : need to fix here when uColor.a = 0.0 and uActorColor.a != 0
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
+
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= mix(borderlineColorAlpha, borderlineOpacity, preMultipliedAlpha);
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    // TODO : Need to find some way without division
+    return vec4(finalMultipliedRGB * mix(1.0 / finalAlpha, 1.0, preMultipliedAlpha), finalAlpha);
   }
-  return mix(textureColor, vec4(BorderlineColorRGB, BorderlineColorAlpha), borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
index 1911b95..443c51c 100644 (file)
@@ -988,7 +988,7 @@ Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
 
       if(!IsBorderlineRequired())
       {
-        // If mNeedBorderline is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
+        // If IsBorderlineRequired is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
         mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
       }