Vectors

Explains how to carry out vector operations.

Positions, directions, and sizes in a Cinema 4D scene are all described by vectors. This manual explains what a c4d.Vector is and walks through the operations that the Cinema API provides for it. Matrices, which combine vectors into transforms, are explained in Matrices.

Overview

A vector is a tuple of numbers. In mathematics, the tuple can have any number of components: two, three, or many more. The Cinema API’s c4d.Vector always has three components, x, y, and z.

In 3D Euclidean space, the components are coordinates relative to three basis vectors, which define the X, Y, and Z axes of a coordinate system. Starting at the origin, the dotted path follows the x, y, and z components in turn to point P. Offset dimension lines with short feet mark each step, and their labels show the component values. The arrow can also be read as a direction with magnitude. Cinema 4D uses a left-handed coordinate system: X points right, Y up, and Z away from the viewer. One unit is one centimeter.

Operations

Select an operation to understand how it works.

Addition

Adding two vectors chains two vectors together tip to end. Start at the origin, follow the first vector, and from where you end up, follow the second one. The result is the single arrow from the origin to that final point. The order does not matter, because both routes end at the same point.

import c4d

a: c4d.Vector = c4d.Vector(2, 1, 1)
b: c4d.Vector = c4d.Vector(1, 2, 0.5)
r: c4d.Vector = a + b # (3, 3, 1)

Subtraction

Subtracting one vector from another gives is the vector that starts at the tip of the vector being subtracted and ends at the tip of the vector it is subtracted from. Swapping the two vectors makes the arrow point the other way.

import c4d

a: c4d.Vector = c4d.Vector(3, 3, 1)
b: c4d.Vector = c4d.Vector(1, 2, 0.5)
r: c4d.Vector = a - b # (2, 1, 0.5)

Scalar Multiplication

Multiplying by a scalar stretches the vector, and a negative scalar also reverses it. The direction stays on the same line through the origin.

import c4d

a: c4d.Vector = c4d.Vector(2, 1, 0.5)
k: float = 2.0
r: c4d.Vector = a * k # (4, 2, 1)

Component-wise Product

Multiplying two vectors component-wise means multiplying each corresponding component together. It is rarely needed apart from nulling components of a vector on specific axes.

import c4d

a: c4d.Vector = c4d.Vector(2, 0.5, 1)
b: c4d.Vector = c4d.Vector(0.5, 2, 1)
r: c4d.Vector = a ^ b # (1, 1, 1)

# Nulling the x component of a vector in an ongoing calculation. Here we null the x component
# of the r-vector before adding it to another vector.
s: c4d.Vector = c4d.Vector(1, 2, 3) ^ (r ^ c4d.Vector(0, 1, 1))

Normalization

Normalizing keeps a vector’s direction and sets its length to one. The result is a unit vector on the unit sphere. Normalize() does the same in place. The zero vector cannot be normalized.

import c4d

a: c4d.Vector = c4d.Vector(3, 2, 1)
r: c4d.Vector = a.GetNormalized()  # (0.802, 0.535, 0.267)
r: c4d.Vector = ~a  # alternative notation for normalization

Negation

Negation reverses a vector without changing its length. It is the same as multiplying by -1.

import c4d

a: c4d.Vector = c4d.Vector(2, 1, 0.5)
r: c4d.Vector = -a  # (-2, -1, -0.5)

Length

The length of a vector follows from its components with the Pythagorean theorem. Computing it needs a square root, so prefer GetLengthSquared() for comparisons where the distance is not needed.

import c4d

a: c4d.Vector = c4d.Vector(3, 2, 1)
r: float = a.GetLength()  # 3.741
s: float = a.GetLengthSquared() # 14

Cross Product

The cross product is perpendicular to both vector operands, and its length is the area of the parallelogram they span. It is commonly used to construct a surface normal. In Cinema 4D’s left-handed system, the result follows the left-hand rule. Swapping the operands flips the result.

import c4d

