This is a guide about the different built-in math objects: vectors, matrices, and quaternions. All of these will be referred to as "vector objects" or just "vectors". Vectors are useful because they can represent a multidimensional quantity (like a 3D position) using just a single value.
-- Without vectors function object:update(dt) object.x = object.x + object.vx * dt object.y = object.y + object.vy * dt object.z = object.z + object.vz * dt end -- With vectors function object:update(dt) object.position:add(object.velocity * dt) end
The following vector types are supported:
quat, a quaternion.
mat4, a 4D matrix.
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() -- position and size are vec3's, rotation is a quat lovr.graphics.box('fill', position, size, rotation) end
Temporary vs. Permanent
Vectors can be created in two different ways: permanent and temporary.
Permanent vectors behave like normal LÖVR objects. They are individual objects that are garbage
collected when no longer needed. They're created using the usual
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
local position = lovr.math.vec3(x, y, z)
As a further shorthand, these vector constructors are placed on the global scope. If you prefer to
keep the global scope clean, this can be configured using the
t.math.globals flag in
local position = vec3(x1, y1, z1) + vec3(x2, y2, z2)
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 a temporary 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.
Vectors have metamethods, allowing them to be used using the normal math operators like
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()) --> 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:
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
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.
lovr.math for the detailed API reference pages for the different vector types.