Zinggi/elm-webgl-math/1.0.5

NOTE: this package is not compatible with Elm 0.19.1

Matrix4

This module deals mostly with 3D transformation matrices.

We can represent a transformation of a 3D vector as a multiplication with a 4x4 matrix by writing the vector in homogeneous coordinates.

Here are a few useful links if you want to understand the math behind this library.

http://learnopengl.com/#!Getting-started/Transformations http://www.codinglabs.net/article_world_view_projection_matrix.aspx http://www.euclideanspace.com/maths/geometry/affine/index.htm

type alias Float4x4 =
Mat4 Float
type alias Mat4 a =
( Vec4 a, Vec4 a, Vec4 a, Vec4 a )

General operations

map : (a -> b) -> Mat4 a -> Mat4 b
map2 : (a -> b -> c) -> Mat4 a -> Mat4 b -> Mat4 c
foldl : (elem -> acc -> acc) -> acc -> Mat4 elem -> acc
foldr : (elem -> acc -> acc) -> acc -> Mat4 elem -> acc

General math

identity : Float4x4

The identity matrix. This is also a valid transformation matrix which doesn't do anything.

I = |1 0 0 0|
    |0 1 0 0|
    |0 0 1 0|
    |0 0 0 1|
fromRows : Float4 -> Float4 -> Float4 -> Float4 -> Float4x4
fromRows a b c d == (a,b,c,d)
fromColumns : Float4 -> Float4 -> Float4 -> Float4 -> Float4x4
fromColumns a b c d == transpose (a,b,c,d)
add : Float4x4 -> Float4x4 -> Float4x4

A + B

sub : Float4x4 -> Float4x4 -> Float4x4

A - B

mul : Float4x4 -> Float4x4 -> Float4x4

A*B

elementWiseMul : Float4x4 -> Float4x4 -> Float4x4

Element wise multiplication. Also called Hadamard product, Schur product or entrywise product.

A .* B
mulByConst : Float -> Float4x4 -> Float4x4

a*A

transpose : Float4x4 -> Float4x4

The transpose. Flips a matrix along it's diagonal.

A^T

mulVector : Float4x4 -> Float4 -> Float4

A*v

Transformation matrices

A transformation matrix represents an arbitrary transform on a 3d vector. To transform a 3d vector v, we multiply it with a 4x4 transformation matrix M. To do that we need to write v in homogeneous coordinates, then transform the result back to normal coordinates.

    |v|   |v'|
M * |1| = |w |,
res = v'/w

These transformations can be chained, e.g. you can apply several transformations in series. Note that to understand how a vector will be transformed, it helps to read it backwards:

T*R*S*v

Means that v will be scaled by the matrix S, then rotated by R and finally translated by T.

transform : Float4x4 -> Float3 -> Float3

Transform a vector by an arbitrary transformation matrix. In math terms, we do:

|v'| = A*|v|  v'/w
|w |     |1|,

Affine transformations

These represent a transform that preserves shapes, e.g. translations, rotations and scaling. These are composed of a 3x3 rotation and scale matrix M and a translation vector t:

|M t|
|0 1|
makeRotate : Float -> Float3 -> Float4x4

Creates a rotation matrix R. This represents a rotation of angle degrees (in radians) around the vector specified by axis. The rotation is specified according to the right hand rule.

makeScale : Float3 -> Float4x4

Create a scale matrix S.

makeTranslate : Float3 -> Float4x4

Create a translation matrix T

makeTransform : Float3 -> Float3 -> Float -> Float3 -> Float3 -> Float4x4

Creates an affine transform given a translation, a scale, a rotation and a pivot vector. The pivot is the 'center' of the rotation and scaling operation.

makeTransform translation scale angle rotationAxis pivot
rotate : Float -> Float3 -> Float4x4 -> Float4x4

Rotate an affine transform by an angle along the given axis.

scale : Float3 -> Float4x4 -> Float4x4

