Animating Netflix Pre-Roll with a WebGL Fragment Shader

In this tutorial you'll learn how to create video-like animations, using WebGL fragment shaders and HTML canvas.

This is the last part of a series of 4 articles - if you jut landed here you may want to start there instead





When animating in 2D there are a couple major tools you will likely want on your belt: scale and rotation .

Enter the matrix!

In GLSL, rotation and scale are processed very efficiently using matrices . Let's first define them:

Rotation Matrix

mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); }

Scale Matrix

mat2 scale2D(vec2 _scale){ return mat2(_scale.x, 0.0, 0.0, _scale.y); }

See it in action

Here is how we would downScale the scene by 2.2 with an anchor point at the middle of the screen:

float downScale = 2.2; st -= vec2(0.5); st = scale2D(vec2(downScale)) * st; st += vec2(0.5);

More tools for your belt

floor find the nearest integer less than or equal to the parameter,

find the nearest integer less than or equal to the parameter, fract compute the fractional part of the argument,

compute the fractional part of the argument, mod compute value of one parameter modulo another.

Putting it all together

With this knowledge in hand we can now better understand how the background texture is generated and applied to the shapes.

create the background

vec3 makeBackground (vec2 st, float angle, float progress) { // apply the rotation around the center st -= vec2(0.5, 0.5); st = rotate2d(angle) * st; st += vec2(0.5, 0.5); // scale st up to create a repeated pattern st.x *= 100.0; // get the fractional coords vec2 ipos = fract(st); // use sin with the x position on screen to progressively change the background st.x += sin(st.x) * sin(25.0 + progress * 150.0) * 4.0; // get the integer coords ipos = floor(st); if (random(ipos) < 0.2) { return vec3(0); } // use random to vary the output return vec3( mod(random(ipos+ 1.0)*4.0, 1.0) * 0.5, mod(random(ipos+ 1.0)*8.0, 1.0) * 0.25, mod(random(ipos+ 1.0)*16.0, 1.0) * 0.75 ); }

Once the color is computed, we apply it to our shape, for example on the right bar of the letter N , we apply the color starting at 4 second, and fully visible by 6 seconds.

nRight = mix( nRight, makeBackground(st, 0.0, 0.5), mapTime(4.0, 6.0, u_time + st.y / 2.0) );

Notice how we apply an angle of 0.42 radians on the oblique bar of the letter N :

nMid = mix( nMid, makeBackground(st, 0.42, 0.5), mapTime(4.25, 6.25, u_time - st.y / 2.0) );

Just like a lego project, we build our creation combining one piece after another.

That's it for today!

This concludes this series of articles on animating in a fragment shader, hopefully you learned something and are now feeling creative!

Revisit other chapters: Intro

We'll go over the basics and project setup.

We'll go over the basics and project setup. Hulu

Next we'll look into drawing shapes and controlling time in animation.

Next we'll look into drawing shapes and controlling time in animation. HBO

We'll reiterate these techniques and take a dive into noise functions.

We'll reiterate these techniques and take a dive into noise functions. checkout full source

Hope you enjoyed this tutorial! The stuff I write about is a way for me to improve my learnings - probably just like you right now. So please if you catch any issue or want to suggest an edit, use the section below or reach out on twitter. Cheers!