Choosing the a bcd
00:00/00:00TIME LEFT

Shortcuts ⌨️

  • SPACE to play / pause
  • ARROW RIGHT or L to go forward
  • ARROW LEFT or J to go backward
  • ARROW UP to increase volume
  • ARROW DOWN to decrease volume
  • F to toggle fullscreen
  • M to toggle mute
  • 0 to 9 to go to the corresponding part of the video
  • SHIFT + , to decrease playback speed
  • SHIFT + . or ; to increase playback speed

Subtitles 💬

Subtitles are only available for members

To get access to 72 hours of video, a members-only Discord server and future updates, join us for only $95!

Want to learn more? 👋


That's the end of the free part 😔

To get access to 72 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson

Animated galaxy

Difficulty Very hard

Starter packFinal project

Introduction 00:00

You can also use shaders with the particles. As we saw in the Particles lesson, animating each vertex of the geometry isn't an efficient solution for performance reasons. That is where the GPU comes in by animating those vertices directly in the vertex shader.

In this lesson, we are going to start with our particle galaxy. We will animate the particles in the vertex shader to make the stars rotate but at different speeds depending on the center's distance, and we will draw a pattern in the particles instead of those ugly squares.

Setup 00:31

The starter is almost the same as the Galaxy Generator lesson starter. The only difference is the spin formula is missing because we will do the spin animation in the shader.

Replacing PointsMaterial by ShaderMaterial 00:48

The particles are currently using a PointsMaterial, but we need to use a ShaderMaterial if we want to write our own shaders.

Replace PointsMaterial by ShaderMaterial:

material = new THREE.ShaderMaterial({
    // ...

If you look at the logs, you should see two warnings telling us that the ShaderMaterial supports neither size nor sizeAttenuation. We will have to add these features on our own. For now, remove these properties:

material = new THREE.ShaderMaterial({
    depthWrite: false,
    blending: THREE.AdditiveBlending,
    vertexColors: true

At this exact moment, some might see the particles like tiny red dots, and some might get a black screen. That depends on how your GPU handles the particles when no size is provided. We won't waste time on this because we will give a size anyway, and everyone should see the particles.

Clearly, we need to provide our own shaders. Add the following vertexShader:

material = new THREE.ShaderMaterial({

    // ...

    vertexShader: `
        void main()
             * Position
            vec4 modelPosition = modelMatrix * vec4(position, 1.0);
            vec4 viewPosition = viewMatrix * modelPosition;
            vec4 projectedPosition = projectionMatrix * viewPosition;
            gl_Position = projectedPosition;

             * Size
            gl_PointSize = 2.0;

The beginning of the shader is the same as we've already seen. We update the position by using successively the modelMatrix, the viewMatrix, and the projectionMatrix. But then, we assign a new variable called gl_PointSize with 2.0 as the value.

gl_PointSize is precisely what you might think. The particles will have a 2x2 size, and you should see 2x2 particles regardless of the distance of the camera.

The unit here are fragments and if you are using a normal screen with a pixel ratio of 1, you'll get 2 pixels by 2 pixels because 1 fragment = 1 pixel. But if you are using a screen with a higher pixel ratio like a retina screen, 1 fragment will be smaller than 1 pixel and you should get smaller particles. We'll fix that later in order to get a consistent result through any pixel ratio.

Before we improve the particles size, let's change the color.

The particles are currently red because we didn't provide any fragmentShader and Three.js uses a default one with a red output.

Add the following fragment shader with a white color:

material = new THREE.ShaderMaterial({

        // ...

        fragmentShader: `
            void main()
                gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);

All the particles should be white.

Want to learn more?

That's the end of the free part 😔

To get access to 72 hours of video, a members-only Discord server and future updates, join us for only $95!

How to use it 🤔

  • Download the Starter pack or Final project
  • Unzip it
  • Open your terminal and go to the unzip folder
  • Run npm install to install dependencies
    (if your terminal warn you about vulnerabilities, ignore it)
  • Run npm run dev to launch the local server
    (your browser should start automatically)
  • Start coding
  • The JS is located in src/script.js
  • The HTML is located in src/index.html
  • The CSS is located in src/style.css

If you get stuck and need help, join the members-only Discord server: