Matrix4
4x4 matrices for the usual transform stack, as flat Float[16] in COLUMN-MAJOR order -- the layout GL expects, so no transpose happens on upload. Static functions returning new arrays, following Vector2's style in Game.Framework. Multiply is 'apply rhs, then lhs', so a model-view-projection is Multiply(projection, Multiply(view, model)).
Operations
- Identity
- IdentityInto
- Inverse
- InverseInto
- LookAt
- LookAtInto
- LookAtOrigin
- Multiply
- MultiplyInto
- Orthographic
- OrthographicBox
- OrthographicInto
- Perspective
- PerspectiveDegrees
- PerspectiveInto
- RotationX
- RotationXInto
- RotationY
- RotationYInto
- RotationYXZ
- RotationYXZInto
- RotationZ
- RotationZInto
- Scale
- ScaleXYZ
- ScaleXYZInto
- Translation
- TranslationInto
- TranslationScale
- TranslationScaleInto
- Transpose
- TransposeInto
IdentityInto # function
Identity, written into a buffer the caller owns. ## Why every builder here has an Into twin A matrix is a Float[16], and the returning forms allocate one per call. At one or two matrices per object per frame that is hundreds of arrays a second, which is enough to trigger a collection mid-frame -- the classic stutter. Objeck's 2D SDL renderer had to be rewritten once for exactly this. Four of these builders were worse than one allocation: Translation, RotationX, RotationY and RotationZ each called Identity() and then overwrote it, so they allocated twice. Now the returning form is the thin one, wrapping the Into form. Reuse one buffer per thing you draw, filled fresh each frame.
function : IdentityInto(out:Float[]) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
Inverse # function
Inverse of a 4x4 matrix, by cofactor expansion. Needed for lighting -- the normal matrix is the transposed inverse of the model matrix, and anything but a uniform scale makes the difference visible -- and for turning a view matrix back into a camera position. Returns the identity when the matrix is singular, which is the same choice LookAt makes for a degenerate basis: a wrong-but-usable matrix rather than a crash or a buffer full of infinities.
function : Inverse(m:Float[]) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| m | Float | the matrix |
Return
| Type | Description |
|---|---|
| Float | the inverse, or the identity when there is none |
InverseInto # function
Inverse into a caller's buffer.
function : InverseInto(out:Float[], m:Float[]) ~ BoolParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements; must not be m |
| m | Float | the matrix to invert |
Return
| Type | Description |
|---|---|
| Bool | true when m was invertible; out is the identity when false |
LookAt # function
A right-handed view matrix for a camera anywhere, looking anywhere. This is what lets a camera orbit or track a subject rather than sit on the +Z axis. Degenerate input -- eye equal to target, or an up vector parallel to the view direction -- yields identity rather than NaNs.
function : LookAt(eye:Vector3, target:Vector3, up:Vector3) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| eye | Vector3 | where the camera is |
| target | Vector3 | what it looks at |
| up | Vector3 | which way is up, usually (0, 1, 0) |
Return
| Type | Description |
|---|---|
| Float | the view matrix |
LookAtInto # function
LookAt into a caller's buffer, for a camera that is not a Camera -- a light looking at a scene, say. Camera->GetViewMatrixInto is the cheaper route when there is a Camera.
function : LookAtInto(out:Float[], eye:Vector3, target:Vector3, up:Vector3) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| eye | Vector3 | where the viewer is |
| target | Vector3 | what it looks at |
| up | Vector3 | which way is up |
LookAtOrigin # function
A view matrix that steps back along +Z and looks at the origin. The smallest useful camera; use LookAt for one that can move.
function : LookAtOrigin(distance:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| distance | Float | how far back to stand |
Return
| Type | Description |
|---|---|
| Float | the matrix |
Multiply # function
Matrix product.
function : Multiply(lhs:Float[], rhs:Float[]) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| lhs | Float | applied second |
| rhs | Float | applied first |
Return
| Type | Description |
|---|---|
| Float | lhs * rhs |
MultiplyInto # function
Matrix product written into a buffer the caller owns. Exists so a draw loop can avoid allocating. Multiply returns a fresh Float[16] every call, which at one or two matrices per object per frame is hundreds of arrays a second -- enough to trigger a collection mid-frame, the classic stutter. Scene uses this with a scratch buffer it keeps.
function : MultiplyInto(out:Float[], lhs:Float[], rhs:Float[]) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements; may not alias lhs or rhs |
| lhs | Float | applied second |
| rhs | Float | applied first |
Orthographic # function
Orthographic projection: no perspective, so distance does not shrink anything. Two uses. A 2D overlay -- a HUD, a minimap -- drawn in pixel coordinates. And, less obviously, a directional light's view of a scene: a light infinitely far away casts parallel rays, so the projection that matches it is parallel too. A shadow map rendered through a perspective projection is wrong in a way that looks like the shadows are being cast by a nearby lamp.
function : Orthographic(left:Float, right:Float, bottom:Float, top:Float, near:Float, far:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| left | Float | the left clip plane |
| right | Float | the right clip plane |
| bottom | Float | the bottom clip plane |
| top | Float | the top clip plane |
| near | Float | the near clip plane; may be negative, unlike Perspective |
| far | Float | the far clip plane |
Return
| Type | Description |
|---|---|
| Float | the matrix |
OrthographicBox # function
A square orthographic box centred on the origin -- the usual shape for a directional light's view of a scene.
function : OrthographicBox(extent:Float, near:Float, far:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| extent | Float | half the width and height covered |
| near | Float | the near clip plane |
| far | Float | the far clip plane |
Return
| Type | Description |
|---|---|
| Float | the matrix |
OrthographicInto # function
Orthographic projection into a caller's buffer.
function : OrthographicInto(out:Float[], left:Float, right:Float, bottom:Float, top:Float, near:Float, far:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| left | Float | the left clip plane |
| right | Float | the right clip plane |
| bottom | Float | the bottom clip plane |
| top | Float | the top clip plane |
| near | Float | the near clip plane |
| far | Float | the far clip plane |
Perspective # function
Right-handed perspective projection, mapping to GL's -1..1 depth range.
function : Perspective(fov_radians:Float, aspect:Float, near:Float, far:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| fov_radians | Float | vertical field of view |
| aspect | Float | width divided by height |
| near | Float | near clip distance; must be greater than 0 |
| far | Float | far clip distance |
Return
| Type | Description |
|---|---|
| Float | the matrix |
PerspectiveDegrees # function
Perspective with the field of view in DEGREES, and sensible clip planes. Both call sites spelled the fov as a bare expression -- Float->Pi() / 4.0 and Float->Pi() / 3.0 -- and repeated the same 0.1 and 100.0 clip distances verbatim. Degrees are how field of view is actually discussed; 60 is a normal first-person view, 45 a slightly telephoto one.
function : PerspectiveDegrees(fov_degrees:Float, aspect:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| fov_degrees | Float | vertical field of view in degrees |
| aspect | Float | width divided by height, as GLWindow->GetAspect reports |
Return
| Type | Description |
|---|---|
| Float | the matrix |
PerspectiveDegrees # function
Perspective in degrees with explicit clip planes.
function : PerspectiveDegrees(fov_degrees:Float, aspect:Float, near:Float, far:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| fov_degrees | Float | vertical field of view in degrees |
| aspect | Float | width divided by height |
| near | Float | near clip distance; must be greater than 0 |
| far | Float | far clip distance |
Return
| Type | Description |
|---|---|
| Float | the matrix |
PerspectiveInto # function
Perspective into a caller's buffer. See IdentityInto. Note this zeroes the destination first, so unlike the other Into forms it must NOT be handed a buffer that already holds something wanted -- a projection matrix is mostly zeroes, and leaving a previous matrix's values in the untouched slots would produce nonsense rather than a projection.
function : PerspectiveInto(out:Float[], fov_radians:Float, aspect:Float, near:Float, far:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| fov_radians | Float | vertical field of view |
| aspect | Float | width divided by height |
| near | Float | near clip distance; must be greater than 0 |
| far | Float | far clip distance |
RotationX # function
Rotation about the X axis.
function : RotationX(radians:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| radians | Float | angle in radians |
Return
| Type | Description |
|---|---|
| Float | the matrix |
RotationXInto # function
Rotation about X, into a caller's buffer. See IdentityInto.
function : RotationXInto(out:Float[], radians:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| radians | Float | angle in radians |
RotationY # function
Rotation about the Y axis.
function : RotationY(radians:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| radians | Float | angle in radians |
Return
| Type | Description |
|---|---|
| Float | the matrix |
RotationYInto # function
Rotation about Y, into a caller's buffer. See IdentityInto.
function : RotationYInto(out:Float[], radians:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| radians | Float | angle in radians |
RotationYXZ # function
Yaw, pitch and roll, allocating.
function : RotationYXZ(yaw:Float, pitch:Float, roll:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| yaw | Float | rotation about Y, applied first |
| pitch | Float | rotation about X |
| roll | Float | rotation about Z, applied last |
Return
| Type | Description |
|---|---|
| Float | the matrix |
RotationYXZInto # function
Yaw, then pitch, then roll -- the same result as RotationY * RotationX * RotationZ, computed directly. Spelling that composition out costs six allocations (three builders, each of which allocated twice) plus two matrix products, per object per frame. This is nine multiplies and no allocation. The derivation is verified against the composition in the regression suite, because a transposed or sign-flipped term here produces a rotation that looks plausible until something is mirrored.
function : RotationYXZInto(out:Float[], yaw:Float, pitch:Float, roll:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| yaw | Float | rotation about Y, applied first |
| pitch | Float | rotation about X |
| roll | Float | rotation about Z, applied last |
RotationZ # function
Rotation about the Z axis.
function : RotationZ(radians:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| radians | Float | angle in radians |
Return
| Type | Description |
|---|---|
| Float | the matrix |
RotationZInto # function
Rotation about Z, into a caller's buffer. See IdentityInto.
function : RotationZInto(out:Float[], radians:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| radians | Float | angle in radians |
Scale # function
Uniform scale matrix.
function : Scale(s:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| s | Float | scale factor |
Return
| Type | Description |
|---|---|
| Float | the matrix |
ScaleXYZ # function
Non-uniform scale. This is what lets one unit-cube mesh become every box in a scene -- walls, floors and obstacles -- instead of uploading a separate mesh per shape.
function : ScaleXYZ(x:Float, y:Float, z:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| x | Float | scale along x |
| y | Float | scale along y |
| z | Float | scale along z |
Return
| Type | Description |
|---|---|
| Float | the matrix |
ScaleXYZInto # function
Non-uniform scale, into a caller's buffer. See IdentityInto.
function : ScaleXYZInto(out:Float[], x:Float, y:Float, z:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| x | Float | scale along x |
| y | Float | scale along y |
| z | Float | scale along z |
Translation # function
Translation matrix.
function : Translation(x:Float, y:Float, z:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| x | Float | x offset |
| y | Float | y offset |
| z | Float | z offset |
Return
| Type | Description |
|---|---|
| Float | the matrix |
TranslationInto # function
Translation, into a caller's buffer. See IdentityInto.
function : TranslationInto(out:Float[], x:Float, y:Float, z:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| x | Float | x offset |
| y | Float | y offset |
| z | Float | z offset |
TranslationScale # function
Translate and scale, allocating.
function : TranslationScale(x:Float, y:Float, z:Float, sx:Float, sy:Float, sz:Float) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| x | Float | x offset |
| y | Float | y offset |
| z | Float | z offset |
| sx | Float | scale along x |
| sy | Float | scale along y |
| sz | Float | scale along z |
Return
| Type | Description |
|---|---|
| Float | the matrix |
TranslationScaleInto # function
Translate and scale in one step, with no multiply at all. This is the whole of a Box's transform -- position plus half-extents -- and it is the single most common model matrix there is. Composing it as Multiply(Translation(...), ScaleXYZ(...)) costs two allocations and sixty-four multiply-adds to produce a matrix whose scale is its diagonal and whose translation is its last column. So write those directly.
function : TranslationScaleInto(out:Float[], x:Float, y:Float, z:Float, sx:Float, sy:Float, sz:Float) ~ NilParameters
| Name | Type | Description |
|---|---|---|
| out | Float | destination, at least 16 elements |
| x | Float | x offset |
| y | Float | y offset |
| z | Float | z offset |
| sx | Float | scale along x |
| sy | Float | scale along y |
| sz | Float | scale along z |