Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Once more, I'm struggling to wrap my head around the threejs API, here are my notes.
> **IMPORTANT** base on threejs `r114` (march 2020)
API topics covered :
* Scene and Object3D, hierarchy, transforms
* Maths, linear algebra
* DirectionalLight, as I'm currently trying to understand how to attach one of them to a Camera...
Handy links :
* source code:
* docs:
* examples:
Scene and Object3D
The `Scene` represents a fairly typical *Scene graph* (or maybe more a *Scene tree*)
composed of `Object3D` instances.
The `Scene` itself is a kind of `Object3D`.
Each `Object3D` had an `id: number`, a `name: string` and an `uuid: string`.
## Hierarchy
`Object3D` have a *parent/children* hierarchical relationship, manipulated through the use of :
* `someParent.add(someChild)`, or `attach` to preserve the child world position in the process
* `someParent.remove(someChild)`
## Coordinate systems and Transforms
Coordinate systems are right-handed systems, with `Y` pointing up.
1. `Object3D` transform is *defined* by the following PRS values, relative to parent :
* `position`: `Vector3`
* `quaternion`: `Quaternion`, which is implicitly mirrored in `rotation` as Euler angles
* `scale`: `Vector3`
2. `Object3D` additionally store its transform through :
* `matrix`: the transform from *local* to *parent* space
* computed from PRS values
* `matrixWorld`: the transform from *local* to *world*
> NOTE - inverse matrices are not stored, and are computed when needed (for exemple, in `worldToLocal` method)
3. These transforms are updated by the `updateMatrix` and `updateWorldMatrix` methods :
* updates can propagate through parents/children depending on arguments
* updates can be skipped depending on flags :
* `matrixAutoUpdate` can be disabled for an object, or generally
* `matrixWorldNeedsUpdate` is a 'dirty flag'
4. By default, the scene general matrix update propagation is done by the renderer :
* `if (scene.autoUpdate === true) scene.updateMatrixWorld();`
* which updates, by default, all `matrix` and dirty `matrixWorld` values, for all the objects in the scene hierarchy
The linear algebra types are :
* `Vector3` storing either positions or directions
* `Matrix3`
* `Matrix4`
> My understanding is that math methods never allocate a result value. I suppose for performance reasons related to GC.
Scalar values are stored in plain javascript numbers (so mostly `float64` values)
Matrices are *stored* in linear arrays, it seems in a *column-major order*: the values for a column are next to each other in the array.
* NOTE - `Matrix.set(...)` takes values in a *row-major* format, to be able to format code is a human-readable math-like way
* on the other hand, `Matrix.fromArray` takes values in a *column-major* way
## Matrix inverse
Matrix inverse is calculated using the *determinant* of the matrix.
An exception is optionally thrown when not inversible (`det === 0`).
## GLSL equivalences
* `` <=> `dot(v1,v2)`
* `v1.cross(v2)` <=> `v1 = cross(v1,v2)`
* `v1.crossVectors(v1,v2)` <=> `v = cross(v1,v2)`
* `v3.applyMatrix3(M)` <=> `v3 = M * v3`
* `v3.applyMatrix4(M)` <=> `vec4 tmp = M * vec4(v3, 1.0); v3 = / v4.w`
* `M1.multiply(M2)` <=> `M1 = M1 * M2`
* `M1.premultiply(M2)` <=> `M1 = M2 * M1`
* `M.multiplyMatrices(M1, M2)` <=> `M = M1 * M2`
`DirectionalLight` orientation is defined by :
* `position`: `Vector3`
* `target`: `Object3D`
1. There's no API to query the actual light direction :
* It seems only calculated in `WebGLLights.js` to feed the `direction` GLSL uniform
* The calculation extracts world positions from `light.worldMatrix` and ``
2. By default, the `target` object is not part of the `scene` :
* its position is `[0,0,0]`
* its `worldMatrix` must be explicity updated if the position moves - *or* the target should be added to the scene hierarchy
3. This `target` behaviour is not the same as the one used in Cameras
* there's an old proposal to change the behaviour : [Github issue, Remove target from DirectionalLight and SpotLight. #5079](
* there's also an old PR that is related, so work is stalled for now : [Make Light targets optional #14658](
## DirectionalLightHelper
Is used to draw a helper object representing the light.
> NOTE - It should be added to the `scene` not as a child of another object.
> * It seems that the underlying geometry is updated only using *world coordinates* taken from the light, so it breaks if the helper *parent* is not the world.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment