-
Notifications
You must be signed in to change notification settings - Fork 26
Matrix
Two matrix classes are supplied, Matrix3, a 3x3 matrix for working with 2D affine transformations, and Matrix4, a 4x4 matrix for working with 3D affine transformations.
The default constructor intializes the matrix to the identity:
>>> Matrix3() Matrix3([ 1.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 1.00]) >>> Matrix4() Matrix4([ 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00])
Internally each matrix is stored as a set of attributes named a
to p
.
The layout for Matrix3 is:
# a b c # e f g # i j k
and for Matrix4:
# a b c d # e f g h # i j k l # m n o p
If you wish to set or retrieve a number of elements at once, you can do so with a slice:
>>> m = Matrix4() >>> m[:] [1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0] >>> m[12:15] = (5, 5, 5) >>> m Matrix4([ 1.00 0.00 0.00 5.00 0.00 1.00 0.00 5.00 0.00 0.00 1.00 5.00 0.00 0.00 0.00 1.00])
Note that slices operate in column-major order, which makes them
suitable for working directly with OpenGL's glLoadMatrix
and
glGetFloatv
functions.
There are class constructors for the most common types of transform.
new_identity
-
Equivalent to the default constructor. Example:
>>> m = Matrix4.new_identity() >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00])
-
new_scale(x, y)
andnew_scale(x, y, z)
-
The former is defined on Matrix3, the latter on Matrix4. Equivalent to the OpenGL call
glScalef
. Example:>>> m = Matrix4.new_scale(2.0, 3.0, 4.0) >>> m Matrix4([ 2.00 0.00 0.00 0.00 0.00 3.00 0.00 0.00 0.00 0.00 4.00 0.00 0.00 0.00 0.00 1.00])
-
new_translate(x, y)
andnew_translate(x, y, z)
-
The former is defined on Matrix3, the latter on Matrix4. Equivalent to the OpenGL call
glTranslatef
. Example:>>> m = Matrix4.new_translate(3.0, 4.0, 5.0) >>> m Matrix4([ 1.00 0.00 0.00 3.00 0.00 1.00 0.00 4.00 0.00 0.00 1.00 5.00 0.00 0.00 0.00 1.00])
new_rotate(angle)
-
Create a Matrix3 for a rotation around the origin. angle is specified in radians, anti-clockwise. This is not implemented in Matrix4 (see below for equivalent methods). Example:
>>> import math >>> m = Matrix3.new_rotate(math.pi / 2) >>> m Matrix3([ 0.00 -1.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00])
The following constructors are defined for Matrix4 only.
new
- Construct a matrix with 16 values in column-major order.
-
new_rotatex(angle)
,new_rotatey(angle)
,new_rotatez(angle)
-
Create a Matrix4 for a rotation around the X, Y or Z axis, respectively. angle is specified in radians. Example:
>>> m = Matrix4.new_rotatex(math.pi / 2) >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 0.00 -1.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00])
new_rotate_axis(angle, axis)
-
Create a Matrix4 for a rotation around the given axis. angle is specified in radians, and axis must be an instance of Vector3. It is not necessary to normalize the axis. Example:
>>> m = Matrix4.new_rotate_axis(math.pi / 2, Vector3(1.0, 0.0, 0.0)) >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 0.00 -1.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00])
new_rotate_euler(heading, attitude, bank)
-
Create a Matrix4 for the given Euler rotation. heading is a rotation around the Y axis, attitude around the X axis and bank around the Z axis. All rotations are performed simultaneously, so this method avoids "gimbal lock" and is the usual method for implemented 3D rotations in a game. Example:
>>> m = Matrix4.new_rotate_euler(math.pi / 2, math.pi / 2, 0.0) >>> m Matrix4([ 0.00 -0.00 1.00 0.00 1.00 0.00 -0.00 0.00 -0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00])
new_perspective(fov_y, aspect, near, far)
-
Create a Matrix4 for projection onto the 2D viewing plane. This method is equivalent to the OpenGL call
gluPerspective
. fov_y is the view angle in the Y direction, in radians. aspect is the aspect ration width / height of the viewing plane. near and far are the distance to the near and far clipping planes. They must be positive and non-zero. Example:>>> m = Matrix4.new_perspective(math.pi / 2, 1024.0 / 768, 1.0, 100.0) >>> m Matrix4([ 0.75 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 -1.02 -2.02 0.00 0.00 -1.00 0.00])
Matrices of the same dimension may be multiplied to give a new matrix. For example, to create a transform which translates and scales:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m2 = Matrix3.new_scale(1.0, 2.0) >>> m1 * m2 Matrix3([ 1.00 0.00 5.00 0.00 2.00 6.00 0.00 0.00 1.00])
Note that multiplication is not commutative (the order that you apply transforms matters):
>>> m2 * m1 Matrix3([ 1.00 0.00 5.00 0.00 2.00 12.00 0.00 0.00 1.00])
In-place multiplication is also permitted (and optimised):
>>> m1 *= m2 >>> m1 Matrix3([ 1.00 0.00 5.00 0.00 2.00 6.00 0.00 0.00 1.00])
Multiplying a matrix by a vector returns a vector, and is used to transform a vector:
>>> m1 = Matrix3.new_rotate(math.pi / 2) >>> m1 * Vector2(1.0, 1.0) Vector2(-1.00, 1.00)
Note that translations have no effect on vectors. They do affect points, however:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m1 * Vector2(1.0, 2.0) Vector2(1.00, 2.00) >>> m1 * Point2(1.0, 2.0) Point2(6.00, 8.00)
Multiplication is currently incorrect between matrices and vectors -- the projection component is ignored. Use the Matrix4.transform method instead.
Matrix4 also defines transpose (in-place), transposed (functional), determinant and inverse (functional) methods.
A Matrix3 can be multiplied with a Vector2 or any of the 2D geometry objects (Point2, Line2, Circle, etc).
A Matrix4 can be multiplied with a Vector3 or any of the 3D geometry objects (Point3, Line3, Sphere, etc).
For convenience, each of the matrix constructors are also available as in-place operators. For example, instead of writing:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m2 = Matrix3.new_scale(1.0, 2.0) >>> m1 *= m2
you can apply the scale directly to m1:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m1.scale(1.0, 2.0) Matrix3([ 1.00 0.00 5.00 0.00 2.00 6.00 0.00 0.00 1.00]) >>> m1 Matrix3([ 1.00 0.00 5.00 0.00 2.00 6.00 0.00 0.00 1.00])
Note that these methods operate in-place (they modify the original matrix), and they also return themselves as a result. This allows you to chain transforms together directly:
>>> Matrix3().translate(1.0, 2.0).rotate(math.pi / 2).scale(4.0, 4.0) Matrix3([ 0.00 -4.00 1.00 4.00 0.00 2.00 0.00 0.00 1.00])
All constructors have an equivalent in-place method. For Matrix3, they
are identity
, translate
, scale
and rotate
. For Matrix4,
they are identity
, translate
, scale
, rotatex
, rotatey
,
rotatez
, rotate_axis
and rotate_euler
. Both Matrix3 and
Matrix4 also have an in-place transpose
method.
The copy
method is also implemented in both matrix classes and
behaves in the obvious way.