Vectors

Edit

LÖVR has math objects for vectors, matrices, and quaternions, collectively called "vector objects". Vectors are useful because they can represent a multidimensional quantity (like a 3D position) using just a single value.

Constructors

lovr.math.vec2Create a temporary Vec2.
lovr.math.vec3Create a temporary Vec3.
lovr.math.vec4Create a temporary Vec4.
lovr.math.quatCreate a temporary Quat.
lovr.math.mat4Create a temporary Mat4.
lovr.math.newVec2Create a new Vec2.
lovr.math.newVec3Create a new Vec3.
lovr.math.newVec4Create a new Vec4.
lovr.math.newQuatCreate a new Quat.
lovr.math.newMat4Create a new Mat4.

Notes

Most LÖVR functions that accept positions, orientations, transforms, velocities, etc. also accept vector objects, so they can be used interchangeably with numbers:

function lovr.draw(pass)
  -- position and size are vec3's, rotation is a quat
  pass:box(position, size, rotation)
end

Temporary vs. Permanent

Vectors can be created in two different ways: permanent and temporary.

Permanent vectors behave like normal Lua values. They are individual objects that are garbage collected when no longer needed. They're created using the usual lovr.math.new<Type> syntax:

self.position = lovr.math.newVec3(x, y, z)

Temporary vectors are created from a shared pool of vector objects. This makes them faster because they use temporary memory and do not need to be garbage collected. To make a temporary vector, leave off the new prefix:

local position = lovr.math.vec3(x, y, z)

As a shortcut, vector constructors are placed on the global scope. The uppercase name of the vector is a function that will create a permanent vector, and the lowercase name will create a temporary vector. This can be disabled using the t.math.globals option in lovr.conf.

local position = vec3(x1, y1, z1) + vec3(x2, y2, z2)
local transform = Mat4()

Temporary vectors, with all their speed, come with an important restriction: they can only be used during the frame in which they were created. Saving them into variables and using them later on will throw an error:

local position = vec3(1, 2, 3)

function lovr.update(dt)
  -- Reusing the temporary 'position' vector across frames will error:
  position:add(vec3(dt))
end

It's possible to overflow the temporary vector pool. If that happens, lovr.math.drain can be used to periodically drain the pool, invalidating any existing temporary vectors.

Metamethods

Vectors have metamethods, allowing them to be used using the normal math operators like +, -, *, /, etc.

print(vec3(2, 4, 6) * .5 + vec3(10, 20, 30))

These metamethods will create new temporary vectors.

Components and Swizzles

The raw components of a vector can be accessed like normal fields:

print(vec3(1, 2, 3).z) --> 3
print(mat4()[16]) --> 1

Also, multiple fields can be accessed and combined into a new (temporary) vector, called swizzling:

local position = vec3(10, 5, 1)
print(position.xy) --> vec2(10, 5)
print(position.xyy) --> vec3(10, 5, 5)
print(position.zyxz) --> vec4(1, 5, 10, 1)

The following fields are supported for vectors:

Quaternions support x, y, z, and w.

Matrices use numbers for accessing individual components in "column-major" order.

All fields can also be assigned to.

-- Swap the components of a 2D vector
v.xy = v.yx

The unpack function can be used (on any vector type) to access all of the individual components of a vector object. For quaternions you can choose whether you want to unpack the angle/axis representation or the raw quaternion components. Similarly, matrices support raw unpacking as well as decomposition into translation/scale/rotation values.

Vector Constants

The following vector constants are available. They return new temporary vectors each time they are used:

See also