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
Three.js documentation
- BufferGeometry
- PointsMaterial
- ShaderMaterial
- Points
- Uniform
- Vector2
- Vector3
- Spherical
- Color
- How to dispose of objects
- Sky (code)
GLSL functions
Others
Shortcuts ⌨️
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
In this lesson we are going to create fireworks whenever the user clicks on the screen:
The trick here is that we are going to use particles and animate them in a single vertex shader.
- The particles start to expand fast in every direction
- They scale up even faster
- They start to fall down slowly
- They scale down
- They twinkle as they disappear
That doesn’t look too complicated, now does it? Remember that we need to do that in the vertex shader in order to achieve good performance, meaning that the same code will be executed for all particles.
Also, all the previously mentioned animation steps are intertwined, and we need to find a way to handle the various steps while combining them.
At the very end, we are going to implement a sky background as a bonus.
Setup 02:09
We get the usual simple setup with a few things to note:
- One test cube to make sure that the experience is running properly
- An instance of
lil-gui
that we are going to use for the sky - The
vite-plugin-glsl
dependency to handle GLSL files OrbitControls
to rotate aroundTextureLoader
that is ready to load some fancy particle texturesgsap
in the dependencies that we are going to use to animate one single property
Base particles 02:57
Let’s create the particles instead of that cube.
Remove the whole Test
section with the cube and create a Fireworks
section instead, right before the Animate
section:
/**
* Fireworks
*/
We are going to have a black screen for a few minutes.
Since we need to create a new firework on each click, we better set a function for it.
Create a createFirework
function and call it immediately:
const createFirework = () =>
{
}
createFirework()
We are going to add various parameters as we go such as the position, the radius, the amount of particles, etc.
Most of the following code will be inside createFirework
.
Geometry
We are going to instantiate the usual BufferGeometry and fill it with random positions, but first, we need to know how many particles we want.
Add a count
parameter to the createFirework
function and set it to 100
when calling the function:
const createFirework = (count) =>
{
}
createFirework(100)
Don’t worry, we are going to add a lot more soon.
Now create a positionsArray
using a Float32Array
with a length of count * 3
since we need 3 values per vertex (xyz
):
const createFirework = (count) =>
{
// Geometry
const positionsArray = new Float32Array(count * 3)
}
Loop from 0
to count
, create an i3
which is i * 3
so that we have a value going 3
by 3
and fill the positionsArray
array with random values:
const createFirework = (count) =>
{
// Geometry
const positionsArray = new Float32Array(count * 3)
for(let i = 0; i < count; i++)
{
const i3 = i * 3
positionsArray[i3 ] = Math.random()
positionsArray[i3 + 1] = Math.random()
positionsArray[i3 + 2] = Math.random()
}
}
We are moving swiftly through this because we have done it multiple times before. But to put it in a nutshell: each loop corresponds to one vertex. For now, we’re filling the array with random positions, but later we will send more specific coordinates.
Subtract 0.5
to each Math.random()
so that values are as much positive as negative:
const createFirework = (count) =>
{
// Geometry
const positionsArray = new Float32Array(count * 3)
for(let i = 0; i < count; i++)
{
const i3 = i * 3
positionsArray[i3 ] = Math.random() - 0.5
positionsArray[i3 + 1] = Math.random() - 0.5
positionsArray[i3 + 2] = Math.random() - 0.5
}
}
We can now create the actual BufferGeometry:
const createFirework = (count) =>
{
// ...
const geometry = new THREE.BufferGeometry()
}
Then, add a 'position'
attribute to it using a Float32BufferAttribute
:
const createFirework = (count) =>
{
// ...
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positionsArray, 3))
}
3
corresponds to the itemSize
and indicates that we have 3 values per vertex (because xyz
).
Material
For the material, let’s not rush anything and start with a PointsMaterial, which we will later replace with a ShaderMaterial:
const createFirework = (count) =>
{
// ...
// Material
const material = new THREE.PointsMaterial()
}
Points
We can finally create the particles that we are going to name firework
(singular) and use a Points instance, then add()
it to the scene:
const createFirework = (count) =>
{
// ...
// Points
const firework = new THREE.Points(geometry, material)
scene.add(firework)
}
Finally, we’re getting something on screen, and we have a long and exciting road ahead.
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