Three.js Fundamentals
Quick Start
javascript
1import * as THREE from "three";
2
3// Create scene, camera, renderer
4const scene = new THREE.Scene();
5const camera = new THREE.PerspectiveCamera(
6 75,
7 window.innerWidth / window.innerHeight,
8 0.1,
9 1000,
10);
11const renderer = new THREE.WebGLRenderer({ antialias: true });
12
13renderer.setSize(window.innerWidth, window.innerHeight);
14renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
15document.body.appendChild(renderer.domElement);
16
17// Add a mesh
18const geometry = new THREE.BoxGeometry(1, 1, 1);
19const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
20const cube = new THREE.Mesh(geometry, material);
21scene.add(cube);
22
23// Add light
24scene.add(new THREE.AmbientLight(0xffffff, 0.5));
25const dirLight = new THREE.DirectionalLight(0xffffff, 1);
26dirLight.position.set(5, 5, 5);
27scene.add(dirLight);
28
29camera.position.z = 5;
30
31// Animation loop
32function animate() {
33 requestAnimationFrame(animate);
34 cube.rotation.x += 0.01;
35 cube.rotation.y += 0.01;
36 renderer.render(scene, camera);
37}
38animate();
39
40// Handle resize
41window.addEventListener("resize", () => {
42 camera.aspect = window.innerWidth / window.innerHeight;
43 camera.updateProjectionMatrix();
44 renderer.setSize(window.innerWidth, window.innerHeight);
45});
Core Classes
Scene
Container for all 3D objects, lights, and cameras.
javascript
1const scene = new THREE.Scene();
2scene.background = new THREE.Color(0x000000); // Solid color
3scene.background = texture; // Skybox texture
4scene.background = cubeTexture; // Cubemap
5scene.environment = envMap; // Environment map for PBR
6scene.fog = new THREE.Fog(0xffffff, 1, 100); // Linear fog
7scene.fog = new THREE.FogExp2(0xffffff, 0.02); // Exponential fog
Cameras
PerspectiveCamera - Most common, simulates human eye.
javascript
1// PerspectiveCamera(fov, aspect, near, far)
2const camera = new THREE.PerspectiveCamera(
3 75, // Field of view (degrees)
4 window.innerWidth / window.innerHeight, // Aspect ratio
5 0.1, // Near clipping plane
6 1000, // Far clipping plane
7);
8
9camera.position.set(0, 5, 10);
10camera.lookAt(0, 0, 0);
11camera.updateProjectionMatrix(); // Call after changing fov, aspect, near, far
OrthographicCamera - No perspective distortion, good for 2D/isometric.
javascript
1// OrthographicCamera(left, right, top, bottom, near, far)
2const aspect = window.innerWidth / window.innerHeight;
3const frustumSize = 10;
4const camera = new THREE.OrthographicCamera(
5 (frustumSize * aspect) / -2,
6 (frustumSize * aspect) / 2,
7 frustumSize / 2,
8 frustumSize / -2,
9 0.1,
10 1000,
11);
ArrayCamera - Multiple viewports with sub-cameras.
javascript
1const cameras = [];
2for (let i = 0; i < 4; i++) {
3 const subcamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
4 subcamera.viewport = new THREE.Vector4(
5 Math.floor(i % 2) * 0.5,
6 Math.floor(i / 2) * 0.5,
7 0.5,
8 0.5,
9 );
10 cameras.push(subcamera);
11}
12const arrayCamera = new THREE.ArrayCamera(cameras);
CubeCamera - Renders environment maps for reflections.
javascript
1const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);
2const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
3scene.add(cubeCamera);
4
5// Use for reflections
6material.envMap = cubeRenderTarget.texture;
7
8// Update each frame (expensive!)
9cubeCamera.position.copy(reflectiveMesh.position);
10cubeCamera.update(renderer, scene);
WebGLRenderer
javascript
1const renderer = new THREE.WebGLRenderer({
2 canvas: document.querySelector("#canvas"), // Optional existing canvas
3 antialias: true, // Smooth edges
4 alpha: true, // Transparent background
5 powerPreference: "high-performance", // GPU hint
6 preserveDrawingBuffer: true, // For screenshots
7});
8
9renderer.setSize(width, height);
10renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
11
12// Tone mapping
13renderer.toneMapping = THREE.ACESFilmicToneMapping;
14renderer.toneMappingExposure = 1.0;
15
16// Color space (Three.js r152+)
17renderer.outputColorSpace = THREE.SRGBColorSpace;
18
19// Shadows
20renderer.shadowMap.enabled = true;
21renderer.shadowMap.type = THREE.PCFSoftShadowMap;
22
23// Clear color
24renderer.setClearColor(0x000000, 1);
25
26// Render
27renderer.render(scene, camera);
Object3D
Base class for all 3D objects. Mesh, Group, Light, Camera all extend Object3D.
javascript
1const obj = new THREE.Object3D();
2
3// Transform
4obj.position.set(x, y, z);
5obj.rotation.set(x, y, z); // Euler angles (radians)
6obj.quaternion.set(x, y, z, w); // Quaternion rotation
7obj.scale.set(x, y, z);
8
9// Local vs World transforms
10obj.getWorldPosition(targetVector);
11obj.getWorldQuaternion(targetQuaternion);
12obj.getWorldDirection(targetVector);
13
14// Hierarchy
15obj.add(child);
16obj.remove(child);
17obj.parent;
18obj.children;
19
20// Visibility
21obj.visible = false;
22
23// Layers (for selective rendering/raycasting)
24obj.layers.set(1);
25obj.layers.enable(2);
26obj.layers.disable(0);
27
28// Traverse hierarchy
29obj.traverse((child) => {
30 if (child.isMesh) child.material.color.set(0xff0000);
31});
32
33// Matrix updates
34obj.matrixAutoUpdate = true; // Default: auto-update matrices
35obj.updateMatrix(); // Manual matrix update
36obj.updateMatrixWorld(true); // Update world matrix recursively
Group
Empty container for organizing objects.
javascript
1const group = new THREE.Group();
2group.add(mesh1);
3group.add(mesh2);
4scene.add(group);
5
6// Transform entire group
7group.position.x = 5;
8group.rotation.y = Math.PI / 4;
Mesh
Combines geometry and material.
javascript
1const mesh = new THREE.Mesh(geometry, material);
2
3// Multiple materials (one per geometry group)
4const mesh = new THREE.Mesh(geometry, [material1, material2]);
5
6// Useful properties
7mesh.geometry;
8mesh.material;
9mesh.castShadow = true;
10mesh.receiveShadow = true;
11
12// Frustum culling
13mesh.frustumCulled = true; // Default: skip if outside camera view
14
15// Render order
16mesh.renderOrder = 10; // Higher = rendered later
Coordinate System
Three.js uses a right-handed coordinate system:
- +X points right
- +Y points up
- +Z points toward viewer (out of screen)
javascript
1// Axes helper
2const axesHelper = new THREE.AxesHelper(5);
3scene.add(axesHelper); // Red=X, Green=Y, Blue=Z
Math Utilities
Vector3
javascript
1const v = new THREE.Vector3(x, y, z);
2v.set(x, y, z);
3v.copy(otherVector);
4v.clone();
5
6// Operations (modify in place)
7v.add(v2);
8v.sub(v2);
9v.multiply(v2);
10v.multiplyScalar(2);
11v.divideScalar(2);
12v.normalize();
13v.negate();
14v.clamp(min, max);
15v.lerp(target, alpha);
16
17// Calculations (return new value)
18v.length();
19v.lengthSq(); // Faster than length()
20v.distanceTo(v2);
21v.dot(v2);
22v.cross(v2); // Modifies v
23v.angleTo(v2);
24
25// Transform
26v.applyMatrix4(matrix);
27v.applyQuaternion(q);
28v.project(camera); // World to NDC
29v.unproject(camera); // NDC to world
Matrix4
javascript
1const m = new THREE.Matrix4();
2m.identity();
3m.copy(other);
4m.clone();
5
6// Build transforms
7m.makeTranslation(x, y, z);
8m.makeRotationX(theta);
9m.makeRotationY(theta);
10m.makeRotationZ(theta);
11m.makeRotationFromQuaternion(q);
12m.makeScale(x, y, z);
13
14// Compose/decompose
15m.compose(position, quaternion, scale);
16m.decompose(position, quaternion, scale);
17
18// Operations
19m.multiply(m2); // m = m * m2
20m.premultiply(m2); // m = m2 * m
21m.invert();
22m.transpose();
23
24// Camera matrices
25m.makePerspective(left, right, top, bottom, near, far);
26m.makeOrthographic(left, right, top, bottom, near, far);
27m.lookAt(eye, target, up);
Quaternion
javascript
1const q = new THREE.Quaternion();
2q.setFromEuler(euler);
3q.setFromAxisAngle(axis, angle);
4q.setFromRotationMatrix(matrix);
5
6q.multiply(q2);
7q.slerp(target, t); // Spherical interpolation
8q.normalize();
9q.invert();
Euler
javascript
1const euler = new THREE.Euler(x, y, z, "XYZ"); // Order matters!
2euler.setFromQuaternion(q);
3euler.setFromRotationMatrix(m);
4
5// Rotation orders: 'XYZ', 'YXZ', 'ZXY', 'XZY', 'YZX', 'ZYX'
Color
javascript
1const color = new THREE.Color(0xff0000);
2const color = new THREE.Color("red");
3const color = new THREE.Color("rgb(255, 0, 0)");
4const color = new THREE.Color("#ff0000");
5
6color.setHex(0x00ff00);
7color.setRGB(r, g, b); // 0-1 range
8color.setHSL(h, s, l); // 0-1 range
9
10color.lerp(otherColor, alpha);
11color.multiply(otherColor);
12color.multiplyScalar(2);
MathUtils
javascript
1THREE.MathUtils.clamp(value, min, max);
2THREE.MathUtils.lerp(start, end, alpha);
3THREE.MathUtils.mapLinear(value, inMin, inMax, outMin, outMax);
4THREE.MathUtils.degToRad(degrees);
5THREE.MathUtils.radToDeg(radians);
6THREE.MathUtils.randFloat(min, max);
7THREE.MathUtils.randInt(min, max);
8THREE.MathUtils.smoothstep(x, min, max);
9THREE.MathUtils.smootherstep(x, min, max);
Common Patterns
Proper Cleanup
javascript
1function dispose() {
2 // Dispose geometries
3 mesh.geometry.dispose();
4
5 // Dispose materials
6 if (Array.isArray(mesh.material)) {
7 mesh.material.forEach((m) => m.dispose());
8 } else {
9 mesh.material.dispose();
10 }
11
12 // Dispose textures
13 texture.dispose();
14
15 // Remove from scene
16 scene.remove(mesh);
17
18 // Dispose renderer
19 renderer.dispose();
20}
Clock for Animation
javascript
1const clock = new THREE.Clock();
2
3function animate() {
4 const delta = clock.getDelta(); // Time since last frame (seconds)
5 const elapsed = clock.getElapsedTime(); // Total time (seconds)
6
7 mesh.rotation.y += delta * 0.5; // Consistent speed regardless of framerate
8
9 requestAnimationFrame(animate);
10 renderer.render(scene, camera);
11}
Responsive Canvas
javascript
1function onWindowResize() {
2 const width = window.innerWidth;
3 const height = window.innerHeight;
4
5 camera.aspect = width / height;
6 camera.updateProjectionMatrix();
7
8 renderer.setSize(width, height);
9 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
10}
11window.addEventListener("resize", onWindowResize);
Loading Manager
javascript
1const manager = new THREE.LoadingManager();
2
3manager.onStart = (url, loaded, total) => console.log("Started loading");
4manager.onLoad = () => console.log("All loaded");
5manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);
6manager.onError = (url) => console.error(`Error loading ${url}`);
7
8const textureLoader = new THREE.TextureLoader(manager);
9const gltfLoader = new GLTFLoader(manager);
- Limit draw calls: Merge geometries, use instancing, atlas textures
- Frustum culling: Enabled by default, ensure bounding boxes are correct
- LOD (Level of Detail): Use
THREE.LOD for distance-based mesh switching
- Object pooling: Reuse objects instead of creating/destroying
- Avoid
getWorldPosition in loops: Cache results
javascript
1// Merge static geometries
2import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
3const merged = mergeGeometries([geo1, geo2, geo3]);
4
5// LOD
6const lod = new THREE.LOD();
7lod.addLevel(highDetailMesh, 0);
8lod.addLevel(medDetailMesh, 50);
9lod.addLevel(lowDetailMesh, 100);
10scene.add(lod);
See Also
threejs-geometry - Geometry creation and manipulation
threejs-materials - Material types and properties
threejs-lighting - Light types and shadows