W3C home > Mailing lists > Public > www-svg@w3.org > February 2017

Re: Non-uniformity of feTurbulence

From: Amelia Bellamy-Royds <amelia.bellamy.royds@gmail.com>
Date: Tue, 28 Feb 2017 15:41:34 -0700
Message-ID: <CAFDDJ7yv9TTkLj7Xp_6j3j_yaUL+B5bxpKmxa2Jv4xpeCWFjwg@mail.gmail.com>
To: Yuqian Li <liyuqian@google.com>
Cc: www-svg <www-svg@w3.org>
Hi Yuqian,

Technical issues with the Filters specification are now managed on GitHub,
in the shared repo with CSS. Are you able to post this there?
https://github.com/w3c/fxtf-drafts/issues

Some questions to address, if you hope to convince implementations to
change:

   - Can you estimate how much of a performance impact this change would
   have? (That is, what proportion of vectors would need to be discarded &
   re-sampled?)
   - Can you give practical graphical examples of where it would create a
   noticeable impact on the final result?


By the way, since you've clearly dissected the algorithm more closely than
I have, I'd be glad if you could take a look at this issue I posted last
week: https://github.com/w3c/fxtf-drafts/issues/112

Best,
Amelia Bellamy-Royds

On 21 February 2017 at 11:51, Yuqian Li <liyuqian@google.com> wrote:

> As https://www.w3.org/TR/SVG/filters.html#feTurbulenceElement specifies,
> feTurbulence creates a Perlin turbulance, which should be uniform in all
> directions (fGradient should be uniformly distributed on a ball).
>
> However, it seems that the specific implementation (source code) in the
> W3C Recommendation violates such uniformity: it directly normalizes a
> random vector from [-1, -1] x [1, 1] to a unit vector (so it's uniformly
> distributed on a box, rather than a ball). It generates more diagonal
> gradient than horizontal/vertical ones. In Perlin's paper, it's recommended
> to discard vectors with length greater than 1, and only normalizes the
> remaining ones to unit vectors as the random gradient. (There are many ways
> of generating uniformly random vectors on a ball; the 3rd answer in this
> Q/A
> <http://math.stackexchange.com/questions/44689/how-to-find-a-random-axis-or-unit-vector-in-3d> is
> what's described here; it's probably the cheapest one for our 2D cases.)
>
> For the difference, please see the attached images. In
> full_original_circle.png, there are more diagonal white lines than
> vertical/horizontal lines; if we rotate it by 45 degrees, we notice a
> significant increase of vertical/horizontal lines and decrease of diagonal
> lines in full_original_circle_45.png. On the other hand, if we properly do
> the normalization (discard vectors with length greater than 1), the
> full_normalize_circle.png and full_normalize_circle_45.png both have
> similar number of diagonal lines and vertical/horizontal lines.
>
> The following is the original W3C implementation:
>
>   for(k = 0; k < 4; k++)
>   {
>     for(i = 0; i < BSize; i++)
>     {
>       uLatticeSelector[i] = i;
>       for (j = 0; j < 2; j++)
>         fGradient[k][i][j] = (double)(((lSeed = random(lSeed)) % (BSize + BSize)) - BSize) / BSize;
>       s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1]));
>       fGradient[k][i][0] /= s;
>       fGradient[k][i][1] /= s;
>     }
>   }
>
>
> And here's the properly normalized implementation that generates gradient
> uniformly in all directions:
>
>   for(k = 0; k < 4; k++)
>   {
>     for(i = 0; i < BSize; i++)
>     {
>       uLatticeSelector[i] = i;
>       for (j = 0; j < 2; j++)
>         fGradient[k][i][j] = (double)(((lSeed = random(lSeed)) % (BSize + BSize)) - BSize) / BSize;
>       s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1]));
>
>       if (s > BSize) {
>
>           i--; // discard the current random vector; try it again.
>
>           continue;
>
>       }
>
>       fGradient[k][i][0] /= s;
>       fGradient[k][i][1] /= s;
>     }
>   }
>
> Thanks,
> Yuqian
>
Received on Tuesday, 28 February 2017 22:48:44 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 22:55:08 UTC