by Feiyue Zhang (2025)
Before you dive into the documentation of any 3D graphics library, here are some tips that can be very helpful if you're new to graphics programming.
Graphics programming can be very confusing if you don't know these concepts, but most docs would just assume you already know them!
Coordinates are usually used to specify the location of a 3D object. For example, a box can be placed at (0, 0, 0), the origin of the coordinate system. But what do you really mean by "origin"? Is it the location of Earth's core, my computer screen, or maybe user's eyes?
By defining different origins and orientations of the axes, we have different coordinate systems ("space"). The most common two are world space and object space.
World space: The origin is a fixed point at (0, 0, 0). It provides a common reference for all objects in a scene.
Object space: The origin is the center of the object
For example: A box is placed at (3, 2, 6) in world space, but in the box's own local space its coordinate is always (0, 0, 0).
There is no universal standard on how a 3D coordinate system is defined. You can name x, y, or z to be the axis pointing upwards. For example, Unity uses right-handed Y-up coordinate system, whereas Blender uses right-handed Z-up coordinate system.
Note that Three.js uses right-handed Y-up coordinate system!
Source: O'Reilly
When you instantiate 3D objects, they exist in your program and exist in your program ONLY — they will never show up on screens.
You need to send all those objects to a single package, and then pass it down to the renderer to draw on screen. And that single package is a scene object. It's like a container that holds all objects you want to render.
Source: CUNY
A scene alone provides not enough information for renderers to render anything. We need an eye — or a camera in graphics term!
A camera defines the viewer’s point of view, which encodes where viewers are looking from, in which direction, and with what field of view. Different camera placement results in drastically different renders.
Three.js provides multiple types of camera, but THREE.PerspectiveCamera is the most commonly used because it mimics the way the human eye sees.
In Three.js, a mesh is defined by two things: geometry and material.
Geometry is the shape of the mesh. It can be a triangle, a quad, or a set of triangles (or any other primitive shapes).
Material is the look of the mesh, including color, transparency, shininess, and how it reacts to light.
Some commonly used textures are:
MeshBasicMaterial: Does not react to light, only shows color/texture.
MeshPhongMaterial: Uses Phong model to render, less realistic but more efficient.
MeshStandardMaterial: Uses PBR (Physics based rendering) to render, more realistic but comes at higher computational cost.
MeshBasicMaterial
MeshPhongMaterial
MeshStandardMaterial
Source: Medium
After you've added objects to your scene and compiled your project, you are most likely to see a black screen. This is because there is no lighting! Lighting is a very important factor in rendering as it greatly affects how your scene looks.
There are many different types of light in Three.js, make sure you add enough light sources (at correct location) to light up the scene! And don't forget to also add lights to your scene object because they are also considered 3D objects.
Renderer handles all the heavy lifting of drawing. We need to pass a camera and a scene to the renderer for it to produce frames to display on browser.
There are different types of renderer, but THREE.WebGLRenderer is most likely the one that you need. Another renderer option is THREE.WebGPURenderer, which implements WebGPU interface rather than WebGL interface.
WebGPU is faster and bundled with more advanced features. However it's not as widely supported as WebGL. This is particularly relevant in this class because WebXR does not support WebGPU at the moment.
Why does my render look a little blurry or jagged? Possible cause:
The device pixel ratio of high-DPI screens is greater than 1, but the renderer defaults this value to 1, making the canvas contain way fewer pixels than the real screen.
Try adding this line to fix the problem: `renderer.setPixelRatio( window.devicePixelRatio );`
THREE.Group is a container for grouping multiple objects. You may ask what's it different from a set or list?
When you add objects to a group, they become part of the scene graph, meaning when you apply rotation or translation to the group, they will also be applied to all the children objects in the group. This saves you much effort to apply operations on each child and makes it easier to organize your scene.
Common pitfall:
Let's say you have a THREE.Group containing some objects, then you pass those objects to your root scene by `scene.add( group )`. Be careful about this operation because when you add, what were in the group would now be moved to the scene, which means after the operation the group would be empty.
Now you've got the very basics of rendering static scenes where objects stay stationary.
If you want to learn more about creating dynamic scenes with animation or even creating game experience, in a similar format where I make a list of tips, go to Interactive Content.