a: c4d.Vector = c4d.Vector(2, 0, 1)
b: c4d.Vector = c4d.Vector(1, 2, 0)
r: c4d.Vector = a.Cross(b)  # (-2, 1, 4)
s: c4d.Vector = a % b # alternative notation for cross product

Dot Product

The dot product measures how much two vectors point in the same direction. It is positive when they point broadly the same way, zero when they are perpendicular, and negative when they oppose each other. The result is a number, not a vector. For unit vectors it is the cosine of the angle between them; geometrically, it gives the projection of one vector onto the other.

import c4d

a: c4d.Vector = c4d.Vector(3, 1, 1)
b: c4d.Vector = c4d.Vector(1, 3, 0.5)
r: float = a.Dot(b)  # 10.5
s: float = a * b  # alternative notation for dot product

Projection onto a Vector

Projecting a vector onto another asks how much of it points along the direction of the other. Picture the other vector as a line, with light shining straight onto it from the side: the shadow cast on that line is the result. What is left over, the dashed remainder, stands at a right angle to the line. It splits a movement into a part along a direction and a part across it. The vector to project onto cannot be the zero vector.

import c4d

a: c4d.Vector = c4d.Vector(2, 3, 1)
b: c4d.Vector = c4d.Vector(4, 0.5, 1)
if b.GetLengthSquared() > 0.0:
    r: c4d.Vector = b * (a.Dot(b) / b.GetLengthSquared())

Projection onto a Plane

Projecting onto a plane flattens a vector onto a flat surface, like the shadow an object casts on the floor from a light straight above. The plane is described by its normal n, the direction standing upright on it. The vector is split into a part along the normal and a part that lies within the plane. Removing the first part leaves the second, the flattened result. It is how you keep a movement on the ground or slide along a surface. The normal must have a length of one. Orbit the preview to inspect the vectors and plane in 3D.

import c4d

a: c4d.Vector = c4d.Vector(2, 2.2, 1.5)
n: c4d.Vector = c4d.Vector(0, 1, 0)  # Must be a unit vector.
r: c4d.Vector = a - n * a.Dot(n)

Rotation

Rotating a vector in 2D is equivalent to moving it along the unit circle.

Note

This section explains the relation between the circle functions and the rotation of a vector in 2D space. It shows you why rotation matrices work and why DCC apps deal with rotations in radians under the hood. Doing it manually as shown here is not necessary, use c4d.utils.MatrixRotX(), c4d.utils.MatrixRotY(), and c4d.utils.MatrixRotZ() instead.

A vector can be rotated using the trigonometric identities adjacent over hypotenuse and opposite over hypotenuse, which correspond to the cosine and sine functions, respectively. With that we can rotate a vector on the unit circle by an angle, as the rotated vector will be described by a triangle with the original vector as the hypotenuse.

Broadly speaking, the sine and cosine functions describe the relationship between the angle and the coordinates of a point on the unit circle; they literally trace out the coordinates of a point on the unit circle, rotated by the given angle. From this insight follows then notion of a ‘rotation matrix’, a little tool that rotates a vector by a given angle.

Below you can find in the top left corner the two trigonometric identities to compute x and y coordinates of a rotated vector. On the top left you find the corresponding rotation matrices. On the bottom left you see the unit circle with the rotated vector. Here you can drag the rotated point to see the diagram update. And on the bottom right, you can see a corresponding sine and cosine plot.

import c4d
import math

angle: float = c4d.utils.DegToRad(30)  # Angles are in radians.
a: c4d.Vector = c4d.Vector(1, 0, 0)

# Rotating with the Cinema API.
M: c4d.Matrix = c4d.utils.MatrixRotZ(angle)
r: c4d.Vector = M * a  # (0.866, -0.5, 0)

# Rotating manually, same as #r.
cos: float = math.cos(angle)
sin: float = math.sin(angle)
s: c4d.Vector = c4d.Vector(a.x * cos + a.y * sin,
                           a.y * cos - a.x * sin,
                           a.z)