# H3DU's Math Functions

The HTML 3D library includes a collection of math functions for working with vectors, matrices, and quaternions.

Here is an overview of these data types.

## Contents

## Vectors

A vector is a line segment pointing in a certain *direction* in space and
having a certain *length* and an unspecified starting point.
A particular vector can instead be treated as describing a position
(by pointing to that position from an *origin* (0,0,0)), or a color.

In `H3DU.Math`

, vectors are stored in arrays of numbers (usually
three or four numbers), and functions dealing with vectors begin
with "vec".

If a 4-element vector describes a position or direction, the elements are given as X, Y, Z, and W, in that order.

If a 4-element vector describes a color, the elements are given as red, green, blue, and alpha, in that order (where each element ranges from 0-1).

If a 3D *direction* is used in a 4-element vector function (one beginning with "vec4"),
use 0 as the fourth element. If a 3D *position* (point) is used in a 4-element vector
function, the fourth element is generally 1. (If the
fourth element is anything other than 0, the vector is in *homogeneous
coordinates*, where the 3D position equals the first three elements divided
by the fourth.)

### Unit Vectors

A *unit vector* is a vector with a length of 1. (A vector's *length* is the square root
of the sum of the squares of its components.) A vector can be "normalized" to
a unit vector by dividing each of its components by its length (doing so won't change
the vector's direction).

The following functions normalize vectors and find their length.

- H3DU.Math.vec3normalize - Converts a 3-element vector to a unit vector.
- H3DU.Math.vec4normalize - Converts a 4-element vector to a unit vector.
- H3DU.Math.vec3length - Finds a 3-element vector's length.
- H3DU.Math.vec4length - Finds a 4-element vector's length.

Note that due to rounding error, normalizing a vector with an `H3DU.Math`

method
might not necessarily result in a vector with a length of 1.

## Matrices

A matrix is a rectangular array that can describe a transformation from one coordinate system to another. Transformations include translation (shifting), scaling, and rotation. Functions dealing with matrices begin with "mat". A 3x3 or 4x4 matrix has 9 or 16 elements, respectively. For more details, see the Matrix Details tutorial.

### Translation

A translation is a shifting of an object's position.

To create a translation matrix, use H3DU.Math.mat4translated(), and specify the X-offset, the Y-offset, and the Z-offset. For example, an X-offset of 1 moves an object 1 unit to the right, and a Y offset of -1 moves it 1 unit down.

To multiply an existing matrix by a translation, use H3DU.Math.mat4translate(). This will put the translation before the other transformations.

### Scaling

Scaling changes an object's size.

To create a scaling matrix, use H3DU.Math.mat4scaled(), and specify the scaling factors for the X, Y, and Z axis. Each point is multiplied by the scaling factors to change the object's size. For example, a Y-factor of 2 doubles an object's height.

To multiply an existing matrix by a scaling, use H3DU.Math.mat4scale(). This will put the scaling before the other transformations.

### Rotation

Rotation changes an object's orientation.

To create a rotation matrix, use H3DU.Math.mat4rotated(), and specify the angle (in degrees) to rotate, and the axis of rotation. For example:

- Specifying
`(45, [1, 0, 0])`

means a 45-degree rotation of the point around the X axis. - Specifying
`(80, [0, 2, 3])`

means a 45-degree rotation of the point around the axis that starts at the origin (0, 0, 0) and points toward the point (0, 2, 3).

When describing an axis of rotation, `[1, 0, 0]`

is the X axis,
`[0, 1, 0]`

is the Y axis, and `[0, 0, 1]`

is the Z axis.

To multiply an existing matrix by a rotation, use H3DU.Math.mat4rotate(). This will put the rotation before the other transformations.

### Combining Transforms

The order in which you do transforms is important. In general, scaling then translating is not the same as translating then scaling. Assuming your geometry is centered at the origin (0, 0, 0), you should create a transformation in this order:

- Call
`H3DU.Math.mat4identity()`

, creating a matrix without a transformation. - Do your translations if needed, using
`mat4translate()`

. - Do your rotations if needed, using
`mat4rotate()`

. - Do your scalings if needed, using
`mat4scale()`

.

This way, the scalings and rotations will affect the object while it's still centered, and before the translations (shifts) take place.

You can also multiply transforms using H3DU.Math.mat4multiply(). This takes two matrices and returns one combined matrix. The combined matrix will have the effect of doing the second matrix's transform, then the first matrix's transform.

## Describing Rotations

Rotations in 3D space can be described in many ways, including quaternions, Tait-Bryan angles, and an angle and axis.

### Axis of Rotation

A rotation of vectors or points can be described using an *angle*
and an *axis of rotation*, for example, in the H3DU.Math.mat4rotate method.

An axis of rotation is a vector pointing in a certain direction. When a point (or vector)
is rotated at any angle around this axis, the new point (or vector) will lie
on the same plane as the previous point. The axis of rotation describes
a vector that is perpendicular to that plane's surface (the plane's *normal*).
Here are examples of an axis of rotation.

- The X axis of rotation (upward or downward turn) is (1, 0, 0).
- The Y axis of rotation (leftward or rightward turn) is (0, 1, 0).
- The Z axis of rotation (side-by-side sway) is (0, 0, 1).

While the axis of rotation points toward the viewer, if the angle's value is positive and the coordinate system is...

- ...right handed, then the angle runs counterclockwise.
- ...left handed, then the angle runs clockwise.

While the axis of rotation points toward the viewer, if the angle's value is negative, then the angle runs in the opposite direction.

Vectors that point in the same direction (for example, vectors (1, 0, 0) and (2, 0, 0)) describe the same axis of rotation.

Unless stated otherwise, an axis of rotation passed to an `H3DU.Math`

method need not be a unit vector.

### Quaternions

A quaternion is a 4-element vector that can describe a 3D rotation. Functions dealing with quaternions begin with "quat".

#### Generating Quaternions

Functions that generate quaternions include:

- H3DU.Math.quatIdentity - Generates a quaternion describing an absence of rotations.
- H3DU.Math.quatFromVectors - Generates a quaternion describing a rotation from one vector to another.
- H3DU.Math.quatFromMat4 - Generates a quaternion from a 4x4 matrix.
- H3DU.Math.quatFromAxisAngle - Generates a quaternion from an angle and axis of rotation.
- H3DU.Math.quatFromTaitBryan - Generates a quaternion from Tait-Bryan angles.

#### Using Quaternions

For best results when using quaternions:

