TLDR: up to at least Chrome 111 some Mac users can’t get consistent <feDisplacementMap>
filter results unless their monitor profile is sRGB or they have hardware acceleration turned off. Safari and FF are fine. Non-Mac users also seem to be fine.
Displacement filter distorts one image (A) using information from another image (D). Since we can displace only using two axis, displacement map only takes two of three color channels from image D.
First, let’s assume both images are of same dimensions. So what filter does for each {x,y}
pair of coordinates:
x,y
dx
and dy
to taken values, as int8
(from -128 to 127)dx
and dy
to a desired scaled range, ie [-50;50]
x+dx,y+dy
x,y
of the result.So Displacement Map filter moves pixels of image A to distances provided by D. Crafting different maps one can distort image geometries in all possible ways: scale, rotate, fisheye, and all of that sort. Distortions are easily animated.
The only caveat – rough, jagged edges. We can only shift a pixel to integer number of steps, no interpolation.
Basically, according to MDN, displacement map filter directive requires several arguments:
Note very important color-interpolation-filters="sRGB"
attribute. Its absense makes displacement map nearly useless: very few have linearRGB images, which is default for the filter.
So, in theory, if we make our displacement map a rectangle with top to bottom gradient in R channel from 0 to 255, and B channel set to constant 128 value, we can do image slant. And, what is important, we do not use G channel for displacement, at all. Green levels can’t affect result.
Or can they?
All three graphs below should look the same: straight diagonal line from bottom left to top right corner, with slightly jagged edges.
It should look like this
We transform vertical line with data from R channels of three gradients. Gradients are provided as PNG images, they are not generated in place.
Red channels in all three images are identical gradient, from 0 at the top to 255 at the bottom. Blue is completely constant and set to 128. Only green channels are different: 0 for 1st image, 128 for 2nd and 255 for 3rd.
In FF and Safari all three graphs are ok.
Old Air 11 screen can’t cover entire sRGB, so Chrome clips
iMac has very vivid green, which affects all channels
In Chrome 110…111 on Mac I clearly see all three graphs are different. Looks like Chrome first transforms source image from sRGB to monitor profile – and takes result as a displacement map. Pixel RGB values changes during conversion which causes channel intermix, distortions, downscaling and clipping in arbitrary fashion.
MacOS is such a great system you can switch your monitor color profile – and get new distortion in Chrome immediately.
Chrome shouldn’t color transform displacement map source. This issue makes feDispalacementMap
very hard to use, unfortunately. The feature is very useful for displaying vector fields action, which looks especially bizzare with animation.
There’s a way to somewhat cover the issue: use RB channels, possibly repeating R to G or zeroing G out completely. Downscaling distances to move them closer to center, with scale increase, also helps.
ermouth, 2023-03-25