Working with vectors and quaternions in Lua scripts

From Serious Sam Wiki
< Lua
Jump to: navigation, search


Lua scripts support manipulation with built in vectors and quaternions (and their parts) which are used when manipulating object's placement and velocities. This document describes those types and how to manipulate object of those types from Lua scripts.

Vector3f

Vector3f describes a point in 3D space. In scripts, Vector3f can be obtained as a return value from some script function or can be created using mthVector3f function (it accepts 3 values, x, y and z components of the vector, respectfully). Vector3f has three members: x, y, and x. Lets illustrate creation and manipulation of Vector3f objects on a simple example:

-- create a new Vector3f object and store it in local variable vPos
local vPos = mthVector3f(3, 4.5, 7.8)

-- print components of vPos
print("vPos = (" .. vPos.x .. "," .. vPos.y .. "," .. vPos.z .. ")")

-- set x component of vPos to 30
vPos.x = 30

-- add 5.6 to y component of vPos
vPos.y = vPos.y + 5.6

-- subtract 10 from z component of vPos
vPos.z = vPos.z - 10

-- print components of vPos once again
print("vPos = (" .. vPos.x .. "," .. vPos.y .. "," .. vPos.z .. ")")

It is also possible to perform simple operation with Vector3f: you can multiply or divide a Vector3f with a scalar (a number). When multiplying a Vector3f with a scalar, all components (x,y,z) are multiplied with it; when dividing a Vector3f with a scalar, all components are divided by it. You can also compare vectors for equality and inequality, using Lua == and ~= operators. Let's illustrate this on an example:

-- create a Vector3f
local vPos = mthVector3f(3, 6, 9)

-- print components of vPos
print("vPos = (" .. vPos.x .. "," .. vPos.y .. "," .. vPos.z .. ")")

-- multiply vPos with 3
vPos = 3*vPos -- same as vPos*3 

-- print components of vPos (should print "vPos = (9,18,27)
print("vPos = (" .. vPos.x .. "," .. vPos.y .. "," .. vPos.z .. ")")

-- divide vPos with 3
vPos = vPos/3


-- print components of vPos (should print "vPos = (3,6,9)
print("vPos = (" .. vPos.x .. "," .. vPos.y .. "," .. vPos.z .. ")")

-- compare vPos with a couple of vectors

local vPos2 = mthVector3f(3, 7, 9)

if vPos == vPos2 then
  print("vPos == vPos2") -- should not be printed
end

if vPos ~= vPos2 then
  print("vPos ~= vPos2") -- should be printed
end

if vPos == mthVector3f(3, 6, 9) then
  print("vPos == mthVector3f(3, 6, 9)") -- should be printed
end

Quaternion4f

Quaternion is usually used to specify orientations of objects or directions. In script code, quaternion are mostly constructed by specifying heading, pitch and banking angles. They are not intended to be directly modified as quaternions. Quaternions objects in script code have a dual nature: they are quaternions if used as quaternions, but they can also be used by manipulating heading, pitch and banking angles. Most of the users should only use h, p and b (heading, pitch and banking; *in radians!*) members of Quaternion4f in script code and completely ignore the 'real' quaternion members (x, y, z and w). Quaternion4f type in scripts also provides operators for addition, subtraction, multiplication and division but they are intended to be used by users that are familiar with quaternion internals and will not be explained here. If you wish to create a new Quaternion4f object, you can do so using the mthHPBToQuaternion function; function takes three arguments, heading, pitch and banking angles, respectively.

We can illustrate use of quaternions on an example:

-- create a quaternion specifying heading of 45 degrees, pitch of 10 degrees and banking of 5 degrees
local qRotation = mthHPBToQuaternion(mthDegToRad(45), mthDegToRad(10), mthDegToRad(5))

-- print heading, pitch and banking angles (watch out, they are in radians!)
print("qRotation = (" .. qRotation.h .. ", " .. qRotation.p .. ", " .. qRotation.b .. ")")

-- modify quaternion through members (set them to 30, 15 and 25 degrees, respectfully)
qRotation.h = mthDegToRad(30)
qRotation.p = mthDegToRad(15)
qRotation.b = mthDegToRad(25)

-- print heading, pitch and banking angles (watch out, they are in radians!)
print("qRotation = (" .. qRotation.h .. ", " .. qRotation.p .. ", " .. qRotation.b .. ")")

QuatVect

QuatVect is a pair of a Quaternion4f and a Vector3f. It is commonly used to specify placement of objects in 3D space. When you wish to obtain entity's placement, you typically use entity's GetPlacement member function which returns QuatVect object. Also, when you wish to set entity's placement, you typically use entity's SetPlacement member function which receives a QuatVect object which provides new placement. You can directly access vector part (using vx, vy and vz members) and quaternion part (using qh, qp and qb members) of a QuatVect. You can also obtain Vector3f part using the GetVect member function; set the Vector3f part using the SetVect function; obtain Quaternion4f part using the GetQuat member function; set the Quaternion4f part using the SetQuat function.

You can create new QuatVect object using the mthQuatVect function which takes two parameters, a Quaternion4f and a Vector3f, respectfully.

Lets illustrate the uses of QuatVect on an example:

-- create a QuatVect
local qvPlacement = mthQuatVect(mthHPBToQuaternion(mthDegToRad(20), mthDegToRad(5), mthDegToRad(15)), mthVector3f(5, 10, 20))

-- print components of QuatVect
print("qvPlacement.q = (" .. qvPlacement.qh .. ", " .. qvPlacement.qp .. ", " .. qvPlacement.qb .. 
  "), qvPlacement.v = (" .. qvPlacement.vx .. ", " .. qvPlacement.vy .. ", " .. qvPlacement.vz .. ")")

-- add 5 degrees to each quaternion component
qvPlacement.qh = qvPlacement.qh + mthDegToRad(5)
qvPlacement.qp = qvPlacement.qp + mthDegToRad(5)
qvPlacement.qb = qvPlacement.qb + mthDegToRad(5)

-- add 5 meters to each vector component
qvPlacement.vx = qvPlacement.vx + 5
qvPlacement.vy = qvPlacement.vy + 5
qvPlacement.vz = qvPlacement.vz + 5

-- print components of QuatVect
print("qvPlacement.q = (" .. qvPlacement.qh .. ", " .. qvPlacement.qp .. ", " .. qvPlacement.qb .. 
  "), qvPlacement.v = (" .. qvPlacement.vx .. ", " .. qvPlacement.vy .. ", " .. qvPlacement.vz .. ")")

-- set QuatVect as placement of static model entity 'treeModel'
treeModel:SetPlacement(qvPlacement)

-- get placement of 'barrelModel' into qvPlacement variable
qvPlacement = barrelModel:GetPlacement()

-- print components of QuatVect
print("qvPlacement.q = (" .. qvPlacement.qh .. ", " .. qvPlacement.qp .. ", " .. qvPlacement.qb .. 
  "), qvPlacement.v = (" .. qvPlacement.vx .. ", " .. qvPlacement.vy .. ", " .. qvPlacement.vz .. ")")