What's happening here?

Hey guys,

I’ve been playing around with different camera projections etc. and I’ve come across some behavior that I can’t seem to wrap my head around.

I’m rendering some vertices like so,


floorVerts[0].Position = new Vector3(-20, -20, 0);
floorVerts[1].Position = new Vector3(-20, 20, 0);
floorVerts[2].Position = new Vector3(20, -20, 0);

floorVerts[3].Position = floorVerts[1].Position;
floorVerts[4].Position = new Vector3(20, 20, 0);
floorVerts[5].Position = floorVerts[2].Position;`

With the following position and look at vectors,

public Vector3 position = new Vector3(0, 0, 30); public Vector3 lookAtVector = new Vector3(0, 1, 0);

Which when using an Up vector of (0, 0, 1) renders completely fine. However if I set the Y value of the look at vector to anything below zero I’m not seeing the results I would expect, instead it seems the camera flips 180 degrees around the Z axis, almost like it has been spun around.

I understand why I wouldn’t see any vertices rendered if the target vector was (0, 0, 0), I’m just confused why the camera wouldn’t just keep looking “further back” along the Y axis, but instead seems to suddenly flip. I’m sure I’m missing something completely obvious here :smiley:

You can read through the source code of the functions you’re calling if you want to understand it mathematically, but to explain it simply, the camera will always be aligned so that its up vector is closer to the one you define (0, 0, 1) than its inverse (0, 0, -1).

You can stand up and imagine that your eyes are the camera, your feet are the origin, and up is up. Then (0, 1, 0) is 1 ft. in front of you, so you tilt your head towards the ground, but it’s still generally upright. If you look at (0, 0, 0) then you’re looking straight down at your feet. Now if you want to look at (0, -1, 0), 1 ft. behind you, you don’t keep tilting your head down because then it feels upside down. Instead you turn around so your head is tilted towards the ground but again feels generally upright.

instead it seems the camera flips 180 degrees around the Z axis, almost like it has been spun around.

Maybe it’s its simpler to understand to just say your at or near the gimble point.

You get gimble lock when your forward and up vector are parrallel as a direction.

You hear alot about gimble lock which is annoying but you also have a gimble inflection point if you use a static up vector or a static forward one that is hard set like Vector3.Up (you will have that no matter what, unless you make your camera have a free up). To do that you use your cameraMatrix’s up vector itself as the up.

Once the vectors you feed to createlookat move past each other you get spin round.
Realize that for the cross product that is used to calculate the right vector internally, the order matters for it.
If you feed a cross product (a, b) you get a opposite direction of (b, a) so if one of your vectors never moves.
As one of the directions (forward) go pasts the other (up), you spin the right all the way around, its basically like feeding the up then forward to the CreateLookAt were a second ago it was taking cross(forward up). Of course you didn’t feed the function things in different order but as your vectors go past each other the right vector that is generated is reversed,

This is a snippet from a ad hock camera i made the other day the function demonstrates the idea of a free camera.

If you do this you don’t have a fixed up and you are like a pilot in space things are as they are, There is no gimble lock point anymore so neither is there gimble lock or a inflection point to spin around.

        Vector3 position = Vector3.Zero;
        void UpdateMovementCam(GameTime gameTime)
            // key presses

            Vector3 rotationalMoment = Vector3.Zero;

            // rotational
            if (Keyboard.GetState().IsKeyDown(Keys.W))
                rotationalMoment.Y += rotspeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.S))
                rotationalMoment.Y += -rotspeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.A))
                rotationalMoment.X += rotspeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.D))
                rotationalMoment.X += -rotspeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.C))
                rotationalMoment.Z += rotspeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.Z))
                rotationalMoment.Z += -rotspeed * elapsed;

            // movement
            if (Keyboard.GetState().IsKeyDown(Keys.E))
                position += camera.Forward * movespeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.Q))
                position += camera.Forward * -movespeed * elapsed;
            // strafe
            if (Keyboard.GetState().IsKeyDown(Keys.Up))
                position += camera.Up * movespeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.Down))
                position += camera.Up * -movespeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
                position += camera.Right * -movespeed * elapsed;
            if (Keyboard.GetState().IsKeyDown(Keys.Right))
                position += camera.Right * +movespeed * elapsed;

            // free camera
            camera *=
                            Matrix.CreateFromAxisAngle(camera.Forward, rotationalMoment.Z) *
                            Matrix.CreateFromAxisAngle(camera.Up, rotationalMoment.X) *
                            Matrix.CreateFromAxisAngle(camera.Right, rotationalMoment.Y) 
            forward = camera.Forward;
            camera.Translation = position;
            camera = Matrix.CreateWorld(position, forward, camera.Up);
            view = Matrix.CreateLookAt(camera.Translation, camera.Translation + camera.Forward, camera.Up);

Now if you want the best of both worlds as a free cam with no gimble lock and having a fixed up gives you a fixed point of gravity that can be very nice.
Then you have to comprimise and turn a free camera into a not quite so free camera,
You have to build a additional function to (gravitate / nudge) the up vector towards were you think up should be and softly up over time. Which really means figuring out what is the horizon and calculating a blending up vector from a right and forward.
That really depends on your needs most of the time a fixed up is just fine but not always.

What to choose as the gravity pull for your up vector for a free camera in different situations ? and how do you want to apply it is a whole other topic which is more of a art then a science.