Using rotateX, rotateY, rotateZ together

While working on code to draw orbits around a sphere, I found a surprising (but correct) result using the rotateX, rotateY, and rotateZ functions, and I am interested if this is or can be better explained somewhere to help users understand the issue.

My use case is to draw a circle around a sphere that is rotated around the Y axis 90 degrees and then tilted to the right by rotating around the Z axis 37 degrees. This would look like the following:

My initial approach is the following:

// Setup a white 3D screen with ortho projection
size(1000, 700, P3D);
background(255);
lights();
noStroke();
ortho();

// Move origin to pivot around the center 
// of the screen and draw our sphere
translate(width *0.5, height*0.5, 0);
sphere(280);

// Setup to draw the circle
noFill();
strokeWeight(3);
stroke(0);

// Rotate and draw
rotateY(PI/2);
rotateZ(radians(37));
circle(0, 0, 600);

But my rotation code is wrong. Instead of the inclined circle, I just get a vertical circle, which looks like the rotation around the Z axis didn’t happen. But it actually did happen, just not how I was (incorrectly) expecting. I made what might be a common mistake, and I was certainly confused about what was actually happening.

The process I was thinking of when writing the code was the following:

  1. Create a circle
  2. Rotate 90 degrees around Y axis
  3. Tilt right 37 degrees by rotating around the Z axis.

But that is not at all what I was actually doing, instead the actual steps are:

  1. Change coordinate system - Y rotation
  2. Change coordinate system - Z rotation
  3. Draw circle in the new coordinate system

The right way to achieve the goal is to reverse the order of the rotations:

rotateZ(radians(37));
rotateY(PI/2);
circle(0,0,600);

This makes sense in considering the matrix operations, but it is a bit difficult to explain. I was able to draw my final picture with multiple inclined orbits around a sphere by reversing the order of rotations from my initial intuition:

// Setup a white 3D screen with ortho projection
size(1000, 700, P3D);
background(255);
lights();
noStroke();
ortho();

// Move origin to pivot around the center 
// of the screen and draw our sphere
translate(width *0.5, height*0.5, 0);
sphere(280);

// Setup to draw the circle
noFill();
strokeWeight(3);
stroke(0);

for (float r = 0.0; r < 2*PI; r += PI/12) {
  pushMatrix();
  rotateY(r+PI/6);
  rotateZ(radians(37));
  rotateY(PI/2);
  circle(0, 0, 608);
  popMatrix();
}

(can’t include more than one image)

2 Likes

Hello @jmwanderer,

The order of rotations matters.

A search for Euler angles and order of rotation or rotation sequence may help understanding this.

Also search for yaw, pitch and roll.

I remember my experience with this years ago and was able to sort that out with a bit of research and writing code.

Lots of articles on the subject… find the one that best suits you.

It also helps to draw axes for x, y and z and label them so you can visualize the rotations.

I used the Scroll Bar examples that come with Processing and added axes and a shape to help me visualize rotations:

:)

2 Likes

Thank you so much for the reply and the pointers to the Euler angles! The description of the 3 rotation matrices is very helpful along with the drawings of using yaw, pitch, and roll to get from one frame to another.

I think it is interesting to consider how to use the Euler transformation matrix in Processing. I saw a good brief write up that the transform matrix from frame 1 to 2 is a product of the x-axis rotation, y axis rotation, and z axis rotation.:

With a rotation matrices Rx, Ry, Rz and a point 1 (p1): p2 = Rx Ry Rz p1

Rz is applied to p1 first, then Ry, and then Rx.

To apply this in Processing for drawing a circle, I think it would be:

rotateX(aX);
rotateY(aY);
rotateZ(aZ);

With the Z axis specified last to make it apply first. The Processing transformation matrix would be updated as: T = T Rx Ry Rz

It is possible a common mistake here would be to call rotateZ first since the z-axis rotation should be applied first, but the way the rotation matrices are applied to the transform matrix is need to be called last. (at least that is what initially confused me before I considered the transform matrix).

Again, thank you so much for the reply and information. It is much appreciated. And I apologize if I have made this reply too confusing or if I am missing something in Processing that I should be using.

1 Like

Hello again!

First and foremost wrap your head around the simple transformations and rotations that Processing offers.

It very much depends on your starting frame of reference.
If you draw a circle on the XY plane with an origin of (0, 0, 0 ) with circle() the Z could be your yaw and the X or Y rotations could be pitch or roll.
You can create your own shapes and have a circle (or other shape) anywhere you want!
You can rotate everything at the start of code or just rotate the circle() on the XY plane to another plane (push and pop) and then rotate that.
It gets complicated and easier once you start working with it.

I did not share an example because this is your journey.
This forum is full of examples.
I have written thousands of examples in my exploration of this!

There are some tutorials here on P2D and P3D:

There is some cool stuff here:

There is a lot to explore in there and found a lot of useful information for my use.

I found the Java code useful when I was exploring rotations and converting between Euler, quaternion and matrix rotations:

Quaternions took a while to understand and can work with them now… that was a challenge!

Euler Angles reference (See also the “See also” section!):

Some good stuff here to stimulate your mind (or complicate your world):

:)