Skip to content
fabian-flassig edited this page Jun 8, 2026 · 2 revisions

The pyvec.* api functions provide vector, matrix and plane math for 3D plugin work.

PYTHA has no built-in math type system, so historically every plugin re-implemented its own vec3 / mat4 helpers. The pyvec namespace fills that gap with a small, dependency-free library.

A vec3 is a plain Lua array {x, y, z} carrying a metatable. Because PYTHA coordinate parameters are themselves {x, y, z} arrays (see Axes and Directions), a vec3 can be passed directly into any pytha.* function that expects a point or direction — no conversion needed. Conversely, the free functions (pyvec.dot, pyvec.cross, ...) also accept ordinary {x, y, z} tables returned by the API; only the arithmetic operators require a real vec3.

A mat4 is a 4×4 affine transform stored row-major as a flat array of 16 numbers (the element at row r, column c is index (r-1)*4 + c). The bottom row is assumed to be {0, 0, 0, 1}.

A plane is stored as {normal, d} with a unit normal satisfying normal · p + d = 0.

All angles are in degrees, consistent with PYTHA's global math helpers.

vec3 — construction

Function Description
pyvec.vec3(x, y, z) Creates a vec3 from three numbers. Missing components default to 0.
pyvec.vec3{x, y, z} Creates a vec3 from (clones) an existing point table — handy to wrap an API return value.

vec3 — functions

These are free functions and are also available as methods, e.g. a:dot(b) is the same as pyvec.dot(a, b).

Function Description
pyvec.dot(a, b) Dot product (number).
pyvec.cross(a, b) Cross product (vec3).
pyvec.length(v) Euclidean length (number).
pyvec.length_sq(v) Squared length (number); avoids the square root.
pyvec.normalize(v) Returns the unit vector and, as a second value, the original length. A zero vector returns (0, 0, 0) and length 0.
pyvec.distance(a, b) Distance between two points.
pyvec.distance_sq(a, b) Squared distance between two points.
pyvec.scale(v, s) v scaled by the scalar s (vec3).
pyvec.lerp(a, b, t) Linear interpolation; t = 0a, t = 1b.
pyvec.angle_between(a, b) Angle between the two vectors in degrees (0..180).
pyvec.approx_equal(a, b [, eps]) Component comparison with tolerance eps (default 1e-9).

vec3 — operators

Operator Result
a + b, a - b Component-wise addition / subtraction (vec3).
-a Negation (vec3).
a * s, s * a Scalar multiplication (vec3).
a / s Scalar division (vec3).
a == b Exact component equality. Use pyvec.approx_equal for a tolerant compare.
tostring(a) "vec3(x, y, z)".

a * b between two vec3 raises an error on purpose — the intent is ambiguous. Use pyvec.dot or pyvec.cross explicitly.

mat4

Function Description
pyvec.mat4(...) Builds a matrix from 16 numbers or a 16-element table. With no arguments it returns the identity.
pyvec.identity() Identity matrix.
pyvec.translation(t) Translation by the point/vec3 t.
pyvec.scaling(s) Uniform scale (number) or per-axis scale (point/vec3).
pyvec.rotation(axis, angle) Rotation about axis through the origin by angle degrees. Right-handed: a positive angle turns counter-clockwise looking down the axis.
pyvec.from_axes(origin, u, v, w) Transform whose columns are the given axes and origin; maps local coordinates to world. The axes are used verbatim and are not orthonormalized.
pyvec.frame(origin, u_dir, w_dir) Builds an orthonormal right-handed frame (u × v = w) from a primary direction u_dir and an approximate up direction w_dir. Mirrors PYTHA's own axis correction (see Axes and Directions).
pyvec.mat_multiply(a, b) Matrix product a · b (mat4).
pyvec.transform_point(mat, p) Transforms point p, applying translation (vec3).
pyvec.transform_vector(mat, d) Transforms direction d, ignoring translation (vec3).
pyvec.transpose(mat) Transposed matrix.
pyvec.inverse(mat) Matrix inverse via Gauss-Jordan elimination. Raises an error if mat is singular. Useful for world → local conversion.

Operators and methods:

Operator / method Result
mat * other Matrix product, when both operands are mat4.
mat * p Transforms the point p, when p is a point/vec3 — same as transform_point.
mat:transform_point(p), mat:transform_vector(d), mat:multiply(other), mat:transpose(), mat:inverse() Method forms of the functions above.
tostring(mat) Formatted 4×4 layout.

plane

Function Description
pyvec.plane(point, normal) Plane through point with the given normal (normalized internally).
pyvec.plane_from_points(a, b, c) Plane through three points; the normal follows the right-hand rule for the order a → b → c.
pyvec.signed_distance(pl, p) Signed distance from p to the plane; positive on the side the normal points to.
pyvec.project_point(pl, p) Orthogonal projection of p onto the plane (vec3).

Methods: pl:signed_distance(p), pl:project_point(p).

Type checks

Function Description
pyvec.is_vec3(v) true if v is a pyvec vec3.
pyvec.is_mat4(m) true if m is a pyvec mat4.
pyvec.is_plane(p) true if p is a pyvec plane.

Example

-- Build an orthonormal frame from a wall direction and world up.
local origin = pyvec.vec3(1.0, 0.5, 0.0)
local frame  = pyvec.frame(origin, pyvec.vec3(1, 1, 0), pyvec.vec3(0, 0, 1))

-- A point given in the frame's local coordinates, expressed in world space.
local world_pt = frame:transform_point(pyvec.vec3(0.2, 0.0, 0.8))

-- world_pt is a {x, y, z} array and can be passed straight to pytha.*:
pytha.create_block(world_pt, 0.1, 0.1, 0.1)

-- Go the other way: world -> local.
local local_pt = frame:inverse():transform_point(world_pt)

-- Distance of a point from a plane through three corners.
local pl = pyvec.plane_from_points(
    pyvec.vec3(0, 0, 0), pyvec.vec3(1, 0, 0), pyvec.vec3(0, 1, 0))
local d = pl:signed_distance(pyvec.vec3(0, 0, 2))   -- 2.0

Version Support:

Minimum PYTHA Version: V27

See also:

Math functions, Axes and Directions, pytha.push_local_coordinates, pytha.rotate_element, pygeo

Clone this wiki locally