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: https://github.com/mrdoob/three.js
- docs: https://threejs.org/docs
- examples: https://threejs.org/examples
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
.
Object3D
have a parent/children hierarchical relationship, manipulated through the use of :
someParent.add(someChild)
, orattach
to preserve the child world position in the processsomeParent.remove(someChild)
Coordinate systems are right-handed systems, with Y
pointing up.
-
Object3D
transform is defined by the following PRS values, relative to parent :position
:Vector3
quaternion
:Quaternion
, which is implicitly mirrored inrotation
as Euler anglesscale
:Vector3
-
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)
-
These transforms are updated by the
updateMatrix
andupdateWorldMatrix
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 generallymatrixWorldNeedsUpdate
is a 'dirty flag'
-
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 dirtymatrixWorld
values, for all the objects in the scene hierarchy
Object3D
store two additional matrix, which are updated by the Renderer
, in the renderObject
method :
modelViewMatrix
: the transform, for points, from local to view spacenormalMatrix
: the transform, for normals, from local to view space (derived frommodelViewMatrix
)
The linear algebra types are :
Vector3
storing either positions or directionsMatrix3
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 is calculated using the determinant of the matrix.
An exception is optionally thrown when not inversible (det === 0
).
Vector3
v1.dot(v2)
<=>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.xyz / v4.w
Matrix3/Matrix4
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
-
There's no API to query the actual light direction :
- It seems only calculated in
WebGLLights.js
to feed thedirection
GLSL uniform - The calculation extracts world positions from
light.worldMatrix
andlight.target.worldMatrix
- It seems only calculated in
-
By default, the
target
object is not part of thescene
:- 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
- its position is
-
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
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.