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), orattachto preserve the child world position in the processsomeParent.remove(someChild)
Coordinate systems are right-handed systems, with Y pointing up.
-
Object3Dtransform is defined by the following PRS values, relative to parent :position:Vector3quaternion:Quaternion, which is implicitly mirrored inrotationas Euler anglesscale:Vector3
-
Object3Dadditionally 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
worldToLocalmethod)
-
These transforms are updated by the
updateMatrixandupdateWorldMatrixmethods :- updates can propagate through parents/children depending on arguments
- updates can be skipped depending on flags :
matrixAutoUpdatecan be disabled for an object, or generallymatrixWorldNeedsUpdateis 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
matrixand dirtymatrixWorldvalues, 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 :
Vector3storing either positions or directionsMatrix3Matrix4
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.fromArraytakes 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 * v3v3.applyMatrix4(M)<=>vec4 tmp = M * vec4(v3, 1.0); v3 = v4.xyz / v4.w
Matrix3/Matrix4
M1.multiply(M2)<=>M1 = M1 * M2M1.premultiply(M2)<=>M1 = M2 * M1M.multiplyMatrices(M1, M2)<=>M = M1 * M2
DirectionalLight orientation is defined by :
position:Vector3target:Object3D
-
There's no API to query the actual light direction :
- It seems only calculated in
WebGLLights.jsto feed thedirectionGLSL uniform - The calculation extracts world positions from
light.worldMatrixandlight.target.worldMatrix
- It seems only calculated in
-
By default, the
targetobject is not part of thescene:- its position is
[0,0,0] - its
worldMatrixmust be explicity updated if the position moves - or the target should be added to the scene hierarchy
- its position is
-
This
targetbehaviour 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
scenenot 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.