Lesson 3 of 5
Your First Scene
A lit cube turning in space, in about fifteen lines. Same graphics card, none of the shaders written by hand.
What you will learn
- import maps
- Scene
- PerspectiveCamera
- WebGLRenderer
- geometry and material
- Mesh
- DirectionalLight
- delta time
Before you start
The two WebGL lessons. You do not need them to run this page, but the point of the lesson is what is no longer here.
What changed
This page draws a lit cube that turns. It is doing far more than the triangle did, and the code is much shorter. There are no shaders in this file. There are no buffers, no attributes, and no drawArrays.
All of those things are still happening. three.js writes the shaders and fills the buffers for you. That is what a library is. The reason the last two lessons were worth the trouble is that you now know what is under this one.
Where three.js comes from
This is the first page in the whole site that depends on something outside its own folder.
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.185.1/build/three.module.js"
}
}
</script>An import map says where a name comes from. Without it, import * as THREE from "three" sends the browser looking for a folder called three next to the page, and it finds nothing. The import map turns the bare name into a real address.
The version number is pinned on purpose. three.js publishes a new release most months, and some of them rename things. A lesson that says latest is a lesson that breaks by itself one morning, with no change from you.
The three things every scene has
| What it is | |
|---|---|
Scene | The list of everything in the world. |
Camera | Where you are looking from, and how wide. |
Renderer | The thing that turns those two into pixels. |
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 100);
var renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.render(scene, camera);Nothing appears until something calls render. A scene full of objects with no render call is a black canvas, and so is a render call with the camera inside the object.
45is how wide the view is, in degrees. It works like a zoom.WIDTH / HEIGHTis the shape of the picture. Get it wrong and everything is stretched.0.1and100are the nearest and furthest anything is drawn. Anything closer or further away vanishes.
Move the camera, change the spin
The camera distance is the interesting one. The box never changes size. You move.
How far back you stand. The box does not change size. You do.
Geometry plus material
var geometry = new THREE.BoxGeometry(1.4, 1.4, 1.4);
var material = new THREE.MeshStandardMaterial({ color: BOX_COLOUR });
var box = new THREE.Mesh(geometry, material);
scene.add(box);A mesh is always exactly two things joined: a geometry, which is the shape, and a material, which is what the surface is like. Every visible object in three.js is these two things. Swap either one and you get a different object.
Try swapping BoxGeometry for SphereGeometry, then for TorusKnotGeometry. One word each time, and the material never changes.
Paint it
Move these and watch your page. The code changes too.
The mistake everybody makes once
Comment out both lights and run it. Sit with the black screen for a moment, because you will see it again. Then put them back.
var lamp = new THREE.DirectionalLight("#ffffff", 3);
lamp.position.set(2, 3, 4);
scene.add(lamp);
scene.add(new THREE.AmbientLight("#ffffff", 0.4));The directional light comes from one direction, like the sun, and it is what makes one face of the cube brighter than another. The ambient light comes from everywhere at once, and its only job is to stop the dark faces being pure black.
Turning at the same speed everywhere
var seconds = clock.getDelta();
box.rotation.y += SPIN_Y * seconds * Math.PI * 2;getDelta() is the seconds since the last frame. Turning the box by a fixed amount per frame would spin it twice as fast on a 120 Hz screen as on a 60 Hz one. Multiplying by the time since the last frame makes the speed the same on every machine. The platformer course makes the same point about movement, and it is the same fix.
Try these changes
Make these changes in the files beside this guide. Each one only uses what this lesson has already covered. Tick each one when it works.
Check yourself
Three quick questions on this lesson. Get them all right to finish the lesson and earn a pack.
Loading your answers
Teacher's versionHow to run this lesson, what to check, and any answers. Students do not need this.
How to teach it
- Put the triangle from lesson 1 on the screen next to this one. Count the lines out loud. That comparison is the lesson.
- Turn the lights off as a class exercise, not as a warning. The black screen has to be experienced or the sentence does not stick.
- Do the geometry swaps live. Three swaps, one word each, and the material untouched. It teaches the geometry and material split faster than any explanation.
- The camera distance slider is worth two minutes on its own. Students expect the box to get bigger. Ask what is actually changing.
- If the page does not load, check three things in this order: is it being served rather than opened as a file, is the network blocking the CDN, and is
type="module"on the script tag.