c4d.Matrix

Warning

The Matrix type does not support the function copy.copy().

Instead use the Matrix constructor:

import c4d

def main():
  if not op: return

  mat = op.GetMg()
  print "Matrix:", id(mat), mat

  ref = mat
  print "Reference:", id(ref), ref

  copy = c4d.Matrix(mat)
  print "Copy:", id(copy), copy


  if __name__=='__main__':
    main()

Members

Matrix.v1

The X axis of a left-handed coordinate system.

Type: Vector

Matrix.v2

The Y axis of a left-handed coordinate system.

Type: Vector

Matrix.v3

The Z axis of a left-handed coordinate system.

Type: Vector

Matrix.off

The translation vector.

Type: Vector

Matrix.__init__(off=Vector(0), v1=Vector(1, 0, 0), v2=Vector(0, 1, 0), v3=Vector(0, 0, 1))
Initalizes a new Matrix.
All arguments are optional so it is possible to create a new matrix without any arguments. All components are simply set to:
  • off = Vector(0)
  • v1 = Vector(1,0,0)
  • v2 = Vector(0,1,0)
  • v3 = Vector(0,0,1)
mat = c4d.Matrix()
# => Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0))

mat = c4d.Matrix()
mat.off = c4d.Vector(100,0,0)

v1 = c4d.Vector(3)
v2 = c4d.Vector(12,4,9.3)
v3 = c4d.Vector(9,80,3)
off = c4d.Vector(v1+v2)
mat = c4d.Matrix(off,v1,v2,v3)
Parameters:
  • off (c4d.Vector) – The translation vector.
  • v1 (c4d.Vector) – The X axis of a left-handed coordinate system.
  • v2 (c4d.Vector) – The Y axis of a left-handed coordinate system.
  • v3 (c4d.Vector) – The Z axis of a left-handed coordinate system.
Return type:

c4d.Matrix

Returns:

A new matrix.

Matrix.__str__()

Returns the Matrix as string. Called if str() is wrapped around an instance of Matrix. (See __str__):

v1 = c4d.Vector(3)
v2 = c4d.Vector(12,4,9.3)
v3 = c4d.Vector(9,80,3)
off = c4d.Vector(v1+v2)
mat = c4d.Matrix(off,v1,v2,v3)
print mat
# => Matrix(v1: (3, 3, 3); v2: (12, 4, 9.3); v3: (12, 4, 9.3); off: (15, 7, 12.3))
Return type:str
Returns:The Vector as string.
Matrix.__add__(other)

Adds two matrices.

Parameters:other (c4d.Matrix) – The other matrix.
Return type:c4d.Matrix
Returns:The result matrix.
Matrix.__sub__(other)

Subtracts two matrices.

Parameters:other (c4d.Matrix) – The other matrix.
Return type:c4d.Matrix
Returns:The result matrix.
Matrix.__mul__(other)
Multiplies a matrix or vector by the matrix. Can also scale each vector of the matrix by a scalar.

If both objects are of type Matrix, multiplies the left hand matrix by the right hand matrix.
If the left object is of type Matrix and the right one of type Vector, multiplies the vector by the matrix including any translation in the matrix.
If the left object is of type Vector and the right one of type Matrix, multiplies the vector by the matrix including any translation in the matrix.
If the right object is a number, multiplies each vector of the matrix by it.
Parameters:other (Union[c4d.Vector, int, float]) – The other argument.
Return type:c4d.Vector
Returns:The result matrix or vector.
Matrix.__div__(other)

Divides each element in the matrix by a scalar.

Parameters:other (float) – The scalar.
Return type:c4d.Matrix
Returns:The result matrix.
Matrix.__invert__()

Inverts the matrix.

Return type:c4d.Matrix
Returns:The inverted matrix.
Matrix.__eq__(other)

Checks if two matrices are equal.

Parameters:other (c4d.Matrix) – The other matrix.
Return type:bool
Returns:True if matrices are equal.
Matrix.__ne__(other)

Checks if two vectors are not equal.

Parameters:other (c4d.Matrix) – The other matrix.
Return type:bool
Returns:True if matrices are not equal.
Matrix.Normalize()

Normalizes the matrix.

Matrix.GetNormalized()

Calculates the normalized matrix.

Return type:c4d.Matrix
Returns:The normalized matrix.
Matrix.Mul(v)

Multiply the vector by the matrix, this includes any translation in the matrix.

Parameters:v (c4d.Vector) – The vector to multiply.
Return type:c4d.Vector
Returns:The result vector.
Matrix.MulV(v)

Multiply the vector by the matrix, this does not include any translation.

Parameters:v (c4d.Vector) – The vector to multiply.
Return type:c4d.Vector
Returns:The result vector.
Matrix.GetTensorMatrix()

Returns the matrix’ tensor.

Return type:c4d.Matrix
Returns:The tensor matrix.
Matrix.Scale(v)

Performs uniform matrix scaling (float) or non-uniform matrix scaling (vector).

Parameters:v (Union[c4d.Vector, float]) – The scaling scalar.

The Matrix Has You

