0

I've been working on a game engine and recently got to the point where I could easily create a Camera class to manage a view matrix (or allow an easy switch to another). I know conceptually what it must do, but where I'm having trouble is figuring out how to rotate about the local origin (for the view matrix, it would be the same as the translation matrix that is multiplied into a rotation matrix).

I know that in direct mode, you would

glTranslatef(x, y, z);   //move back to origin
glRotatef(angle, x_rot, y_rot, z_rot);   //turn using a quaternion
glTranslatef(-x, -y, -z);   //move back to original location

but I'm not sure how that would translate to a more modern application. Would you do essentially the same thing, make a translation matrix back to origin, rotate, and translate back? For every single object you want to rotate? From what I've tested so far, that method works for viewing, but controlling that in 3D space is unwieldy (I'm not sure how to adjust for the rotation constantly. Convert movement components into a single vec4, multiply by the rotation, apply to the translation, then do the actual rotation?)

It seems like there's a more efficient way than doing three or more 4x4 matrix multiplications that I'm missing.

Here's the specific section after trying out a suggested solution.

Cave Dweller
  • 502
  • 2
  • 4
  • 17

2 Answers2

3

You can do basically the same thing as the sequence you posted without doing full matrix multiplies at runtime. Since the translation matrices are very simple, you can to the multiplication manually. With R being a 3x3 rotation matrix, and p being the position you want to rotate around, you can build your 4x4 matrix by:

  1. Store R in the rotation part of the 4x4 matrix.
  2. Calculate p - R * p, and store the result in the translation part of the 4x4 matrix.

This would reduce it to one matrix * vector multiply, and a vector subtraction. You may want to double check my math, since I just derived it on paper.

Another approach is that you keep rotations and translations separate in your CPU code, update them as needed, and only combine them into a 4x4 matrix when updating the uniform.

Since you have control over the shader code, you don't even have to use a 4x4 matrix to contain the entire transformation. For example, if it's more convenient for you to apply translations before rotations, you can feed a mat3 rotation matrix and a vec3 translation vector into your shader, and add the translation vector to the position before multiplying with the rotation matrix. Keeping the two separate can also be beneficial if you update one of them much more frequently than the other.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • I'm going to test this outside of the Camera class and see if it helps at all, I think you might have gotten it. – Cave Dweller Apr 27 '14 at 05:36
  • Unfortunately it's still rotating around the world origin, and at a slower pace. – Cave Dweller Apr 27 '14 at 05:48
  • Wait, I think I misunderstood your instructions. I'm going to test with the actual Camera class and see if that actually did it. – Cave Dweller Apr 27 '14 at 06:19
  • Alright, testing the actual Camera class, that completely stopped motion in all axes unless rotated. I don't think that will work for a game. – Cave Dweller Apr 27 '14 at 08:15
  • Not sure what exactly you tested. What is described is how to calculate the rotation matrix for rotation around an arbitrary point. You'll still have to combine that with your other transformation. – Reto Koradi Apr 27 '14 at 16:34
  • Ahh, that wasn't clear in your original post. You said "4x4 matrix" without specifying its purpose, and went on to say it would reduce everything to two operations. Alright, I'll try __this__ solution and see if the camera acts as intended. It sounds like it would work. – Cave Dweller Apr 27 '14 at 18:16
  • Alright, it's still rotating about some other axis, and now my small testing mesh is actually turning around its edge by the amount I've rotated. I think it would be more beneficial to have the code right in front of you, so I'm pushing to the GitHub repo and linking directly to the problem area in the main post. – Cave Dweller Apr 27 '14 at 18:32
  • Alright, after toying around with it a bit I think your second solution (store the values separately) works the best, and there's some other mistake I made (probably mixing row-major and column-major accidentally somewhere, maybe in the make_____Matrix functions). Thanks for the response! – Cave Dweller Apr 30 '14 at 23:51
0

I think you're over-complicating it by thinking of the old pipeline.

Form your new transformation matrix, T. Assume you have your existing camera matrix, C. You want C', the modified camera matrix.

There's really only two options. Either:

C' = CT, or
C' = TC

Because what other information have you got?

In practice what you're picking between is the new transform taking effect "before" the existing camera matrix, in which case it'll act in world coordinates, or "after" in which case it'll take place in camera coordinates.

You seem to want pre-multiplication. So use that. The transformation will then take effect in the global coordinate space.

The old OpenGL routines always post multiplied.

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • I'm not exactly sure what you mean by this. Multiply the model/view matrix by the translation matrix? Or create a new model/view matrix and multiply the old one by it (you say "transformation matrix" which to me is ambiguous). If it's just the translation matrix, what about rotation? – Cave Dweller Apr 27 '14 at 05:56
  • One matrix describes the camera. That's the camera matrix. One matrix describes how you'd like to transform the camera. That's the transformation matrix. It doesn't make a jot of difference how you'd describe the matrices — as rotations, translations, skews, or whatever. There's no modelview matrix at all because that's something you compose from model and view matrices, at least one of which is completely irrelevant to your question. – Tommy Apr 27 '14 at 15:02
  • Well I meant model or view, which are essentially the same thing except one's rotation and position are "reversed" relative to the other- unless I'm fundamentally misunderstanding something. So in the case of the camera, then, it would most likely be a view matrix, simply multiplied by a new rotation and/or translation matrix? – Cave Dweller Apr 27 '14 at 18:14
  • A view matrix is (informally) the inverse of a model matrix (so that a view from a model shows that model at the origin) but I think it's more normal just to invert the thing there and then than to spend your entire time composing the individual inverse transformations in the opposite order. But, yeah, you'd multiply by another matrix, a rotation or a translation in every likely scenario, just as a post- rather than a pre- (or vice versa if you're composing an inverse step by step rather than inverting at the last minute). – Tommy Apr 27 '14 at 18:50
  • So you're saying I should simply compose my transformation then multiply by the old view matrix (since this is a camera)? `mat4f transformation = rotation.toRotationMatrix() * translation;` (`rotation` is a quaternion) and then `view_mat = view_mat * transformation;`? Or is that something like the complete opposite of what you were saying? – Cave Dweller Apr 27 '14 at 18:55
  • Yes, pretty much. Once the order of the two things is selectable (which it wasn't with `glRotate`/etc) you no longer need to think about order-of-operation workarounds; just specify the order of operations by selecting whether to pre- or post-multiply. Try it both ways around to see the difference. – Tommy Apr 27 '14 at 19:10
  • Alright, let me show you the problems with that... With the snippet I posted above, it looks like [this](http://i.imgur.com/TNqpkgh.png). Alright, no problem, swap the order of the [second set of multiplications](http://i.imgur.com/Y3nqFOO.png)- nope. Swap the order of the first set but not the second: http://i.imgur.com/zeA0NJS.png Swap both: http://i.imgur.com/9V55ppT.png You're ignoring something fundamental about matrix multiplication- it is not commutative: en.wikipedia.org/wiki/Matrix_multiplication#All_matrices. – Cave Dweller Apr 27 '14 at 19:35
  • I spent my answer and all of my comments trying to impress upon you the difference between pre- and post-multiplication. If what you're getting from this is "matrix multiplication is commutative" then you're clearly not actually actually reading what I'm writing. Which implies little benefit in writing any more. Suffice to say, if you understood the maths you'd understand that I've given you the correct answer. – Tommy Apr 27 '14 at 20:07