how to rotate using long/long coords instead of lat/long

Started by
6 comments, last by Doctor Zero 13 years, 9 months ago
I'm working on a starfield simulation in Direct3D (v10) and I want it to be able to turn left/right, or up/down randomly. The problem I'm having is that as the direction gets closer to "down" or "up", turning left or right turns into a spin. My code is as follows:
            ForwardDirection = new Vector3(0, 0, 1);            vUp = new Vector3(0, 1, 0);            vRight = new Vector3(1f, 0f, 0f);            Matrix matRotation;            //Rotate by fxr radians on the Y-axis            matRotation = Matrix.RotationAxis(vUp, (float)fxr);            ForwardDirection.TransformCoordinate(matRotation);            vRight.TransformCoordinate(matRotation);            //Rotate by fyr radians on the new X-axis            matRotation = Matrix.RotationAxis(vRight, (float)fyr);            ForwardDirection.TransformCoordinate(matRotation);            vUp.TransformCoordinate(matRotation);


I think a more concise way to explain the desired effect would be that I want a rotation of fxr to be along a longitudinal line, but the code I currently have rotates fxr along a latitudinal line.

I've tried several tweaks and am unable to achieve the desired effect. Surely there is an easy way to do this?
Advertisement
Sounds like gimbal lock. The solution is fairly well known the wiki page on it has the relevant math.
It's not gimbal lock. It's just manual modification of individual Euler angles not working like you want it to work.

Rather than keep around fxr and fyr, keep around matRotation. When you need to rotate it, create a rotation matrix deltaRotation from fxr or fyr, then premultiply or postmultiply matRotation by it (depending on what effect you want). Incidentally, none of that requires ForwardDirection, vUp, or VRight (well, I guess you need them for creating deltaRotation, but they're just the unit X or Y vectors). When working with matrices other than look-at matrices, you tend to combine them directly rather than playing with matrix-vector multiplication.
Thanks for the help. After studying Euler angles, I understand the problem better, and taking your advice regarding using deltas, I was able to solve the problem.

However I'm still using vectors, but now time I'm preserving the values of the vectors and just rotating them by deltas each time.

The reasons for this are
A) I need vUp and ForwardDirection to build the View matrix, and I need ForwardDirection to move the camera forward through space; and
B) I'm still fairly new to matrices. In this case my world transform is always Matrix.Identity; instead of moving the stars or translating the world, the ship moves forward through the stars, and lookat is derived from CameraPosition + ForwardDirection + LookDirection (lookdirection is determined by the mouse).

Is this bad practice? Why is it better to manipulate matrices than vectors? This is only my 3rd Direct3D app so I'm still pretty new to this.
Quote:Original post by Doctor Zero
A) I need vUp and ForwardDirection to build the View matrix
No you don't. Nothing says that you have to put a look-at matrix in your view matrix. A look-at matrix is just a rotation followed by a backwards translation.
Quote:and I need ForwardDirection to move the camera forward through space
You'll find the forward direction in the third column of your matrix. (Or the third row, depending on your matrix layout.)
Quote:B) I'm still fairly new to matrices.

All the more reason to learn to do it right, then.
Quote:Why is it better to manipulate matrices than vectors? This is only my 3rd Direct3D app so I'm still pretty new to this.
Well, it's a little more efficient, but the main reason is because it allows you to think in terms of transformations instead of vectors. Really, once you understand how basic transformations can be combined to achieve whatever effect you want, you'll have a much easier time of things than juggling vectors.
Quote:I need vUp and ForwardDirection to build the View matrix
You don't actually; to build the view matrix, you can simply invert the world transform matrix for the camera.
Quote:and I need ForwardDirection to move the camera forward through space
You can extract the forward direction vector (and the up and side vectors as well, if needed) from the transform matrix for the camera.
Quote:Is this bad practice? Why is it better to manipulate matrices than vectors?
IMO, working with the direction vectors directly is a fairly roundabout way of manipulating an object's orientation. Basically what you're doing is manually replicating functionality that will already exist in any decent math library. Instead of using three direction vectors, I recommend representing orientations using a matrix or quaternion, as most math libraries will already include functions for building and applying rotation transforms using these representations.

