From our sponsor: Ready to show your plugin skills? Enter the Penpot Plugins Contest (Nov 15-Dec 15) to win cash prizes!
Everybody loves images. They are bright and colorful and we can do fun things with them. Even text sometimes strives to be an image:
|\_/| | @ @ Woof! | <> _ | _/\------____ ((| |)) | `--' | ____|_ ___| |___.' /_/_____/____/_______|
Once you want to show more than one image, you can’t help making a transition between them. Or is it just me?
Jokes aside, image transitions are all over the web. They can be powered by CSS, SVG or WebGL. But of course, the most efficient way to work with graphics in the browser is using the Graphics Processor, or GPU. And the the best way to do this is with WebGL, specifically with shaders written in GLSL.
Today we want to show you some interesting image transition experiments that reveal the boundless possibilities of WebGL. These effects were inspired by the countless incredible design examples and effects seen on websites like The Avener and Oversize Studio.
Setup
I will be using the Three.js framework for my transitions. It doesn’t really matter what library you use, it could have also been the amazing Pixi.js library, or simply (but not so straightforward) native WebGL. I’ve used native WebGL in my previous experiment, so this time I’m going to use Three.js. It also seems most beginner friendly to me.
Three.js uses concepts like Camera, Scene and Objects. We will create a simple Plane object, add it to Scene and put it in front of the Camera, so that it is the only thing that you can see. There is a template for that kind of object, PlaneBufferGeometry:
To cover the whole screen with a plane you need a little bit of geometry. The Camera has a fov (field of view), and the plane has a size. So with some calculations you can get it to fill your whole screen:
camera.fov = 2*(180/Math.PI)*Math.atan(PlaneSize/(2*CameraDistance));
Looks complicated, but it’s just getting the angle(fov), knowing all the distances here:
That is actually the end of the 3D part, everything else will be happening in 2D.
GLSL
In case you are not yet familiar with this language, I highly advise you to check out the wonderful Book Of Shaders.
So, we have a plane and we have a fragment shader attached to it that calculates each pixels color. How do we make a transition? The simplest one done with a shader looks like this:
void main() {
vec4 image1 = texture2D(texture1,uv);
vec4 image2 = texture2D(texture2,uv);
gl_FragColor = mix(image1, image2, progress);
}
Where progress
is a number between 0 and 1, indicating the progress of the animation.
With that kind of code you will get a simple fade transition between images. But that’s not that cool, right?
Cool transitions
Usually all transitions are based on changing so called UVs, or the way texture is wrapped on the plane. So for instance, multiplying UV scales the image, adding a number just shifts the image on the plane.
UVs are nothing magical. Think of them as a coordinate system for pixels on a plane:
Let’s start with some basic code:
gl_FragColor = texture2D(texture,uv);
This just shows an image on the screen. Now let’s adjust that code a bit:
gl_FragColor = texture2D(texture,fract(uv + uv));
By taking the fractional part, we make sure that all the values stay between 0 and 1. And if UV was from 0 to 1, doubling it means it will be from 0 to 2, so we should see the fractional part changing from 0 to 1, and from 0 to 1 again!
And that’s what you get: a repeated image. Now let’s try something different: subtracting UV and using the progress for the animation:
gl_FragColor = texture2D(texture, uv - uv * vec2(1.,0) * progress * 0.5);
First, we make sure that we are only changing one axis of UV, by multiplying it with vec2(1.,0). So, when the progress is 0, it should be the default image. Let’s see:
Now we can stretch the image! Let’s combine those two effects into one.
gl_FragColor = texture2D(uTextureOne, uv - fract(uv * vec2(5.,0.)) * progress * 0.1 );
So basically, we do the stretching and repeat it 5 times. We could use any other number as well.
Much better! Next, if we add another image, we get the effect that you can see in demo 7.
Cool isn’t it? Just two simple arithmetic operations, and you get an interesting transition effect.
That’s just one way of changing UVs. Check out all the other demos, and try to guess what’s the math behind them! Try to come up with your own unique animation and share it with me!
References and Credits
- three.js
- GL Transitions
- Images from Unsplash
I lvoe these effects, would be so cool if there was a tutorial on how to make this transtiion on drag in a infinite slider of sorts! Any ideas on how I could implement this?
Same here would be amazing with a timed delay or something similar
all of the transitions are just 0 to 1 animations, so if you use same arithmetic “API” in your slider, it would just work.
Très cool! Thanks for sharing!
Mhh, the source files doesn’t work for me, I only get a black screen. What’s wrong?
Hi David, you need to run the examples from a local web server: https://threejs.org/docs/#manual/en/introduction/How-to-run-things-locally Hope this helps, cheers, ML
Okay thanks. And why it doesn’t work on my webspace? https://rooosh.com/playground/web/webGL/index6.html
Hello,
You just need to change the revelative path URL to absolute path URL
Hope this helps !
Thanks Yuriy! I will have to use this in a future project!
Hello,
First of all thanks to you Yuriy !
I’ve a question, is there a way to create the transition animation on div element instead only the image ?
For example I would like to create the transition from slider_1 to slider_2 etc.
Thanks in advance for your help !
Sorry but my comment (code) was deleted.
If we consider that we have 3 divs with this following IDs “slider_1”, “slider_2”, “slider_3”
How can I create the transition from slider_1 to slider_2 etc ?
Actually we can only create this transition on the images.
Thanks in advance
I upload the files on my server but show this message on my console “Failed to load resource: the server responded with a status of 404 (Not Found)”… I just copy and paste your folder… ]
I am not a developer, for this reason, would be great if you can tell me exactly which file and what I have to change to make the URL works.
You need absolute path URL for images and js files.