Introduce
The waterdrop filter in ibispainting is commonly used to simulate the look of droplets on glass. This effect is often applied to create embossed textures for watermarks and glass-like surfaces. From my perspective, the filter appears to combine a convex lens and a plane lens, where the background is represented as an infinitely large, seamless backdrop.
Core Parameters of the Filter:
-
Height Parameter: Controls the height of the lens effect. The required height to make all patterns resemble a standard convex lens is determined by the area of the largest pattern in the mask. The larger the area of the biggest pattern, the higher the height value.
-
Distance Parameter: Determines the distance between the image and the lens. At a short distance, the image appears as a upright image. As the distance increases, the image becomes inverted.
-
Refraction Index Parameter: The mask shapes themselves function like lenses, and the refraction index adjusts how light bends through them.
Additionally, the filter includes lighting and shadow parameters that help enhance the realism of the effect.
My Approach to Implementing the Ibis Water Droplet Effect Using GMIC:
Starting with David’s GMIC drop water script, I sought to recreate the Ibis effect with some adjustments and enhancements:
Elevation Map Creation (David’s Approach): David’s method involves applying a single blur to the mask image to generate an elevation map. This map determines the area where the warp refraction effect will take place, simulating the lens’ curvature from the outer to the inner areas.
My Adjustments:
- Warp Boundary Conditions: By changing the
period
parameter in the Warp, I could simulate the effect of mapping the texture, which mimics Ibis’ behavior.
+warp[img] .,1,1,2
- Normalize: Adjusting this parameter affected both the height and the range of specular highlights. This was critical for achieving the glossy, water droplet-like shine.
- Elevation Map Fine-Tuning:
-
With one blur, the results were quite good with low refraction and height, closely resembling Ibis. However, when using high refraction and height values, no matter how much I increased the blur, the effect couldn’t create a fuller, more inflated pattern. To solve this, I adjusted the blur process used to generate the elevation map.
-
By applying multiple blurs, with each blur effect diminishing, I was able to more accurately simulate the Ibis-style convex lens effect, achieving the desired fullness.
# Create elevation map. +b. $18 *. [shape] b. {$18*0.5} *. [shape] b. {$18*0.25} *. [shape] b. {$18*0.125} *. [shape] b. {$18*0.0625} *. [shape] b. {$18*0.03125} n. 0,$17 => elevation
-
Full script code of current version filter
#@gui WaterDrop121 : fx_drop_waters, fx_drop_waters_preview(1)
#@gui : note = note("<small><b>Shape geometry:</b></small>")
#@gui : 1 Shapes = choice(1,"Procedural","Opaque Regions on Top Layer")
#@gui : 2 Density = float(20,0,100)
#@gui : 3 Radius = float(2,0,5)
#@gui : 4 Variability = float(80,0,100)
#@gui : 5 Random Seed = int(0,0,16384)
#@gui : note = note("<small>Parameters <i>Density</i>, <i>Radius</i>, <i>Variability</i> and <i>Random seed</i>
#@gui : are used only in <i>Procedural shapes</i> mode.</small>")
#@gui : sep = separator()
#@gui : note = note("<small><b>Light parameters:</b></small>")
#@gui : o 6 Refraction = float(7,0,30)
#@gui : o 7 Light Angle = float(35,0,360)
#@gui : o 8 Specular Size = float(10,0,100)
#@gui : o 9 Specular Intensity = float(1,0,1)
#@gui : o 10 Specular Centering = float(1,0,1)
#@gui : sep = separator()
#@gui : note = note("<small><b>Shadow parameters:</b></small>")
#@gui : o 11 Shadow Size = float(0.05,0,3)
#@gui : o 12 Shadow Intensity = float(0.1,0,1)
#@gui : o 13 Shadow Smoothness = float(0.1,0,3)
#@gui : o 14 Diffuse Shadow = float(0.05,0,3)
#@gui : sep = separator()
#@gui : o 15 Smoothness = float(0.15,0,3)
#@gui : o 16 Output as Separate Layers = _bool(1)
#@gui : o 17 height = float(900,0,5000)
#@gui : o 18 sphere size = float(25,0,150)
#@gui : o 19 highlight size = float(1,0,100)
#@gui : o 20 smoothswitch = choice("smoothoff","smoothon")
#@gui : o 21 smoothvalue = float(60,0,100)
#@gui : o 22 blend mode = choice("default","overlay")
#@gui : sep = separator()
fx_drop_waters :
N:=$!-$1
if $N<=0 error "At least two layers are required in this mode." fi
repeat $N { l[{$!-$>-1}] {
nm0={n} nm=${-gui_layer_name}
=> img
# Create binary shapes (i.e. opacity map).
srand $5
if $1 # Shape from top layer.
pass[0] 0 to_a. channels. 100% >=. 50%
r. [0],[0],1,1,0,0,0.5,0.5
else # Procedural shape.
100%,100%
rmin,rmax:=max(0.1,$3*(1-$4%)),max(0.1,$3)
repeat 10 {
100%,100%
random3d {max(1,$2)} *3d. {-2,w},{-2,h},0
j3d.. .,0,0,0,1,1,0,0 rm.
b. {$rmin+($rmax-$rmin)*$>/9}%,0,1
j.. .,0,0,0,0,0.5 rm.
}
>=. 10%
fi
=> shape
# Create elevation map.
+b. $18
*. [shape]
b. {$18*0.5}
*. [shape]
b. {$18*0.25}
*. [shape]
b. {$18*0.125}
*. [shape]
b. {$18*0.0625}
*. [shape]
b. {$18*0.03125}
n. 0,$17
=> elevation
# Warp image.
g[elevation] xy,2 a[-2,-1] c => grad
+*[grad] {grad,$6*max(w,h)/100} *. [shape] b. $15%
+warp[img] .,1,1,2
#smooth
if $20
smooth. $21,0.7,0.3,0.6,1.1,0.8,30,2,1
fi
rm.. => refraction
# Compute specular spots.
+*[grad] -1 100%,100%,1,1,1 a[-2,-1] c orientation. # 3D normal map.
a:=$7*pi/180 ca:=-cos($a) sa:=-sin($a)
mix_channels. ({(1-$10)*$ca},{(1-$10)*$sa},1)
adjust_colors. $19
c. {100-$8}%,100%
n. 0,1
*. [shape] => spots
# Compute ambiant light (gradient).
mix_channels[grad] ($ca,$sa)
n[grad] 0,1 *[grad] [shape]
# Drop shadow.
+shift[shape] {-$11*$ca}%,{-$11*$sa}%,0,0,1
-. [shape] >=. 1 b. $13% n. 0,1
=> shadow
b[shape] $14% n. 0,1 # Add diffuse shadow around each drop.
# Prepare layers for output.
=>[img] name($nm)
*[shadow] 255 channels[shadow] -1,0 mv[shadow] 1
=>[shadow] "name("$nm" [shadow]),mode(alpha),opacity("{$12*100}")"
to_a[refraction] sh[refraction] 100% +b[shape] $15% *[-2,-1] rm.
mv[refraction] 2
=>[refraction] "name("$nm" [refraction]),mode(alpha)"
if $22
channels[spots] -1,0 sh[spots] 0 f. 1 rm. *[spots] 255
=>[spots] "name("$nm" [specular spots]),mode(overlay),opacity("{$9*100}")"
else
channels[spots] -1,0 sh[spots] 0 f. 1 rm. *[spots] 255
=>[spots] "name("$nm" [specular spots]),mode(alpha),opacity("{$9*100}")"
fi
rv[shape,grad] a[grad,shape] c *[grad] 255 b[grad] $15%
=>[grad] "name("$nm" [gradient]),mode(grainmerge)"
rv
if !$16 gui_merge_layers => $nm0 fi
} }
if $1 rm[0] fi
fx_drop_waters_preview :
N:=$!-$1
if $N<=0 gui_warning_preview "At least two layers are required in this mode." return fi
if $1
repeat $N { l[{$!-$>-1}] {
pass[0] 0 mv. 0
echo $*
fx_drop_waters ${1-16},{$17*0.33},{$18*0.33},${19-22} gui_merge_layers
} }
rm[0]
else foreach { fx_drop_waters $* gui_merge_layers }
fi
Pics used for testing in the article
Issues with the current version Filter:
-
Shadows and Lighting:
- In Ibis, there are inner shadows (giving the droplet effect more depth).
- In GMIC Water Droplet, outer shadows are applied, which is not quite the same.
- The interactive lighting effect in Ibis is not yet available in GMIC, as there doesn’t seem to be a corresponding command to simulate this dynamic lighting.
-
Distortion Details:
- The distortion for specific shapes like hearts, peanuts, and stars (combined shapes) does not yet behave the same as in Ibis. The texture mapping and distortion for these custom shapes still differ from Ibis’ results.
- The distortion for specific shapes like hearts, peanuts, and stars (combined shapes) does not yet behave the same as in Ibis. The texture mapping and distortion for these custom shapes still differ from Ibis’ results.
-
Performance:
- GMIC is much slower in execution compared to Ibis, where the effect is almost real-time. In GMIC, the process can take up to about ten seconds, which is quite slow.
I found a thread where Phong shading and skeleton estimating (maybe not need for waterdrop scenario) are discussed, and I’m wondering whether these techniques are related to achieving the effect of Water Droplet effect in ibis.
![light](https://d2x313g9lpht1q.cloudfront.net/original/3X/a/a/aafba8a549d3550847508abc73a68f0c3e30ed38.gif)