I am following the tutorial from learnopengl.com but it uses a Y-up system, but I would like to change it for a Z up system because I'm more used to it.

I tried changing the up vector to be 1.0 on the last coordinate but and inverting the pitch And the Yaw, but when having the camera face the positive y-axis the mouse movement breaks and starts to move slower and opposite to the way I move the mouse.

The Axis system I'm trying to achieve: enter image description here

That is the same as the Blender one.

This is the function of the camera class which handles the Pitch and Yaw: (offset is the mouse movement on the x axis and y axis):

void Camera::updateCameraVectors()
    // Calculate the new Front vector
    glm::vec3 front;

    front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
    front.y = sin(glm::radians(Pitch));
    front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));

    Front = glm::normalize(front);
    // Also re-calculate the Right and Up vector
    Right = glm::normalize(glm::cross(Front, WorldUp));  // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
    Up = glm::normalize(glm::cross(Right, Front));

Up is the vector that I initialized as (0.0f, 0.0f 1.0f)

Are there any resources available online that explain how to make the switch from a Y-up to Z-up system?


OpenGL uses a coordinate system, where the positive z-axis points "out of the screen", it's y-axis points up and it's x-axis to the right. In the end, you need to transform every data to this target coordinate system. Let us call this the "OpenGL" coordinate system.

So there is a transformation between your camera coordinate system, which we will call the "camera coordinate" system, that transforms into the "OpenGL" system. Since both coordinate systems are right-handed, a simple rotation should do the trick. In your case, the difference between the "OpenGL" coordinate system and the "camera coordinate" system is just a rotation around the x-axis by 90 degrees:

$$O_{oc} = R_x(\frac{\pi}{2})$$

Here O means orientation, the index oc means "OpenGL in Camera" and R_x is the rotation matrix that represents a rotation around the x-axis. Note that our orientation is a matrix!

Now you need to know, how your camera coordinate system is oriented in the "world space" system. If you define that both systems have the same orientation if yaw=0 and pitch=0, your camera systems orientation in world space can be described by the 2 following rotations in matrix notation:

$$O_{cw} = R_z(yaw) \cdot R_x(pitch)$$

Keep in mind, that you read matrix multiplication from right to left. So you apply the pitch first by rotating around the x-axis. Afterward, you apply the yaw. Order matters, so don't exchange them.

Now you have all information together, but there is still one problem. The system dependencies are wrong. You want to transform your data from world space to "OpenGL" space. This means you need the matrix:

$$O_{wo} = O_{co} \cdot O_{wc}$$

Note that the indices are swapped! So you need to find the transformations in the opposite direction, which means you need to find the inverse matrix. Luckily, that is rather easy for the orientations. Since orientation (rotation) matrices are so-called orthogonal matrices, the inverse is just the transposed. So you could do:

$$O_{co} = O_{oc}^T$$ $$O_{wc} = O_{cw}^T$$

Another way, that might be a little bit easier to understand is, that if you have applied some rotations to an object (transformed from A to B) and you want to undo the rotations (transform back to A from B), you can do this by simply applying the rotations in the opposite direction in the opposite order. For our matrices that means:

$$\begin{matrix} O_{oc} &=& R_x(\frac{\pi}{2})\\ O_{co} &=& R_x(-\frac{\pi}{2}) \end{matrix}$$ and $$\begin{matrix} O_{cw} = R_z(yaw) \cdot R_x(pitch)\\ O_{wc} = R_x(-pitch) \cdot R_z(-yaw) \end{matrix}$$

So you get:

$$O_{wo} = R_x(-\frac{\pi}{2}) \cdot R_x(-pitch) \cdot R_z(-yaw)$$

This is the matrix, that transforms the orientations from world space to "OpenGL" space. Its rows are your Front, Right and Up vectors. I am not sure about the ordering since I didn't check it explicitly, but I think the second row is the Front vector, the first is Right and the last is Up. You can try to extract them, but since you need to bundle them into the same matrix later, I would say, don't do it. Keep using the matrix instead.

However, there are still some things to consider: translations. To get to the actual camera position, you need to translate your data. A quick look into the tutorial (the one you linked) just revealed that this is already explained there, so I won't repeat the derivation again. Your full transformation matrix from world to "OpenGL" space is then:

$$M_{wo} = O_{wo}\cdot\begin{bmatrix} 1&0&0&-x_{cam}\\ 0&1&0&-y_{cam}\\ 0&0&1&-z_{cam}\\ 0&0&0&1\\ \end{bmatrix}$$

I am actually using this approach myself. Therefore I know that it works ;). You can still optimize it a little by performing the matrix multiplications by hand, but since you are doing it once per frame, it isn't too important for performance.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.