SPACE
to play / pauseARROW RIGHT
orL
to go forwardARROW LEFT
orJ
to go backwardARROW UP
to increase volumeARROW DOWN
to decrease volumeF
to toggle fullscreenM
to toggle mute0 to 9
to go to the corresponding part of the videoSHIFT
+,
to decrease playback speedSHIFT
+.
or;
to increase playback speed
Shortcuts ⌨️
⚠️ Update
In the latest versions of Three.js, we need to output the colors in sRGB
color space.
To do that, add the following line at the end of the fragment shader.
void main()
{
// ...
#include <colorspace_fragment>
}
You’ll discover what this #include
is later in the course.
Colors might look slightly different from the lesson, but you’ll be able to tweak them.
Unlock content 🔓
To get access to 93 hours of video, a members-only Discord server, subtitles, lesson resources, future updates and much more join us for only $95!
Want to learn more? 👋
That's the end of the free part 😔
To get access to 93 hours of video, a members-only Discord server and future updates, join us for only $95!
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);
#include <colorspace_fragment>
}
`
})
All the particles should be white.
As we’ve seen in a previous lesson, #include <colorspace_fragment>
output the color in sRGB
so that it matches WebGLRenderer
color space which improves color management.
void main()
{
// ...
#include <colorspace_fragment>
}
You’ll discover what this #include
is later in the course.
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 warns you about vulnerabilities, ignore it) -
Run
npm run dev
to launch the local server
(project should open on your default browser 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