Skip to content

Instantly share code, notes, and snippets.

@rotoglup
Last active March 13, 2020 08:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rotoglup/12084cd2b28880c1f1393f7748e527bf to your computer and use it in GitHub Desktop.
Save rotoglup/12084cd2b28880c1f1393f7748e527bf to your computer and use it in GitHub Desktop.

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 :

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)

  1. 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'
  2. 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

View related transforms

Object3D store two additional matrix, which are updated by the Renderer, in the renderObject method :

  • modelViewMatrix: the transform, for points, from local to view space
  • normalMatrix: the transform, for normals, from local to view space (derived from modelViewMatrix)

Maths

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

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

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 light.target.worldMatrix
  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

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