Scale an affine transform with the given vector. Same as M*makeScale(s)

translate : Float3 -> Float4x4 -> Float4x4

Translate an affine transform by the given vector. Same as M*makeTranslate(t)

transformBy : Float3 -> Float3 -> Float -> Float3 -> Float3 -> Float3 -> Float3

Transform a vector by the transformation specified in the parameters

transformBy translation scale angle rotationAxis pivot v

TODO: does it make sense for these to be post multiplied? This means that currently these operations will be done before doing the transform, meaning they will act as local transformations. However this makes creating a composed transformation weird, as the order of operations might be counter-intuitive! E.g. identity |> translate |> rotate actually corresponds to I*T*R which means rotate first, then translate.

makeLookAt : Float3 -> Float3 -> Float3 -> Float4x4

Create a transform that makes a 3D object look at the target. Very often used with cameras to make them look at a target. The up vector is usually (0, 1, 0), e.g. the y-axis. (some people also use the z-axis)

makeLookAt cameraPosition target (0, 1, 0)
makeBasis : Float3 -> Float3 -> Float3 -> Float4x4

Create an affine transform from 3 orthogonal (perpendicular) vectors. Make sure xAxis yAxis zAxis are really orthonormal, otherwise you won't get an affine transform! Only use this if you know what you are doing.

makeBasis (1, 0, 0) (0, 1, 0) (0, 0, 1) == identity

Operations on affine transforms

These can speed up some calculations, but are only correct if actually used with affine transforms.

transformAffine : Float4x4 -> Float3 -> Float3

Same as transform, but a bit faster. Only correct if used with an affine transform!

mulAffine : Float4x4 -> Float4x4 -> Float4x4

Multiply two affine transforms. Same as mul but a bit faster. Only correct if used with an affine transform!

inverseRigidBodyTransform : Float4x4 -> Float4x4

Calculate the inverse of a rigid body transform. This a special form of affine transform, that is only composed of rotations and translations.

| R t |^-1 = | R^T -R^T*t |
| 0 1 |      | 0    1     |

It's usually easier and faster to just do the construction of the matrix you want to invert in reverse, e.g.

inverseRigidBodyTransform (makeRotate 1.2 (0,1,0)) == makeRotate -1.2 (0,1,0)
inverseRigidBodyTransform (makeScale (2,3,1)) == makeScale (1/2,1/3,1)

Cameras

Cameras can also be represented as a transformation matrix. NOTE: These transforms are generally not affine transforms!

Camera projection matrices map their view of the scene into a 2x2x2 cube. Math heavy reference: http://www.songho.ca/opengl/gl_projectionmatrix.html

makeFrustum : Float -> Float -> Float -> Float -> Float -> Float -> Float4x4

Creates a matrix for a projection frustum.

makeFrustum left right bottom top znear zfar

http://www.songho.ca/opengl/gl_projectionmatrix.html

makePerspective : Float -> Float -> Float -> Float -> Float4x4

Creates a matrix for a perspective projection.

makePerspective fovy aspect znear zfar

fovy - field of view in the y axis, in degrees aspect - aspect ratio znear - the near z distance of the projection zfar - the far z distance of the projection

makeOrtho : Float -> Float -> Float -> Float -> Float -> Float -> Float4x4

This creates an orthographic projection.

makeOrtho left right bottom top znear zfar
makeOrtho2d : Float -> Float -> Float -> Float -> Float4x4

Same as makeOrtho, but with znear = -1 and zfar = 1 set.

makeOrtho2d left right bottom top

Other

maxNorm : Float4x4 -> Float

The max norm. This is the biggest element of a matrix. Useful for fuzz testing.

almostEqual : Float -> Float4x4 -> Float4x4 -> Bool

This checks whether |A - B| <= eps.

almostEqual eps a b

This is useful for testing, see the tests of this library for how this makes testing easy.

Since any definition of a norm can be used for this, it uses the simple maxNorm