Course outline
Object3D and Transforms
In one line
Meshes, lights, cameras and groups are all Object3Ds with a position, rotation, scale and visibility. You learn add, remove, traverse and getObjectByName, and what happens when an object is hidden, scaled to 0, placed behind the camera or added twice.
Think of it like this
Every item in a shop has a label with the same fields: where it is, which way it faces, how big, and whether it is on display. A lamp, a chair and a shelf are different things, but the label is the same. In three.js that label is Object3D.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Object3D
- The base class of everything in a scene. It has a position, rotation, scale, visibility, a name, a parent and children.
- Group
- An
Object3Dthat draws nothing itself. It exists to carry children so they move, turn and scale together. - parent / child
- An object inside another. Its position is measured from its parent's origin, and it moves with the parent.
- traverse
- Visit an object and all its descendants, calling a function on each.
Step by step
01Make and place an object
const mesh = new THREE.Mesh(geometry, material); mesh.position.set(1, 0.3, 0); mesh.rotation.y = Math.PI / 4; mesh.scale.set(1, 2, 1). scene.add(mesh) puts it in the tree.
02Give it a name
mesh.name = "orange" costs nothing and lets you find it: scene.getObjectByName("orange"). The scene inspector under each canvas also shows names.
03Hide it, remove it, or scale it
visible = false keeps it in the tree and skips drawing; remove takes it out; scale = 0 still draws it, invisibly. The first example prints the draw calls for each.
04Visit everything
scene.traverse((o) => ...) visits the scene, then every object below it. The example counts six: the scene, two lights and three boxes. Lights are objects too.
Try it yourself
- 1
Remove instead of hiding
In the first example replace
b.visible = false;withscene.remove(b);. The draw calls are the same (2) andscene still holds itprintsfalse. But a later line,scene.getObjectByName("blue").visible, fails withUncaught TypeError: Cannot read properties of undefined (reading 'visible'), because the name finds nothing. Hidden objects stay in the tree; removed ones leave it. - 2
Add the same box twice
Add
scene.add(a); console.log("children:", scene.children.length);just beforefunction draw(label) {. It printschildren: 5: the secondadddid nothing. Now tryscene.add(scene);: the console logsTHREE.Object3D.add: object can't be added as a child of itself.followed by a dump of the scene, and the picture is unchanged.
Code & diagrams
The status bar shows the draw calls too. Scale 0 still costs a draw call; a hidden object and an object behind the camera cost none.
Console
Run the scene to see its console.Expected console output
three boxes | draw calls: 3 | triangles: 36
blue.visible = false | draw calls: 2 | triangles: 24
scene still holds it: true
grey.scale = 0 | draw calls: 2 | triangles: 24
orange.position.z = 10 | draw calls: 1 | triangles: 12
found by name: false | missing name gives: undefined
traverse visits 6 objects (the scene itself, 2 lights, 3 boxes)No canvas needed: these are facts about the tree. Positions come from `getWorldPosition` after `updateMatrixWorld()`.
Console
Run the scene to see its console.Expected console output
in left: left has 1 | right has 0 | world x = -1.5
added to right: left has 0 | right has 1 | world x = 2.5
added twice to right: right has 1 child
moved to scene: local x stays 0.5 | world x = 0.5 (its local number now means something else)
right.attach(wheel): local x = -1.5 | world x = 0.5
after remove: parent is null | right has 0 children
scene children: left, rightBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Add something that is not there
Add scene.add(undefined); before the first draw(...) in the first example.
Myth vs fact
Myth
scale.set(0, 0, 0) removes an object from the work.
Fact
It is still sent to the GPU (the example's draw call count stays at 2). Use visible = false to skip it.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
visible = falseon a parent hides the whole subtree, so its children cost nothing either: the cheapest way to hide ten parts. - ▸
Culling uses a bounding sphere, computed from the geometry on the first render. If you change vertices yourself, update it (Topic 4.5), or the object can vanish at the screen edge while still on screen.
Remember this
- 1
The problem this solves: you need one way to place, turn, hide, find and group anything in a scene. Without it each kind of object would need its own commands.
- 2
**Every scene object extends
Object3D**:Mesh,Group, lights, cameras, evenScene. Main fields:position,rotation(Euler, radians),quaternion(the same turn, kept in sync: Topic 2.6),scale,visible,name,parentandchildren. - 3
**
addandremove** build the tree;parent.add(a, b)adds several. An object has one parent: adding it elsewhere first removes it from the old one (it moves, it is not copied: second example). Adding it twice to the same parent does nothing.removesetsparenttonullbut frees nothing: geometry and material stay on the GPU until disposed (Phase 17). - 4
**A wrong argument to
add.**undefinedor a non-Object3DlogsTHREE.Object3D.add: object not an instance of THREE.Object3D.; adding an object to itself logsTHREE.Object3D.add: object can't be added as a child of itself.Both are console errors, not exceptions, so the scene runs on without the object. A model that failed to load is the usual cause. - 5
Local numbers, world meaning.
positionis measured from the parent (Topic 2.4). Moving an object to another parent withaddkeeps its local numbers and changes its world position;parent.attach(child)keeps the world position and rewrites the local numbers instead. - 6
**
visible = false, scale 0 and a position behind the camera** all hide an object at different costs (first example).visible = falseskips the object and its subtree: no draw call.scale.set(0, 0, 0)still sends a draw call. Behind the camera or outside the frustum, culling skips the draw call, but matrices are still updated. - 7
**
traverseandgetObjectByName.**traverse(fn)callsfnon an object and every descendant.getObjectByName("front-wheel")returns the first match orundefined; names are not checked for uniqueness. Name the parts you will look for, as the course does from Phase 4.
Explain it without notes
What is the difference between visible = false, scene.remove(obj) and scale.set(0, 0, 0)?
What happens if you add the same mesh to two different groups?
Practice
Write a function findAll(root, namePrefix) that returns every object whose name starts with a prefix.
A model's parent is scene. Write the line that moves it to rack but keeps it where it is on screen.
Done when you can
Place, turn, scale, hide and name an object
Say what
visible,removeandscale 0each costUse
traverseandgetObjectByNameExplain why an object has only one parent and when to use
attach