- Store the rotation of each object as a single quaternion.
- As rotations happen each frame, convert the rotation (which may be in pitch/yaw/roll or another form, depending on the input device) to a quaternion (see "Generating Quaternions" and multiply that quaternion by the current quaternion to get the object's new rotation.
- Normalize the rotation quaternion (using
`quatNormalize()`

or`quatNormalizeInPlace()`

) every few frames. (Quaternions that describe a 3D rotation should be unit vectors.)

#### Multiplying Quaternions

When two quaternions are multiplied (for example, with {@H3DU.Math.quatMultiply}), the result is a combined rotation in which the second rotation happens before the first rotation (when applied in the global coordinate frame). Like matrix multiplication, the order in which you multiply quaternions is important.

### Tait-Bryan angles

Pitch-yaw-roll angles (also called Tait-Bryan angles) describe three different rotations of the same vector around three different axes, called the pitch, yaw, and roll axes (or the X, Y, Z axes, respectively), which occur one after the other. However:

- There are multiple conventions for pitch-yaw-roll angles, including the order of rotations (for example: pitch-roll-yaw, roll-pitch-yaw), and whether the rotations occur around the object's original axes ("extrinsic") or its new axes ("intrinsic").
- Rotations are multiplied like in quaternions and matrices, so the order the rotations occur is important. For example, a 30-degree pitch followed by a 20-degree roll is not the same as a 20-degree pitch followed by a 30-degree roll.
- Pitch-yaw-roll angles can cause a problem called "gimbal lock", in which a rotation along one axis (say, a pitch) can cause a vector to be parallel to another axis (say, the roll axis), so that a rotation along that axis will do nothing.

Related functions:

- H3DU.Math.quatFromTaitBryan() - Converts from Tait-Bryan angles to a quaternion
- H3DU.Math.quatToTaitBryan() - Converts from a quaternion to Tait-Bryan angles

### 4x4 Matrices

A 4x4 matrix can describe a 3D vector rotation; see "Rotation", above.

## Planes

A 4-element array can describe a plane in the following manner:

The 4 elements, labeled A, B, C, and D in that order, describe a plane whose points satisfy the equation:

Ax + By + Cz + D = 0

where x, y, and z are the coordinates of any point lying on the plane.

- A, B, and C are the X, Y, and Z components of the plane's normal vector.
- D is the signed distance from the plane to the origin (0,0,0). It's positive if the plane's normal points toward the origin, and negative if it points away from the origin.
- D is the negative dot product of the plane's normal and any point on the plane.

There is one method that deals with planes:

- H3DU.Math.planeNormalizeInPlace - Converts the plane to a form in which its normal has a length of 1.

## Boxes

An array of six numbers can describe an axis-aligned bounding box (AABB). If it does, the first three numbers are the box's minimum X, Y, and Z coordinates, and the last three numbers are the box's maximum X, Y, and Z coordinates.

If a minimum coordinate is greater than a maximum coordinate, then the box is considered empty.

Methods that deal with boxes include:

- H3DU.Math.boxCenter - Finds a box's center.
- H3DU.Math.boxDimensions - Finds a box's dimensions.
- H3DU.Math.boxIsEmpty - Determines whether a box is empty.

## Coordinate Systems

There are two conventions of 3D coordinate systems, left-handed and right-handed:

- In a
*left-handed*coordinate system, the positive Z axis points*away from the viewer*whenever the positive X axis points to the right and the positive Y axis points up. - In a
*right-handed*coordinate system, the positive Z axis points*toward the viewer*whenever the positive X axis points to the right and the positive Y axis points up.

To show this more visually, point one hand's thumb to your right and its index finger up, and bend the other three fingers halfway down. In a coordinate system named after that hand (left-handed or right-handed), if the positive X axis points in the thumb's direction and the positive Y axis points in the index finger's direction, the Z axis will point in the direction the other three fingers point.

As used here, the Z axis is the cross product of two perpendicular axes, namely the X axis and the Y axis, in that order. Which of the X, Y, or Z axes is the right, up, or forward axis is essentially arbitrary; for example, some conventions may have the Z axis, rather than Y, be the up axis. Therefore, these three axes are defined here to avoid confusion.

### Differences in Behavior

#### Projection and view matrices

The difference between a left-handed and right-handed coordinate system affects how 3D points are transformed, mainly in the projection and view matrices. The projection and view matrices returned by H3DU.Math matrix methods are designed for a right-handed coordinate system. Their documentation describes how to adjust them for a left-handed coordinate system.

#### Rotation angles (such as used in `mat4rotate`

and `quatRotate`

)

While the axis of rotation points toward the viewer, if the angle's value is positive and the coordinate system is...

- ...right handed, then the angle runs counterclockwise.
- ...left handed, then the angle runs clockwise.

While the axis of rotation points toward the viewer, if the angle's value is negative, then the angle runs in the opposite direction.

#### Cross product (`vec3cross`

) and normals

Given a triangle formed by...

- points (A minus C), (B minus C), and C, in that order, or
- points A, B, and (0, 0, 0), in that order,

the cross product of the first point with the second,
in that order, is a *normal* of that triangle (a vector that's perpendicular to the triangle's surface).

While this particular normal points toward the viewer, the triangle's vertices run in a counterclockwise path for right-handed coordinate systems, or a clockwise path for left-handed systems. (In general, there are two possible choices for normals, which each point in opposite directions.)

### Winding and face classification

A two-dimensional triangle has counterclockwise *winding* if its vertices are ordered in a counterclockwise path from the first to second to third to first vertex. Otherwise, it has clockwise winding. If the triangle is in 3D space, it's first transformed into 2D *window coordinates* before its winding is found. (Window coordinates roughly correspond to screen pixels.)

By default, triangles with counterclockwise winding are *front faces*, and
other triangles are *back faces*. To change which kinds of triangles are
front faces, call the `frontFace`

method of Scene3D.

#### Finding a triangle's winding

To find a triangle's winding, do the following calculation (X1, X2, X3 and Y1, Y2, Y3 are the window coordinates of its vertices). Note that half of the result will be the triangle's signed area.

(X3 - X1) * (Y3 - Y2) - (X3 - X2) * (Y3 - Y1)

If the result is positive, and the window space X axis points right and the positive Y axis points...

- ...up (which is the case in WebGL), then the triangle has counterclockwise winding.
- ...down, then the triangle has clockwise winding.

If the result is negative, then the triangle has the opposite winding.