As part of a project I’m working on right now, I’ve been looking at this set of SVG effects for HTML elements.
This allows us to use the turbulence effect in a broader context than simple HTML elements with relatively primitive SVG shapes, which is desirable for reasons that will be clear once the project is published and I’m able to share.
Looking at the source for the aforementioned article, I can see these distortion effects are powered by an old friend of mine – Perlin noise.
It’s been quite some time since I used Perlin noise, so after dusting off some old articles and refreshing myself with the methods and terminology, I’m equipped to run at this.
There are existing Perlin shaders out there, which I have had a play with, however none of these quite meet my needs in terms of the configurability offered by the SVG filters. I specifically need two-channel (X & Y) animated noise to pull these effects off in a post-processing context.
Luckily for us, the SVG specification provides the code used to power the turbulence effect in plain C.
Yesterday I attempted to port this into ES6 and a GLSL fragment shader. Whilst I was able to get something that looks sensible in memory and compiles properly, there are problems with the current setup.
- The gradient mapping array contains a lot of consecutive zero’s towards the end of the array. I wouldn’t expect to see this in a data set which is supposed to map random, smooth noise.
- The biggest problem of all is that running the shader gives me a black screen. Clearly this isn’t working as intended. I should be seeing a mix of values on the red and green channels.
I’ll need to grab Visual Studio C++ 2019 for this, which these days totals 8GB with all the accompanying packages.
Meanwhile, check out this quick experiment I wrote whilst waiting, perhaps this can be put to use somewhere!
I ran the code from the SVG spec in Visual Studio and I can see that I get the expected output from the random function.
Next we check the lattice selectors match.
And fix an issue to get the gradient maps to match.
Once we’ve got the exact same lookup table and gradient map going to the graphics card, a quick once over reveals a couple of missing lines due to human error on my part.
Solving the missing code finally completes this task.
This exactly matches the output of the SVG distortion functions, I’ve also added gain and lacunarity into the mix.