ReadonlyelementsThe sixteen elements in column-major order. The array itself is never replaced, so views taken by a renderer stay valid for the matrix's lifetime; only its contents change.
OptionalonOptional change hook invoked at the end of every mutator that actually writes elements. Engine-internal: owners install it, user code normally leaves it unset. It is intentionally not copied by Matrix4.copy or Matrix4.clone.
Allocates a new matrix with the same elements. The clone has no change hook. This is the only allocating method on the type (§7b).
Sets this matrix to the §7 local transform T · Tp · R · S · Tp⁻¹:
translate by position, then rotate and scale about pivot. The pivot
therefore affects rotation and scale but not position — a node at
position with any pivot still has its pivot point at position.
Expanding the product, the upper-left 3×3 block is exactly R · S (the
rotation columns scaled by scale.x/y/z) and the translation column is
position + (I − R · S) · pivot
which is how the formula is evaluated here — one pass over raw scalars, no
intermediate matrices and no allocation. rotation is assumed unit length
(§7b); a non-unit quaternion scales the result by its squared length.
All four inputs are required: pivot has no default because §7 makes it a
first-class field of Transform, and an implicit zero would quietly hide a
caller that forgot to pass it. Pass a zero vector for "no pivot".
Copies the elements of m into this matrix. The change hook is not copied.
Splits this matrix into translation, rotation, and scale, writing each into
the corresponding required out object (plan D7) and returning this.
This matrix is not modified and its own change hook does not fire; each out
object is written through a single set(...), so each of their hooks fires
exactly once.
Two documented limitations, both inherent rather than implementation shortcuts:
compose folds the pivot into the
translation column, and infinitely many (position, pivot) pairs produce
the same matrix. outPosition therefore receives the composed
translation position + (I − R · S) · pivot, which equals position
exactly when the pivot is zero. Round-tripping a transform means keeping
the pivot alongside the matrix (§7 keeps it on Transform).A zero scale component collapses a column, leaving no direction to recover:
outRotation is set to the identity rather than NaN (defined here — the
same "no-op beats poisoning the frame" reasoning as Quaternion.normalize).
Shear (a non-orthogonal upper-left block) is not detected; the returned
rotation is then the closest thing the column-normalization produces.
Determinant of this matrix. Does not mutate and does not allocate.
Reads sixteen column-major elements starting at offset. This is the
inverse of reading Matrix4.elements and the entry point used by
serialization (§79), by matrixAutoUpdate = false authoring (§7), and by
tests that build matrices from raw numbers.
Optionaloffset: numberResets this matrix to the identity.
Inverts this matrix in place (general inverse via the adjugate — no
assumption that the matrix is affine, orthogonal, or uniformly scaled, so
it also inverts projection matrices, §47's inverseProjectionMatrix).
Singular behaviour (defined here, plan §1 rule 12): a matrix whose
determinant is exactly 0 has no inverse, so this method leaves the
elements unchanged, returns this, and does not fire the change hook —
the hook reports a change, and nothing changed. Callers that must
distinguish "inverted" from "left alone" check m.determinant() !== 0
first. Resetting to the identity was rejected: it silently substitutes a
different, plausible-looking transform for the failure, which is the
hardest kind of bug to trace. Throwing was rejected because inversion sits
on per-frame paths (§43, §47) where an exception would take down the frame.
A nearly singular matrix still inverts, producing large elements; this method deliberately applies no epsilon, since the right threshold depends on the caller's units (§40).
Matrix product this = this * m — this matrix is the left operand, so the
combined transform applies m first and this matrix second (the same
ordering as Quaternion.multiply, and the ordering the §7 composition
formula is written in). Aliasing-safe: m may be this.
Sets this matrix to a right-handed orthographic projection (plan D8, §47).
left/right/bottom/top bound the view volume in camera space with +Y up
(§7a); the camera looks down its own −Z axis, so near and far are
positive distances in front of the camera, not Z coordinates.
The name says set because this overwrites every element rather than
post-multiplying — see Matrix4.setPerspective.
depthRange selects the backend's clip-space depth convention and defaults
to "negative-one-to-one" (WebGL 2, §120); WebGPU passes "zero-to-one".
A degenerate box (right === left, top === bottom, far === near)
produces non-finite elements rather than throwing — see
Matrix4.setPerspective.
OptionaldepthRange: DepthRangeSets this matrix to a right-handed perspective projection (plan D8, §47).
The camera looks down its own −Z axis with +Y up (§7a), so near and
far are positive distances in front of the camera, not Z coordinates:
0 < near < far. fovYRadians is the full vertical field of view in
radians (§7a — there is no degree overload) and aspect is width ÷ height.
The name says set because this overwrites every element rather than
post-multiplying — the same reason identity() is a mutator, and the
reason it is not called perspective().
depthRange selects the backend's clip-space depth convention and defaults
to "negative-one-to-one" (WebGL 2, §120); WebGPU passes "zero-to-one".
Nothing above this method ever sees the difference (§7a).
Degenerate arguments (near === far, aspect === 0, a field of view at or
beyond π) produce non-finite or meaningless elements rather than throwing:
the math package validates nothing, and camera types (§47) are the layer
that reports configuration errors.
OptionaldepthRange: DepthRange
Mutable 4×4 matrix stored column-major in a
Float64Array(16)(§7b) — the transform type of the scene graph (§7) and of camera projections (§47).Element layout —
elements[column * 4 + row], the order GPU APIs andWebGL2RenderingContext.uniformMatrix4fvexpect; for an affine transform the translation therefore lives ine[12..14]:Float64Array(notFloat32Array) is deliberate: the scene graph does its arithmetic in double precision and narrows to float only at the backend boundary (§62), so accumulated transform error stays below anything the determinism tiers (§33) care about.Allocation policy (§7b, plan D7): every method mutates in place and returns
this; only Matrix4.clone allocates. Matrix4.decompose produces three results that are notthis, so it takes three required out objects and allocates nothing either.Change notification (plan D3): every mutator invokes Matrix4.onChanged exactly once, after the last element is written. Writing
elementsdirectly bypasses the hook by design — the same rule asv.x = 1on the vector types.