Search code examples
matrixopengllwjgljoml

How to rotateX or rotateZ view matrix around specified axis?


I would like to rotate view matrix (I supposed to think this represents camera position).

I already rotate view matrix about Y-axis by using Matrix4f#rotateY successfully.

However, about rotateX this requires the target position at (0,0,0) center of the world, I would like to rotate the view matrix around a specified position.

I tried to rotate the matrix like following:

targetCenter = Vector3f(x, y, z)

viewMatrix
    .translate(targetCenter)
    .rotateX(rotation)
    .translate(targetCenter.mul(-1.0f))

However, this make the rendered model twice. Is this the correct method to rotate view matrix around specified axis ?

EDIT

  • I've implemented camera with Kotlin according to Draykoon D's answer, thank you
  • I'm using JOML as a library to manipulate Matrix
fun Matrix4f.orbitBy(modelCenter: Vector3f, angleY: Float, angleX: Float, focalLength: Float) {
    // Setup both camera's view matrices
    val modelCenterCp = Vector3f(modelCenter)
    val recenter = Matrix4f().translate(modelCenterCp.mul(-1.0f)) //not needed if world origin
    val rotation = Matrix4f()
            .rotateY(angleY)
            .rotateX(angleX)
    val moveBack = Matrix4f().translate(modelCenter) //not needed if world origin
    val transfer = moveBack.mul(rotation).mul(recenter) //order from right to left

    val eye = Vector3f(0f, modelCenter.y, -focalLength).mulProject(transfer)
    val up = Vector3f(0f, 1f, 0f)
    this.setLookAt(eye, modelCenter, up)
} 

Solution

  • It works in your example because I suppose your target equals the world origin. If you want to rotate around the world origin, you don't need the translation part. If it's around a point it will become mandatory.

    What I like to use when computing the view Matrix is to keep 3 values inside my camera:

    • The camera position (eye)
    • The camera target (center)
    • The camera upVector (up)

    If you want to orbit around your target point you need to apply your rotation on your eye and upVector, once done you can recompute the viewMatrix using a mat4 lookAt(eye, center, up)

    void orbitBy(float yaw, vec3 rotationCenter) {
         mat4 recenter = translate(mat4(1.0), -rotationCenter); //not needed if world origin
         mat4 rotation = rotateY(mat4(1.0), yaw); //can be replaced by glm::eulerAngleZXY(yaw, pitch, roll) ...
         mat4 moveBack = translate(mat4(1.0, rotationCenter)); //not needed if world origin
         mat4 transfo = moveBack * rotation * recenter; //order from right to left
         m_eye = transfo * m_eye;
         m_up = transfo * m_up; 
         m_viewMatrix = lookAt(m_eye, m_center, m_up);
    }
    

    I prefer this approach cause it gives you simpler values which are very helpfull for debugging