r/vulkan • u/wonkey_monkey • 1d ago
Inexplicable behaviour from a simple smooth noise function when run in Vulkan (works as expected in WebGL)
I've been experimenting with Vulkan by compiling and running some ShaderToy shaders. It's mostly working fine, but I've come across a smooth noise function that doesn't seem to be behaving as it should under Vulkan (but looks fine in WebGL).
The functions in question are:
float hash( vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
vec2 i = floor( p );
vec2 f = fract( p );
vec2 u = f*f*(3.0-2.0*f);
return -1.0+2.0*mix(
mix(hash(i + vec2(0.0,0.0)), hash(i + vec2(1.0,0.0)), u.x),
mix(hash(i + vec2(0.0,1.0)), hash(i + vec2(1.0,1.0)), u.x),
u.y);
}
By calling noise with a vector, the idea is that you get cubically smoothed noise. Here's the kind of result you get in WebGL when the vector ranges from 0-8 in both x and y coordinates:
https://i.ibb.co/bjSQVvvV/image.png
But here's what happens compiling and running the same shader in Vulkan:
https://i.ibb.co/TDsK6f3D/image.png
If you change the noise function the following:
float noise( in vec2 p ) {
vec2 i = floor( p );
return hash(i + vec2(0.0, 0.0));
}
...it shows you the solid blocks of pseudorandom noise from the hash function which are the basis of the smoothed version:
Now if you change the added vector to vec2(0.0, 1.0), the pattern shifts vertically, as you might expect:
https://i.ibb.co/m3Gy4SH/vertical.gif
But if you change the vector to vec2(1.0, 0.0), the pattern does shift horizontally, but this time not all blocks have the shifted value:
https://i.ibb.co/BHNjQL5N/horizontal.gif
Even more oddly, if you put p += vec2(1.0, 0.0); right at the top of function, instead of adding vec(1.0, 0.0) to the floored value (i), it returns the expected pattern with no errors.
Does anyone know what's going on? Somehow, adding 1.0 to a floored value isn't sending x+1.0 to the function...
Edit: just found out this fixes it, somehow:
return hash(floor(i + vec2(1.0, 0.0))); // can also just use the unfloored p instead i
How can i [= floor(p)] + vec2(1.0, 0.0) not be equal to floor(i + vec2(1.0, 0.0)?