the original tutorial by @cyanilux.bsky.social
www.cyanilux.com/tutorials/wh...
@simsure.bsky.social
๐ฎ๐น ๐พIndie game dev โhttp://ko-fi.com/simsure โกhttp://gamejolt.com/@Simsure ๐ฎhttp://simsure.itch.io
the original tutorial by @cyanilux.bsky.social
www.cyanilux.com/tutorials/wh...
That's it, hope this can help making cool whirlpool or other effects in your games. ๐โค๏ธ
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0And the final touch is making this render three times, tweaking the uniforms to have smaller, faster and more transparent foam under the main one
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0The actual color comes not from the shader but from the background texture, you can see how it gives a much better look.
The shader could be modified to make it darker the center, this is just how we did it in our game.
The result
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0// Multiply the inverted swirl with the fading circle vec4 fadedSwirl = vec4(animSwirlStepInv.rgb, 1.0) * fadeCircleInv; // Discard any non opaque pixel if(fadedSwirl.r < 0.1) discard; // Get a fading value where the center is more transparent float fadedSwirlInvValue = 1.0 - ((fadedSwirl.r + fadedSwirl.g + fadedSwirl.b) / 3.0); // Add an external opacity value float finalValue = fadedSwirlInvValue * u_opacity; // Keep the final value above 0 transparency finalValue = max(finalValue, 0.05); gl_FragColor = vec4(1.0, 1.0, 1.0, finalValue);
The final steps consist in removing transparent pixels to have a opaque foam, (thanks to the previous step we have a perfect circle and not a square)
With some final inversion and multiplication we get a single float value of our swirling foam, fading as it goes to the center
The result
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0// Use the modified polar coordinates to sample a noise texture vec4 animSwirl = texture2D(u_noise, animUv); // Use the step function to get only the white shape of the whirling "foam" float animStep = step(u_scale, animSwirl.r); vec4 animSwirlStep = vec4(animStep); // Create a fade circle image, darker on the inside and lighter on the outside. float fadeValue = pow((polarColor.r/1.0), 2.0); vec4 fadeCircle = vec4(fadeValue, fadeValue, fadeValue, 1.0); // Invert both the swirl step and the fade circle vec4 animSwirlStepInv = vec4(1.0 - animSwirlStep.rgb, 1.0); vec4 fadeCircleInv = vec4(1.0 - fadeCircle.rgb, 1.0); // Multiply the inverted swirl with the fading circle vec4 fadedSwirl = vec4(animSwirlStepInv.rgb, 1.0) * fadeCircleInv; gl_FragColor = fadedSwirl;
Now using the polarColor.r from before we generate a fading circle image, that will be used to make the edge of the whirlpool blend with the surroundings.
Get the final image by multiplying the inverted circle with the inverted image from the last step
The result
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0// Use the modified polar coordinates to sample a noise texture vec4 animSwirl = texture2D(u_noise, animUv); // Use the step function to get only the white shape of the whirling "foam" float animStep = step(u_scale, animSwirl.r); vec4 animSwirlStep = vec4(animStep); gl_FragColor = animSwirlStep;
With a step function let's get only the white "foam" form the rotating noise image
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0The result, we can already see the whirlpoolness
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0float animR = (polarColor.r * 1.5) + time; float animG = (polarColor.r * 1.5) + polarColor.g; vec2 animUv = vec2(animR, animG); animUv = vec2(fract(animR), fract(animG)); // Use the modified polar coordinates to sample a noise texture vec4 animSwirl = texture2D(u_noise, animUv); gl_FragColor = animSwirl;
Now we use a noise texture to sample the image that will be the canvas for our whirlpool,
i used a generic noise image (cloud like) found online.
The UV to use for sampling are based on the polar coordinates after some passes.
The result
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0#define PI 3.1415926538 varying vec2 v_vTexcoord; varying vec4 v_vColour; uniform sampler2D u_noise; uniform float u_time; uniform float u_scale; uniform float u_opacity; // Function to calculate the polar coordinate in a specific point vec2 polar(vec2 UV, vec2 center, float radialScale, float lengthScale) { vec2 delta = UV - center; float radius = length(delta) * 2.0 * radialScale; float angleRad = atan(delta.y, delta.x); float angle = (angleRad + PI) / (2.0 * PI) * lengthScale; return vec2(radius, angle); } void main() { // Slow down the time float time = u_time / 40000.0; // Center of the UV vec2 center = vec2(0.5,0.5); // Mirror the UV (this change the whirlpool spin direction) vec2 coord = v_vTexcoord; coord.y = 1.0 - coord.y; // Get poolar coordinate of this point vec2 polarColor = polar(coord, center, 1., 1.); gl_FragColor = vec4(polarColor.r, polarColor.g, 0.0, 1.0); }
The starting point is a polar coordinate texture, we use this custom function found online that i changed a bit to make it work correctly in GMS
07.08.2025 17:59 โ ๐ 0 ๐ 0 ๐ฌ 1 ๐ 0First of all i want to thanks @cyanilux.bsky.social, my version is a Game Maker adaptation of his whirlpool shader, and i started by following his tutorial, he make a lot of other cool stuff.
This tutorial is specific for making it work in Game Maker Studio 2
๐งต
Here's a little #tutorial for the whirlpool #shader we used in Whirloop.๐
๐๐ซ๐๐ฆ๐ข๐ฌ๐: it was made pretty fast for a game jam, it can probably be way more optimized and clean, i just fixed it a bit for this tutorial
๐๐งต
The magic of sprite stacking.
#GMTK2025 #gmtkjam #spritestack
The last layer of every stack is drawn slightly bigger and with a similar color of the water tile, when the last layer change, it looks like the water adapt perfecly to the object, like an outline.
05.08.2025 16:28 โ ๐ 0 ๐ 0 ๐ฌ 0 ๐ 0A simple trick in Whirloop to give the illusion of water around objects.
itch.io/jam/gmtk-202...
pixeltentacles.itch.io/whirloop
#GMTKJam #GMTK2025 #spritestack #loop
The last layer of every stack is drawn slightly bigger and with a similar color of the water tile, when the last layer change, it looks like the water adapt perfecly to the object, like an outline.
05.08.2025 16:27 โ ๐ 0 ๐ 0 ๐ฌ 0 ๐ 0Me an Wah made this little game for the #GMTKJam
You can try and rate it on the jam page.
Has been fun i'm really happy with the final result of just two days of work.
itch.io/jam/gmtk-202...
pixeltentacles.itch.io/whirloop
#GMTK2025 #spritestack #loop
Dinosaur game! I'm putting it on hold for now, but I had a lot of fun animating all these guys.
02.03.2025 12:19 โ ๐ 592 ๐ 144 ๐ฌ 18 ๐ 4