Wednesday, May 4, 2016

Why is uniform grey not a neutral DisplacementMap?

Leave a Comment

I have been trying to generate a specific feDisplacementMap and failing miserably. I believe it's because I have a fundamental misunderstanding of the mechanism. The SVG 1.1 spec says:

This filter primitive uses the pixels values from the image from ‘in2’ to spatially displace the image from ‘in’. This is the transformation to be performed:

P'(x,y) <- P( x + scale * (XC(x,y) - .5), y + scale * (YC(x,y) - .5)) where P(x,y) is the input image, ‘in’, and P'(x,y) is the destination. XC(x,y) and YC(x,y) are the component values of the channel designated by the xChannelSelector and yChannelSelector. For example, to use the R component of ‘in2’ to control displacement in x and the G component of Image2 to control displacement in y, set xChannelSelector to "R" and yChannelSelector to "G".

By my reading, this means a neutral grey image should result in no net pixel movement. Aka in a filter with scale=50, a pixel at 100,100 should get its new value from (100 + 50 * (0.5 - 0.5), 100 + 50*(0.5-0.5)) = 100,100. However when I try a greyscale, it's mapping pixels up and to the left of the source image.

<svg width="800px" height="600px" >        <defs>      <g id="displacerect">      <rect x="50" y="50" width="300" height="300" fill="rgb(127, 127, 127)"/>      <rect x="90" y="90" width="50" height="50" fill="red">        </rect>      </g>                    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">        <stop offset="0%" stop-color="rgb(255,255,0)" stop-opacity="1" />        <stop offset="100%"stop-color="rgb(255,0,0)" stop-opacity="1" />      </linearGradient>        <filter id="displaceME" x="0%" y="0%" width="100%" height="100%">      <feImage xlink:href="#displacerect"  result="displaceImage"/>      <feDisplacementMap scale="125" xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" in2="displaceImage"/>           </filter>        </defs>        <g filter="url(#displaceME)">    <rect x="50" y="50" width="300" height="300" fill="url(#grad1)"/>    </g>        <use xlink:href="#displacerect" x="400"/>             </svg>

According to other sources: the ACTUAL neutral displacement Map should be this image:

enter image description here

2 Answers

Answers 1

I can see at least one bug in your example.

In your <feDisplacementMap> you are referencing your displacement image (in2) with in2="displacerect". But there is no filter primitive with that result value. I believe you mean in2="displaceImage"?

Answers 2

It seems that browsers don't follow the spec for this, and simply duplicate the behavior of Photoshop in calculating displacement.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment