EARTH 801
Computation and Visualization in the Earth Sciences

Lesson 6: Translations and Rotations in 3D

PrintPrint

New syntax discussed: P3D, rotateX, rotateY, sphere, box, beginShape(QUADS), beginShape(TRIANGLES)

Rotation around X or Y

Last week when we rotated shapes, all the rotations were in the plane of the computer screen, meaning that the rotation was happening around the Z axis, if you think of the Z axis as a line drawn perpendicular to your screen. Processing has a 3D renderer to allow you to work in a three-dimensional coordinate system. The default is that the positive Z direction is out of the screen towards you and the negative Z direction is into the screen away from you. In order to let Processing know that you want to have a 3D coordinate system, you have to specify the renderer when you call size(). We are going to work with the P3D renderer but there are other ones, such as OpenGL. You can look up the other ones at the Processing website if you want to.

Example 6.0

Here are a series of three simple programs to demonstrate rotations in 3D. First, start with the rotation we know about from last week: rotation around the Z axis.

//rotating orange square

float rotAngle = 0;

void setup(){
   size(400, 400);
}

void  draw(){
   background(255);
   translate(width/2, height/2);
   
   rotate(rotAngle);
   rotAngle+=0.01;
      fill(250, 100, 13);
   rectMode(CENTER);
   rect(0, 0, 200, 200);
}

Example 6.1

Now let’s take that same square and rotate it around the X axis. That program looks like this:

//rotating orange square
//rotates around X axis

float  rotAngle = 0;

void setup(){
   size(400, 400, P3D);
}

void  draw(){
   background(255);
   translate(width/2, height/2,0);
   rotateX(rotAngle);
   rotAngle+=0.01;
   fill(250, 100, 13);
   strokeWeight(4);
   rectMode(CENTER);
   rect(0, 0, 200, 200);
}

Notice the different things in this program: When I called size(), I specified P3D after I gave the dimensions of the window. When I called translate(), I used three arguments. The third one is for translation in Z. I used the command rotateX instead of just rotate.

Example 6.2

Here’s the same program again except with rotation around the Y axis:

//rotating orange square
//rotates around Y axis

float rotAngle = 0;

void setup(){
   size(400, 400, P3D);
}

void draw(){
   background(255);
   translate(width/2, height/2,0);
   rotate(rotAngle);
   rotAngle+=0.01;
   fill(250, 100, 13);
   strokeWeight(4);
   rectMode(CENTER);
   rect(0, 0, 200, 200);
}

The only thing different between the program in Example 6.2 and the program in Example 6.1 is the use of rotateY instead of rotateX.

cartoon Eliza alerting you that instructions come nextHere's a screencast that directly compares the three programs above (and a captioned version) and shows you what they look like when they are running.

Interactive rotation

Now let’s modify our rotating square so that we are controlling the rotation with the mouse. You know all the commands to make this work already. Here’s how it is done. Decide how much of a rotation you want to allow (a full rotation is 360 degrees, or 2*PI radians). Then map this angle to the width or height of the screen based on the mouse location.

Example 6.3

Here is an example of rotation about the Y axis based on the X location of the mouse. Does this seem counterintuitive? Think about it for a minute. Rotation around Y basically means side-to-side rolling, so to me it seems more intuitive to control this motion with the side-to-side, or X, position of the mouse.

//rotating orange square
//rotates around Y axis with mouse

void setup(){
   size(400, 400, P3D);
}

void draw(){
   background(255);
   translate(width/2,height/2,0);
   float rotAngle = 2*PI*mouseX/width;
   rotateY(rotAngle);
   fill(250, 100, 13);
   strokeWeight(4);
   rectMode(CENTER);
   rect(0, 0, 200, 200);
}
cartoon Eliza alerting you that instructions come next

The most important line of this program is the one that says:

float rotAngle = 2*PI*mouseX/width;

That line does a lot for you. It tells Processing that you want one whole rotation to occur over the distance that equals the width of the window and you want the amount of rotation to be dependent on the X position of the mouse. It is a good idea to experiment with putting different numbers into this line to see what they do. For example, try getting rid of the number 2 or changing it to 4 and see what happens. What would you have to change to get one whole rotation about the X axis based on the Y position of the mouse? Here's a screencast of the mouse-controlled rotation program (and a captioned version) so you can see what it looks like when it is running.

Quiz Yourself!

What does this code do? See if you can figure it out before trying it.

float rotAngle0 = 0;
float rotAngle1 = 0;

void setup(){
   size(200, 200, P3D);
}

void draw(){
   background(255);
   translate(width/2,height/2,0);
   rotateX(rotAngle0);
   rotateY(rotAngle1);
   if (keyPressed == true && key == 'l'){
   rotAngle0+=0.01;
   }
   if (keyPressed == true && key == 'i'){
      rotAngle1+=0.01;
   }
   fill(250, 100, 13);
   strokeWeight(4);
   rectMode(CENTER);
   rect(0, 0, 100, 100);
}

Answer:

This program draws an orange square with a black outline. If the user holds down the "l" key, then the orange square rotates about its own equator. If the user holds down the "i" key, then the orange square rotates side to side around a vertical axis that bisects the square.

Drawing 3D shapes

Knowing how to rotate a flat shape in space is the first step to drawing an actual shape in three dimensions. There is a little bit of a trick to drawing in three dimensions and that is that the usual shape primitives, such as rect() and ellipse() don’t accept Z coordinates as arguments. If you want to build a three-dimensional object, you have to use beginShape() and endShape() because the vertex() command does accept Z coordinates.

Example 6.4

Let’s draw a cube that will rotate about its center. We’ll start by drawing one face of the cube, like this:

float theta=0;
float d = 100; //length of an edge of the cube

void setup(){
   size(600, 400, P3D);
}

void draw(){
   background(255);
   stroke(0);
//make the origin the center of the cube
   translate(width/2,height/2,0);
   rotate(theta);
   theta+=.01;
   beginShape(QUADS);
//back face of the cube
   fill(255, 0, 0);
   vertex(-d/2, -d/2, -d/2);
   vertex(d/2, -d/2, -d/2);
   vertex(d/2, d/2, -d/2);
   vertex(-d/2, d/2, -d/2);
   endShape();
}

Notice that I used the argument QUADS with beginShape(). That lets Processing know that I’m trying to draw something with four sides. This will become useful later because if we want to draw several four-sided shapes in a row, we don’t have to use separate beginShape()/endShape() pairs. You’ll see what I mean with the next step for this project when we add the front face of the cube:

float theta=0;
float d = 100; //length of an edge of the cube

void setup(){
   size(600, 400, P3D);
}

void draw(){
   background(255);
   stroke(s);
//make the origin the center of the cube
   translate(width/2,height/2,0);
   rotateY(theta);
   theta+=.01;
   beginShape(QUADS);
//back face of the cube is red
   fill(255, 0, 0);
   vertex(-d/2, -d/2, -d/2);
   vertex(d/2, -d/2, -d/2);
   vertex(d/2, d/2, -d/2);
   vertex(-d/2, d/2, -d/2);
//front face of the cube is yellow
   fill(255, 255, 0);
   vertex(-d/2, -d/2, d/2);
   vertex(d/2, -d/2, d/2);
   vertex(d/2, d/2, d/2);
   vertex(-d/2, d/2, d/2);
   endShape();
}

Now to add a side face:

float theta=0;
float  d = 100; //length of an edge of the cube

void setup(){
   size(600, 400, P3D);
}

void  draw(){
   background(255);
   stroke(0);
//make the origin the center of the cube
   translate(width/2,height/2,0);
   rotateY(theta);
   theta+=.01;
   beginShape(QUADS);
   //back face of the cube is red
   fill(255, 0, 0);
   vertex(-d/2, -d/2, -d/2);
   vertex(d/2, -d/2, -d/2);
   vertex(d/2, d/2, -d/2);
   vertex(-d/2, d/2, -d/2);
//front face of the cube is yellow
   fill(255, 255, 0);
   vertex(-d/2, -d/2, d/2);
   vertex(d/2, -d/2, d/2);
   vertex(d/2, d/2, d/2);
   vertex(-d/2, d/2, d/2);
   //a green side face
   fill(0, 255, 0);
   vertex(-d/2, -d/2, -d/2);
   vertex(-d/2, -d/2, d/2);
   vertex(-d/2, d/2, d/2);
   vertex(-d/2, d/2, -d/2);
   endShape();
}

It’s an exercise for you to finish the cube. Note that Processing does have two intrinsic functions called box() and sphere(). For real, you’d probably want to use the box() function to draw a 3D cube. I made you do it the hard way so you’d see how to draw other less regular shapes.

Export a stand-alone app

Wouldn’t it be great to show your pals what you’ve been up to without making them download Processing and compile your program?! I’m sure you’ve been wanting to do this. Well, you can. All you have to do is choose “Export Application . . .” from Processing's File drop-down menu. Processing will pop up a dialog box asking you what kind of platform (mac, windows, or linux) you are intending to run it on. Then it will make a new folder inside your sketch folder with the app in it. Try it out!

Exercises

6.1 Draw three shapes to the screen all at once. Have each of them rotate about their own centers: one rotates around the z axis, one rotates around the x axis, and the other rotates around the y axis.

6.2 Finish the 4th side of the cube. Change the program to rotate the cube with the mouse.

6.3 Use beginShape(TRIANGLES) to draw a four-sided pyramid with mouse-controlled rotation in 3D space.

6.4 Export an app so you or someone else can run one of your programs.

Turning in your work

Turn in either 6.1 OR 6.3 to its assignment dropbox in Canvas