It seems it's somewhat common to implement cameras in terms of 'side, up, and forward' vectors, which I suspect is due to an over-reliance on 'look-at' view transform functions. What people don't seem to realize is that a 'look-at' function is merely a convenience; it's not the 'only way' to create a view transform. Remember, the view transform is just the inverse of the camera world transform, nothing more, nothing less.

[Edit: Mostly a repeat of what Sneftel said...]
For a 3x3 orthonormal rotation matrix, the three columns (or rows, depending how your matrix is laid out) represent the basis vectors for the transformation space. Put in simpler terms, the first three columns are your X, Y, and Z axes. That is, the first three columns are your right vector, up vector, and backward vector (using OpenGL conventions). If you use a 4x4 matrix, and only perform rotation and translation, the first three columns are those same X, Y, Z axes and the fourth is the position.
Thanks everyone for the help. I hate to admit it but i'm still having trouble understanding how these matrices work. I can't find a single example anywhere on how to build a view matrix without using LookAtLH. Fortunately, the code I have using a combination of vectors and matrices works right now, but often the camera gets all jittery and I noticed that even when my rotation deltas are all set to zero, my vectors keep changing. Should I stick with a static view matrix and alter the world matrix instead?

Here's what I got:
        static Vector3 ForwardDirection = new Vector3(0, 0, 1); //direction we are travelling        static Vector3 BaseUpVector = new Vector3(0, 1, 0); //Ship up vector        static Vector3 BaseRightVector = new Vector3(1, 0, 0); //ship right vector        static Vector3 vLook = new Vector3(0, 0, 1); // Actual Look direction        static Vector3 vUp = new Vector3(0.0f, 1.0f, 0.0f);   // Look Up Vector        static Vector3 vRight = new Vector3(1.0f, 0.0f, 0.0f);   // Look Right Vector//updates the direction of the ship based on rotation deltas fxrsp, fyrsp, fzrsp        private void UpdatForwardMatrix()        {            Matrix matRotation, DeltaMatrix;            matRotation = Matrix.RotationAxis(ForwardDirection, (float)fzrsp) * Matrix.RotationAxis(BaseRightVector, (float)fyrsp);            DeltaMatrix = matRotation;            BaseUpVector.TransformCoordinate(matRotation);            //must use modified up vector to turn in the proper direction            matRotation = Matrix.RotationAxis(BaseUpVector, (float)fxrsp);            ForwardMatrix *= matRotation;            BaseRightVector.TransformCoordinate(DeltaMatrix);            ForwardDirection.TransformCoordinate(DeltaMatrix);            vUp = BaseUpVector;            vRight = BaseRightVector;            vLook = ForwardDirection;        }//Looks l/r/u/d relative to cockpit based on rotations xr, yr derived from mouse        private void UpdateViewMatrix()        {            Matrix matRotation;            matRotation = Matrix.RotationAxis(vUp, (float)xr);            vLook.TransformCoordinate(matRotation);            vRight.TransformCoordinate(matRotation);            matRotation = Matrix.RotationAxis(vRight, (float)yr);            vLook.TransformCoordinate(matRotation);        }        private void Render()        {            UpdateForwardMatrix();            UpdateViewMatrix();            //move the ship forward            CameraLocation += Vector3.Multiply(ForwardDirection, (float)Speed);            d3dDevice.Transform.World = Matrix.Identity;            Vector3 LookAt = Vector3.Add(CameraLocation, vLook);            d3dDevice.Transform.View = Matrix.LookAtLH(CameraLocation, LookAt, vUp);            d3dDevice.Transform.Projection = Matrix.PerspectiveFovLH(fov, AR, 0, 10000);            //Render everything here        }


I also tried using a persistent view matrix starting out with LookAtLH(pos(0,0,0), lookat(0,0,1), up(0,1,0)) and translating and transforming it by deltas each frame, but my original problem came back plus a couple new problems, and it didn't solve the jitter issue either.

Can anyone either show me the right way to do this or point me in the right direction (using matrices, of course) to learn how to implement this properly? Also how can I get rid of the "jittery camera" issue?

This topic is closed to new replies.

Advertisement