Shapes form complex structures via hierarchies. These make it easier to manipulate structures.
Example: We should be able to just rotate stick person's arm at the shoulder, and ball will move (instead of having to move everything individually).
Students spend their whole first month struggling with the linear algebra in spite of this.
In graphics for CS majors, we have a prerequisite of linear algebra for the course.
A point \(p\) is a vector:
A transformation \(M\) is a matrix:
We perform matrix multiplication to apply the transformation: \( p' = M p\)
What if we multiply by the so-called identity matrix?
(1,1)
(2,2)
(2,2)
(4,4)
All of these transformations are considered linear transformations:
We want to be able to move objects through space.
But we can't do this using our standard linear algebra...
If we have a single, complex matrix, we can simply apply it to our object to get the resulting transform.
But we can (and often should!) think about it as a sequence of simpler transformations:
Mathematical reason: matrix multiplication is generally not commutative.
Intuitive: what happens if we translate then reflect vs reflect then translate?
No Transformations Applied
Translate Only
Rotate Only
translate()
rotate()
draw()
rotate()
translate()
draw()
translate(x, y)
: applies a translation which moves points by (x,y)rotate(
θ)
: rotates by θ radians
scale(p)
: Scales by p, where 1.0 is no change.Transformations are a little like modes, where the transformation function affects all future draw calls.
Two major differences:
void draw(){
translate(100, 100);
ellipse(0, 0, 100, 100);
translate(200, 200);
ellipse(0, 0, 60, 60);
translate(300, 300);
ellipse(0, 0, 35, 35);
}
Ctrl+Z 101
rotate(radians(45));
translate(200, 0);
// Undo our transformation
rotate(radians(-45));
translate(-200, 0);
shape(ref);
Wuh woh.
rotate(radians(45)); // shoes
translate(200, 0); // socks
translate(-200, 0); // isocks
rotate(radians(-45)); // ishoes
shape(ref);
pushMatrix()
takes the current global transformation and records it in a matrix stack. You can think of this as a global variable that is hidden from you and can only be accessed with the functions here.popMatrix()
pops a transformation matrix off of the stack and makes it the current transformation matrix.void draw(){
pushMatrix();
translate(100, 100);
ellipse(0, 0, 100, 100);
popMatrix();
pushMatrix();
translate(200, 200);
ellipse(0, 0, 60, 60);
popMatrix();
pushMatrix();
translate(300, 300);
ellipse(0, 0, 35, 35);
popMatrix();
}
We can already emulate scale by passing parameters to rect()
. Why not just add a rotation parameter?
rect(0, 0, 100, 20, PI/8)
By author Zorgit on Wikimedia, CC-BY-SA 3.0: https://commons.wikimedia.org/wiki/File:Cycloid_f.gif
void draw(){
translate(300, 300);
rotate(frameCount * 0.03);
translate(50, 0);
translate(30, 0);
rotate(frameCount * 0.05);
translate(10, 0);
rotate(frameCount * 0.1);
rect(0, 0, 100, 100);
}
We need at least four* parameters to describe a rotation in three dimensions.
* terms and conditions apply
We need more spatial arguments as well!
box(x, y, z, width, height, depth, rot1, rot2, rot3, rot4);
In 3D, transformations are heavily used to avoid parameter explosions:
The transformation in step 1 should apply to all of the other steps. For Steps 2-5, you may want to pushMatrix() and popMatrix() so that your transformations don't get too confusing.