Vectors
EditLÖ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.vec2 | Create a temporary Vec2. |
lovr.math.vec3 | Create a temporary Vec3. |
lovr.math.vec4 | Create a temporary Vec4. |
lovr.math.quat | Create a temporary Quat. |
lovr.math.mat4 | Create a temporary Mat4. |
lovr.math.newVec2 | Create a new Vec2. |
lovr.math.newVec3 | Create a new Vec3. |
lovr.math.newVec4 | Create a new Vec4. |
lovr.math.newQuat | Create a new Quat. |
lovr.math.newMat4 | Create 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:
x
,y
,z
,w
r
,g
,b
,a
s
,t
,p
,q
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:
vec2.zero
(0, 0)vec2.one
(1, 1)vec3.zero
(0, 0, 0)vec3.one
(1, 1, 1)vec3.left
(-1, 0, 0)vec3.right
(1, 0, 0)vec3.up
(0, 1, 0)vec3.down
(0, -1, 0)vec3.back
(0, 0, 1)vec3.forward
(0, 0, -1)vec4.zero
(0, 0, 0, 0)vec4.one
(1, 1, 1, 1)quat.identity
(0, 0, 0, 1)