A convention for describing transforms
2023-03-25 -- 2024-01-01How to talk, write and code in a manner that makes it clear what a linear transform is describing?
Firstly, it helps to have words to differentiate the two ways we can interpret the same transform: Are we interpreting transform as being Passive or Active?
A transformation matrix with the notation
- An active transform that moves an object from
to , as seen from a global reference frame. This is often the context you are in when working in 3D software such as Blender or 3ds Max, you're always observing the changes from a global reference frame: the program's viewport. - A passive transform that transforms the coordinate of a point expressed in the
reference frame into the coordinates for the same point expressed in the reference frame , I.e. .
To be more clear, we should specify the following about a rotation and translation representation:
- Rotation
- The frame we are rotating to.
- The frame we are rotating from.
- Translation
- The point we are translating to.
- The point we are translating from.
- The frame that this translation is expressed in.
Math Notation and How to Describe Them
Here are some useful phrases to help describe quantities and transforms and what they represent.
Vector
The vector from B to C expressed in A.
Angular velocity
The angular velocity of frame C as seen from frame B, expressed in frame A.
Transforms
"The pose of
with respect to " or "Transforms point from frame into frame "
It is also helpful to express even more in writing:
The transformation matrix,
, represents the pose of the body frame , with respect to the world frame , such that a point expressed in the body frame , can be transformed into the world frame by .
The same phrasing can be used for pure rotations.
Notation in Code
Assuming column-vectors, the standard in Eigen and OpenGL, transforms in code can often look like this:
transformed_point = M * point;
When multiple matrices are being combined, it can become vague and hard to keep track of what is happening. Instead, a clearer way to express this is to name the variables representing transforms as A_from_B
and assume that we are looking at them in the passive sense.
This has some nice benefits:
-
Allows composition of transforms where it's clear what transforms fit together by seeing that the frames at the start and end of the name line up
projection_from_object = projection_from_view * view_from_world * world_from_object
-
Inverting a transform flips the order:
object_from_world = inverse(world_from_object)
. -
Also works nicely with points, if they follow the rule
framename_point
:world_point = world_from_object * object_point
However, this requires you to talk about the transforms in the passive sense.
One could use the a_to_b
instead of a_from_b
formulation for talking about the transforms in the active sense. However, as Sebastian Sylvan describes in their post, the a_to_b
names might be better used for when dealing with row-vectors.
I'm currently leaning towards assuming passive
, if that is the normal case in the code base, and then specifying when I'm talking about a transform in the active sense:
// 2 ways of talking about the same transform
// A_from_B == active_A_to_B
A_point = A_from_B * B_point // passive
point_at_B = active_A_to_B * point_at_A // active
Ideas here are mainly taken from:
- Representing robot pose by Paul Furgale
- Naming Convention for Matrix Math by Sebastian Sylvan