SPACEto play / pauseARROW RIGHTorLto go forwardARROW LEFTorJto go backwardARROW UPto increase volumeARROW DOWNto decrease volumeFto toggle fullscreenMto toggle mute0 to 9to go to the corresponding part of the videoSHIFT+,to decrease playback speedSHIFT+.or;to increase playback speed
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
The halftone is a technique used in printing to create color variations looking like gradients using a grid of points of the same color but of varying size.
Seen from far away, a combination of various halftones results in pleasant shades of colors.
Today, it’s used to create old school vibes and you can appreciate it in modern movies such as Spider‑Man: Into the Spider‑Verse.
Make sure to watch the following images in a high enough resolution to appreciate the effect:
And here is a good example of halftone implementation by @YanSculpts: https://twitter.com/YanSculpts/status/1692251937087832389
In this lesson, we are going to reproduce this effect to add shadow and reflection to our 3D objects:
Setup 02:57
The starter already contains the following:
- 3 rotating objects: a sphere, Suzanne and a torus knot
- A basic shader already included in the
src/shaders/halftone/folder with avertex.glsland afragment.glsl - Light functions from the previous lessons in the
includes/folder (we won’t be using them just yet) - An instance of
lil-gui, with two tweaks, that controls theclearColorand theuColoruniform sent to the fragment shader. - The
vite-plugin-glsldependency to handle GLSL files OrbitControlsto rotate around
Lighting 04:14
Although the halftone idea is to create shading with uniform color, we are actually going to apply it like in Spider‑Man: Into the Spider‑Verse and add it on top of a subtle light shading.
- The
vNormaland thevPositionare already sent from the vertex to the fragment. - The
viewDirectionis already calculated. - The
normalis already normalized.
We are going to use the ambient light and the directional light.
Include both light sources in fragment.glsl:
#include ../includes/ambientLight.glsl
#include ../includes/directionalLight.glsl
void main()
{
// ...
} Create a light variable to vec3(0.0) and multiply it by the color:
void main()
{
vec3 viewDirection = normalize(vPosition - cameraPosition);
vec3 normal = normalize(vNormal);
vec3 color = uColor;
// Lights
vec3 light = vec3(0.0);
color *= light;
// ...
}
Add the following ambientLight():
void main()
{
// ...
// Lights
vec3 light = vec3(0.0);
light += ambientLight(
vec3(1.0), // Light color
1.0 // Light intensity,
);
color *= light;
// ...
}
We end up with the initial color because we are using a light intensity of 1.0.
Add the following directionalLight():
void main()
{
// ...
light += directionalLight(
vec3(1.0, 1.0, 1.0), // Light color
1.0, // Light intensity
normal, // Normal
vec3(1.0, 1.0, 0.0), // Light position
viewDirection, // View direction
1.0 // Specular power
);
// ...
}
The directional light adds a subtle shading to our objects.
How to use it 🤔
- Download the Starter pack or Final project
- Unzip it
- Open your terminal and go to the unzip folder
-
Run
npm installto install dependencies
(if your terminal warns you about vulnerabilities, ignore it) -
Run
npm run devto 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