Object3D Hierarchy

Tip

This course was updated in 2024. For the newer content, please visit Object3D Hierarchy

Description

The scene is an Object3D. You can add other Object3Ds to the scene and they become children of the scene. The scene itself is derived from the Object3D base class.

If you rotate the scene, or scale the scene, or translate its position, it will affect all if its child objects.

You make an Object3D a child of another Object3D by using the parents `add` method.

``````scene.add(cube)
``````

You can also add Object3Ds to other Object3Ds that are already part of the scene. Any changes to the Object3D such as position, scale, rotation will affect all of the children under the same parent equally.

It is possible to create a Hierarchy of Object3Ds by continually adding new objects to any existing objects.

``````scene
|--object1 (Red Ball)
|--object2 (Green Ball)
|--object3 (Blue Ball)
``````

In this example, the blue ball is a child of the green ball, which is a child of the red ball.

Any changes to the red ball will effect the green and blue balls,

Any changes to the green ball, will affect the blue ball, but not its parent, the red ball.

Any changes to the blue ball, have no effect on its parent, or grand parent balls.

Any number of Object3Ds can be added as children of other Object3Ds.

An Object3D can have only 1 parent, and you can change its parent dynamically any time.

Changing an Object3Ds parent will affect the current position, scale and rotation based in the parent it has now become a child of.

``````scene.position.set(0, 0, 0) // this is default position of a scene, and any Object3Ds
cube.position.set(5, 0, 0) // cube is offset x = 5 from of its parent.
scene.add(cube) // add the cube to the scene. The scene becomes its parent Object3D.

sphere.position.set(3, 0, 0) // sphere is offset x = 3 from the center of its parent.
cube.add(sphere) // The spheres parent is now the cube. The sphere will be x=3 offset from the cube in local space. So that will be 8 in world space since the cube is a child of the scene and is already offset x = 5.
``````

Getting an Object3D transform, such as position, rotation/quaternion and scale will return the values in local transform space. If the Object3D is a direct descendant of the scene, then the world space values will be identical.

If your Object3D is a child of another Object3D which is already a child of the scene, then the world transform values will also consider the transforms of its parent, grandparents, great grandparents etc.

``````obj.position // values are local transform
obj.rotation // values are local transform
obj.quaternion // values are local transform
obj.scale // values are local transform
``````

To get the world transforms of an object,

``````const objectsWorldPosition = new THREE.Vector3()
object.getWorldPosition(objectsWorldPosition)

const objectsWorldDirection = new THREE.Vector3()
object.getWorldDirection(objectsWorldDirection)

const objectsWorldQuaternion = new THREE.Quaternion()
object.getWorldQuaternion(objectsWorldQuaternion)

const objectsWorldScale = new THREE.Vector3()
object.getWorldScale(objectsWorldScale)
``````

Lesson Scripts

./dist/client/index.html

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31``` `````` Three.js TypeScript Tutorials by Sean Bradley : https://sbcode.net/threejs
``````

./src/client/client.ts

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113``` ``````import * as THREE from 'three' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import Stats from 'three/examples/jsm/libs/stats.module' import { GUI } from 'dat.gui' const scene = new THREE.Scene() scene.add(new THREE.AxesHelper(5)) const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) camera.position.x = 4 camera.position.y = 4 camera.position.z = 4 const renderer = new THREE.WebGLRenderer() renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) const controls = new OrbitControls(camera, renderer.domElement) controls.target.set(8, 0, 0) const light1 = new THREE.PointLight(0xffffff, 400) light1.position.set(10, 10, 10) scene.add(light1) const light2 = new THREE.PointLight(0xffffff, 400) light2.position.set(-10, 10, 10) scene.add(light2) const object1 = new THREE.Mesh(new THREE.SphereGeometry(), new THREE.MeshPhongMaterial({ color: 0xff0000 })) object1.position.set(4, 0, 0) scene.add(object1) object1.add(new THREE.AxesHelper(5)) const object2 = new THREE.Mesh(new THREE.SphereGeometry(), new THREE.MeshPhongMaterial({ color: 0x00ff00 })) object2.position.set(4, 0, 0) object1.add(object2) object2.add(new THREE.AxesHelper(5)) const object3 = new THREE.Mesh(new THREE.SphereGeometry(), new THREE.MeshPhongMaterial({ color: 0x0000ff })) object3.position.set(4, 0, 0) object2.add(object3) object3.add(new THREE.AxesHelper(5)) window.addEventListener('resize', onWindowResize, false) function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) render() } const gui = new GUI() const object1Folder = gui.addFolder('Object1') object1Folder.add(object1.position, 'x', 0, 10, 0.01).name('X Position') object1Folder.add(object1.rotation, 'x', 0, Math.PI * 2, 0.01).name('X Rotation') object1Folder.add(object1.scale, 'x', 0, 2, 0.01).name('X Scale') object1Folder.open() const object2Folder = gui.addFolder('Object2') object2Folder.add(object2.position, 'x', 0, 10, 0.01).name('X Position') object2Folder.add(object2.rotation, 'x', 0, Math.PI * 2, 0.01).name('X Rotation') object2Folder.add(object2.scale, 'x', 0, 2, 0.01).name('X Scale') object2Folder.open() const object3Folder = gui.addFolder('Object3') object3Folder.add(object3.position, 'x', 0, 10, 0.01).name('X Position') object3Folder.add(object3.rotation, 'x', 0, Math.PI * 2, 0.01).name('X Rotation') object3Folder.add(object3.scale, 'x', 0, 2, 0.01).name('X Scale') object3Folder.open() const stats = new Stats() document.body.appendChild(stats.dom) const debug = document.getElementById('debug1') as HTMLDivElement function animate() { requestAnimationFrame(animate) controls.update() render() const object1WorldPosition = new THREE.Vector3() object1.getWorldPosition(object1WorldPosition) const object2WorldPosition = new THREE.Vector3() object2.getWorldPosition(object2WorldPosition) const object3WorldPosition = new THREE.Vector3() object3.getWorldPosition(object3WorldPosition) debug.innerText = 'Red\n' + 'Local Pos X : ' + object1.position.x.toFixed(2) + '\n' + 'World Pos X : ' + object1WorldPosition.x.toFixed(2) + '\n' + '\nGreen\n' + 'Local Pos X : ' + object2.position.x.toFixed(2) + '\n' + 'World Pos X : ' + object2WorldPosition.x.toFixed(2) + '\n' + '\nBlue\n' + 'Local Pos X : ' + object3.position.x.toFixed(2) + '\n' + 'World Pos X : ' + object3WorldPosition.x.toFixed(2) + '\n' stats.update() } function render() { renderer.render(scene, camera) } animate() ``````