iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Scene

A Three.js scene is the root Object3D — a tree of meshes, lights, cameras, helpers. Add children with add(), traverse with traverse(), dispose carefully when removing.

Build, traverse, dispose, scene graph

EXAMPLE
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

// 1) Scene setup
const scene  = new THREE.Scene();
scene.background = new THREE.Color(0x0b0b0b);
scene.fog = new THREE.Fog(0x0b0b0b, 10, 50);

const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000);
camera.position.set(5, 5, 10);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.appendChild(renderer.domElement);

// 2) Lights
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
const sun = new THREE.DirectionalLight(0xffffff, 2);
sun.position.set(5, 10, 7);
scene.add(sun);

// 3) Meshes
const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(50, 50),
    new THREE.MeshStandardMaterial({ color: 0x555555 }),
);
floor.rotation.x = -Math.PI / 2;
floor.name = 'floor';
scene.add(floor);

const cube = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshStandardMaterial({ color: 0x0ea5e9 }),
);
cube.position.set(0, 0.5, 0);
cube.name = 'hero-cube';
scene.add(cube);

// 4) Group — organise children
const building = new THREE.Group();
building.name = 'building';
building.add(makeWall());
building.add(makeRoof());
building.add(makeDoor());
building.position.set(5, 0, 0);
scene.add(building);

// 5) Resize handler
addEventListener('resize', () => {
    camera.aspect = innerWidth / innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(innerWidth, innerHeight);
});

// 6) Render loop
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

function tick() {
    controls.update();
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
    requestAnimationFrame(tick);
}
tick();

// 7) Traverse the scene
scene.traverse((obj) => {
    if (obj.isMesh) {
        obj.castShadow = true;
        obj.receiveShadow = true;
    }
});

// Find by name
const target = scene.getObjectByName('hero-cube');

// Filter
const meshes = [];
scene.traverse((o) => o.isMesh && meshes.push(o));

// 8) Add / remove children
const extra = new THREE.Mesh(...);
scene.add(extra);
// Later:
scene.remove(extra);
// IMPORTANT — dispose GPU resources
extra.geometry.dispose();
extra.material.dispose();
if (extra.material.map) extra.material.map.dispose();

// 9) Helper — dispose a whole subtree
function disposeNode(node) {
    node.traverse((o) => {
        if (o.geometry) o.geometry.dispose();
        if (o.material) {
            const mats = Array.isArray(o.material) ? o.material : [o.material];
            for (const m of mats) {
                for (const k of ['map','normalMap','roughnessMap','metalnessMap','aoMap','emissiveMap','envMap','alphaMap']) {
                    if (m[k]) m[k].dispose();
                }
                m.dispose();
            }
        }
    });
}

scene.remove(building);
disposeNode(building);

// 10) Load a glTF model
const loader = new GLTFLoader();
const gltf = await loader.loadAsync('/models/car.glb');
const car = gltf.scene;
car.scale.setScalar(0.5);
car.position.set(-3, 0, 0);
scene.add(car);

// 11) Background — solid, color, texture, environment
scene.background = new THREE.Color(0x0b0b0b);
scene.background = new THREE.TextureLoader().load('/sky.jpg');

// Environment map (PMREM for PBR materials)
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
const pmrem = new THREE.PMREMGenerator(renderer);
const hdr = await new RGBELoader().loadAsync('/env/studio.hdr');
const envMap = pmrem.fromEquirectangular(hdr).texture;
hdr.dispose(); pmrem.dispose();
scene.environment = envMap;
scene.background  = envMap;

// 12) World vs local coordinates
cube.position.set(0, 0, 0);
building.add(cube);
// cube.position is now relative to building. World position:
const world = new THREE.Vector3();
cube.getWorldPosition(world);

// 13) Updating object transforms
cube.position.x = 5;
cube.rotation.set(0, Math.PI / 4, 0);
cube.scale.setScalar(2);
cube.updateMatrixWorld();    // usually automatic each render; force if you need it now

// 14) Helpers for debugging
scene.add(new THREE.AxesHelper(2));
scene.add(new THREE.GridHelper(20, 20));
scene.add(new THREE.BoxHelper(cube, 0xff0000));

// 15) Performance + memory tips
//   • Reuse geometries + materials across many meshes (InstancedMesh for thousands)
//   • Dispose textures + materials when removing objects
//   • renderer.info gives draw calls, triangle counts
//   • Use scene.matrixAutoUpdate = false on static groups to save matrix work
//   • Frustum culling is automatic; if your object 'disappears' check frustumCulled

// 16) Teardown when leaving the page
function cleanup() {
    cancelAnimationFrame(rafId);
    disposeNode(scene);
    renderer.dispose();
    renderer.domElement.remove();
    controls.dispose();
}

Why it matters

Three.js doesn’t garbage-collect GPU resources for you. Build a disposeNode helper early and call it whenever you remove a subtree — long-running apps leak fast otherwise.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111);
scene.add(mesh);
Try it Yourself »

Exercise

Add an object to the scene.

scene. (cube);

Test yourself

Q1. A Scene is the…
Q2. Add an object to the scene with…
Q3. A child Object3D inherits its parent's…

Discussion

Loading…