问题
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.
回答1:
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:
- Store
R
in the rotation part of the 4x4 matrix. - 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.
回答2:
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.
来源:https://stackoverflow.com/questions/23319269/is-there-a-standard-way-to-rotate-around-local-coordinates-that-is-from-a-mode