Apologies if the title doesn't quite make sense, it's been a long time since I did any 3D stuff. I would like to be able to pan my camera up and down with the arrow keys. The camera's rotation is described by a quaternion, and I need to rotate that quaternion around an imaginary axis orthogonal to the way the camera is pointing (if you can imagine the camera mounted on the front of a big + then the axis I need would be the horizontal bars).

I know how many radians I need to rotate by, but I'm struggling to work out how to get the axis I need to rotate around. I've tried to draw what I mean:

MS paint quaternion rendering

The red line is where my camera is actually facing. It (eventually) will be able to tilt left and right as well. The green line is "up" from where the camera is pointing, and the blue line is the axis I want to rotate around for up/down panning. Please try and imagine they're all at right angles.

How do I rotate my quaternion q around the blue line by r number of radians? Is there something I can do with a matrix here and skip looking for an axis? If it helps I'm using g3n in golang so this is what I have to work with.

  • \$\begingroup\$ If your quaternion is \$q\$, don't you just want the vector \$q r q^{-1}\$ where \$r\$ is your right-hand vector in local coordinates (eg (1,0,0) )? \$\endgroup\$
    – DMGregory
    Jun 16, 2021 at 21:13
  • \$\begingroup\$ I'm not entirely sure how to interpret qrq-1 sorry. Should I multiply those terms? I need to read more on this, I have no idea how to multiply a quaternion by a vector. \$\endgroup\$ Jun 16, 2021 at 21:34
  • \$\begingroup\$ In the usual way. \$\endgroup\$
    – DMGregory
    Jun 16, 2021 at 21:48
  • \$\begingroup\$ I have very rarely, if ever, encountered mathematical notation like that beyond what is typically taught in school in my life so "the usual way" is relatively alien to me when the subject matter is talking about conjugation and Hamilton products. I'm going to try and work this article out regardless, cheers. \$\endgroup\$ Jun 16, 2021 at 22:04

1 Answer 1


With a push in the right direction from DMGregory I managed to get this working after a bit of tweaking with the order of multiplication. I was probably overthinking the issue to begin with, but the code looks like this:

// Find our new camera quaternion by multiplying quaternions describing l/r and u/d panning.
camPos := math32.NewVector3(cam.Position().X, cam.Position().Y, cam.Position().Z)
camRot := math32.NewQuaternion(cam.Quaternion().X, cam.Quaternion().Y, cam.Quaternion().Z, cam.Quaternion().W)

upDownRot := math32.NewQuaternion(0, 0, 0, 0).SetFromAxisAngle(math32.NewVector3(1, 0, 0), upDownPanSpeed)
leftRightRot := math32.NewQuaternion(0, 0, 0, 0).SetFromAxisAngle(upVec, leftRightPanSpeed)
camRot = leftRightRot.Multiply(camRot.Multiply(upDownRot))

// Rotate the velocity vector which describes "new" movement to our cam's orientation, then add it to the current position.
newPos := math32.NewVector3(leftRightSpeed, upDownSpeed, forwardBackSpeed).ApplyQuaternion(camRot).Add(camPos)
cam.SetPosition(newPos.X, newPos.Y, newPos.Z)

This answer was particularly helpful in sorting the multiplication order.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .