Phase 12 · part: Frame paint
Shaders with GLSL
Write the small programs the GPU runs for every vertex and pixel: GLSL, uniforms, patterns, noise, displacement and debugging, then the showroom's metal-flake paint.
Until now you used the looks three.js ships. This phase opens the box: a shader is a small program the GPU runs for every vertex and every pixel. You learn GLSL, how data reaches a shader (uniforms, attributes, varyings), how to draw patterns and noise from a few functions, how to move vertices, and how to find your mistakes when you cannot print anything.
Every topic has a live example that fails on purpose: a compile error with its real line number, a uniform that never updates, banding, stale normals, a mesh culled while it is on screen, and a phone's 16-bit precision.
The build gives the frame its paint: a metallic orange with tiny flakes and a glossy clear coat, made by editing a MeshPhysicalMaterial's shader so that lights, shadows and the environment keep working.
Phase 12 · the brief from Lumen
Ama, head of design at Lumen Bikes
“The orange looks like plastic. Real frame paint has flakes in it, and a gloss on top.”
The showroom shows the bike with loaded, compressed models and a smooth camera. Ama opens it on her desk, turns the bike under the lights and frowns. The frame is a flat, even orange. "That is not our paint," she says. "Our paint has metal flake. When the bike turns, tiny points catch the light. And there is a clear coat on top, like a car."
Kofi tries what he knows: a higher metalness, a rougher roughness, a texture of speckles. Each looks wrong in a different way. The speckle image slides when the bike turns and blurs when you zoom. Kofi realises the paint is not an image. It is a rule: for every tiny patch of the frame, pick a random tilt and let the light decide.
A rule for every pixel is what a shader is. In this phase Kofi writes his first ones, learns why they fail, and ends with the paint that makes Ama smile. By the end, the frame has flakes that glint as the bike turns, under a glossy coat, still lit by every light in the scene.
At this station
You will learn
- Write a vertex and a fragment shader in GLSL and run them
- Pass data with uniforms, attributes and varyings, and spot a forgotten update
- Draw patterns and noise, and displace vertices with the right normals
- Read a compile error and debug with colour
- Build the metal-flake paint for the frame
You write code in
In your lumen-3d project (npm run dev) and in the editor on this page
Files you touch
- src/materials/paint.glsl.js
- src/objects/bike.js
- src/main.js
Work order · 7 steps
- 12.1What a Shader IsA shader is a tiny program the GPU runs thousands of times at once: a vertex shader places each corner of a triangle, a fragment shader colours each pixel. You write them in GLSL and try them in a Shadertoy-style sandbox. 20 min 2 live scenes
- 12.2Uniforms, Attributes and VaryingsData reaches a shader in three ways: uniforms (one value for the whole draw), attributes (one per vertex) and varyings (vertex outputs blended into fragment inputs). ShaderMaterial adds helpers, RawShaderMaterial adds nothing. 22 min 3 live scenes
- 12.3Fragment PatternsWith a UV coordinate and five functions (step, smoothstep, mix, fract, mod) you can draw stripes, circles and gradients without any image. The edge case to know is banding, and dithering fixes it. 20 min 2 live scenes
- 12.4Noise and Shaping FunctionsNoise is random numbers made smooth: hash a grid, blend the corners (value noise), add smaller copies (fBm). Shaping functions bend a number's curve. Together they make clouds, rust, and the paint's metal flake. 23 min 2 live scenes
- 12.5Vertex DisplacementA vertex shader can move vertices: waves, wind, a swelling balloon. Lighting then needs a new normal, and three.js needs to know the mesh is no longer where its bounding sphere says. 20 min 2 live scenes
- 12.6Debugging ShadersYou cannot print from a shader. You read three.js's compile log with its line numbers, show values as colours, know what precision a phone really has, and treat onBeforeCompile as a powerful but fragile tool. 22 min 3 live scenes
- 12.7Build: The Metal-Flake PaintbuildThe frame gets the Lumen paint: a metallic orange with tiny flakes that glint as the bike turns, under a glossy clear coat. It is one material, still lit by the scene's lights and environment. 59 min 1 live scene
Quality control · 5 tests
Build it yourself, press Check, and the page tests the scene you made: what is in it, where it sits, what it costs the GPU.
vUv.x, fract and step.AdvancedQC-02Draw a soft orange circleDraw an orange circle (vec3(1.0, 0.42, 0.17)) of radius 0.3 in the middle of the plane, with black outside. Use length(vUv - 0.5) and smoothstep so the rim is soft.AdvancedQC-03Unfreeze a uniformThe plane should turn from black to white once a second (fract(uTime)), but it never changes. Find why and fix it without changing the shaders.AdvancedQC-04Find the vanished panelA vertex shader lifts the orange panel to the height the camera looks at, yet nothing is drawn. Make the panel appear with one line of JavaScript, without changing the shaders.AdvancedQC-05Tint a paint with onBeforeCompileThe ball uses a white MeshPhysicalMaterial. With onBeforeCompile, multiply the final colour by vec3(1.0, 0.45, 0.2) just before #include <dithering_fragment>, and give the material its own customProgramCacheKey. Keep the lighting.Advanced