Single precision matrix mathematics - A matrix is basically an array of number arranged in a rectangular pattern. The matrices used in Cinema 4D, represented by the class Matrix, consist of three rows and four columns, i.e. they have the dimension 3x4. The first row is always “1, 0, 0, 0”, which means that there are 12 numbers that are used. These numbers are grouped into four vectors, one for the remaining numbers in each column. The four vectors are called off, v1, v2 and v3, together these four vectors can be used to represent the coordinate system for a Cinema 4D object. A coordinate system consists of three axes, one for each coordinate (X, Y and Z). The system also has a base position, from which the three axes originate. This base position is stored in off, and the three axis vectors are stored in v1, v2 and v3 respectively. Also check out Matrix Fundamentals. So now we can follow the white rabbit - knock knock - neo.

../../../_images/matrix1.gif

Note

Cinema 4D uses a left-handed coordinate system.

Here is a small example how to use the type Matrix:

v_1    = Vector(30)
v_2    = Vector(1.5, 9.87, 2)
v_3    = Vector(0)
off    = Vector() #Vector with components: 0
mat    = Matrix(off, v_1, v_2, v_3) #create new instance of Matrix
print mat.v1.x #return 30

Freeze Transformations

With R12 you probably have noticed that BaseObject no longer has members like GetPos, but instead twice as many: BaseObject.GetRelPos() and BaseObject.GetAbsPos().

To understand what’s going on I’ll quickly introduce you to Freeze Transformations.

For (character) animation it is important that you can define rest poses. Think e.g. of the typical CG human that has arms and legs stretched. Most objects carry all kinds of complicated position, scale and rotation information. Freeze Transformations allow you to “freeze” this information, but reset position/rotation to 0.0 and scale to 1.0. This is great as it allows you at any time to go back to the original - just reset all position and angle information to 0.0 - and your object has reached its rest state again. You could achieve the same by adding for every single object in your hierarchy a parent null object, but Freeze Transformations let you do this without the need to change the hieararchical structure. Technically however you can think of it as a “parent null object” without the actual body of a physical object.

All parts of the application that deal with keyframing only access values without the freeze transformation part. This way you can conveniently animate (the rest pose is always 0.0 for position and rotation) and avoid rotation singularities. The correct routines for animation and keyframing are labeled “Rel”.

Other parts of the application however (e.g. like a target expression) need to get the absolute local position of a target - the position that consists of frozen and regular matrix. For those purposes you need to use the routines that are labeled “Abs”.

To clarify: as long as an object has no Freeze transformation assigned (which is always the default case when you create a new object) there is no difference between the Abs or Rel. So e.g. after creating an object it doesn’t matter which routine you choose. If you however want to read the position of an object (and that object uses freeze transformations) there is a difference.

BaseObject.GetMl() / BaseObject.SetMl() and BaseObject.GetMg() / BaseObject.SetMg() always include the frozen information, thus are “Abs” versions.

After so much theory a practical example. Take a look at the cube and null object in the picture below. The null object has a position of (0/200/0) and rotation of (0°/45°/0°). The cube has a position of (0/100/0). You can see to the left its global position in space.

../../../_images/freeze_transformation1.png

Now let’s try to do the same with one single object:

../../../_images/freeze_transformation2.png

You can see that the Null object’s position / rotation have been transferred to the Cube’s frozen position and frozen rotation. The result is exactly the same as before, just without the need for an extra null object.

Now if you call cube.GetAbsPos the return value will be (0/270.711/-70.711). When you call cube.GetRelPos however you’ll get (0/100/0) as a result. The coordinate manager offers exactly those two display modes: Object (Abs) and Object (Rel).

As copying position, rotation and scale data from one object to another is much more complex than before there is a new routine BaseObject.CopyMatrixTo() that copies all position, rotation and scale data (including the frozen states) over to another object.

Let’s take a look at the mathematical background: In Cinema 4D the matrix multiplication order for two matrices A and B:

[C] = [A] * [B]

is defined as the rule “A after B”… so the following two lines are equivalent:

transformed_point = original_point * [C]
transformed_point = (original_point * [B]) * [A]

(the original point is first transformed by matrix [B] and then later by [A])

An object’s global matrix is calculated this way:

[Global Matrix] = [Global Matrix of Parent] * [Local Matrix]

or:

[Global Matrix] = op.GetUpMg() * op.GetMl()

To calculate the local matrix of an object the formula is:

[Local Matrix] = [Frozen Translation] * [Frozen Rotation] * [Relative Translation] * [Relative Rotation] * [Frozen Scale] * [Relative Scale]

or:

[Local Matrix] = MatrixMove(op.GetFrozenPos()) * HPBToMatrix(op.GetFrozenRot()) * MatrixMove(op.GetRelPos()) * HPBToMatrix(op.GetRelRot()) * MatrixScale(op.GetFrozenScale) * MatrixScale(op.GetRelScale())

or equally:

[Local Matrix] = MatrixMove(op.GetAbsPos()) * HPBToMatrix(op.GetAbsRot()) * MatrixScale(op.GetAbsScale)

Please note that the both scales are applied at the very beginning, so the local matrix is not the same as [Frozen Matrix] * [Relative Matrix]. This is necessary in order to guarantee that your local matrix always stays a rectangular system; distorted systems would be too complicated to handle.