简体   繁体   中英

What's wrong with my camera?

I'm using VS2010 together with C# and XNA 4.0. I'm following the book "Learning XNA 4.0" by Aaron Reed. I added the camera game component to my project but this camera behaves really weird. Moving mouse makes it "jump" and then crash. I don't know what is causing this. It looks that the code is almost identical to that in book. It worked earlier, but now it isn't, although I can't remember whether I change anything in it (I think not). Note that I am only registering this component in game, nothing more. It should work, but it does not. Any help would be great. Here's the code:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace MyGame
{
    public class Camera : Microsoft.Xna.Framework.GameComponent
    {

        public Matrix View { get; protected set; }
        public Matrix Projection { get; protected set; }
        public Vector3 CameraPosition { get; protected set; }
        public Vector3 CameraDirection { get; protected set; }
        public Vector3 CameraUp { get; protected set; }
        private MouseState prevMouseState;

        public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
            : base(game)
        {
            // Some initialization of camera.
            CameraPosition = pos;
            CameraDirection = target - pos;
            CameraDirection.Normalize();
            CameraUp = up;
            CreateLookAt();

            Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.PiOver4,                
                (float)Game.Window.ClientBounds.Width /
                (float)Game.Window.ClientBounds.Height,
                1f, 3000f);
        }

        public override void Initialize()
        {
            // Set mouse position and do initial get state.
            Mouse.SetPosition(Game.Window.ClientBounds.Width / 2,
                Game.Window.ClientBounds.Height / 2);
            prevMouseState = Mouse.GetState();

            base.Initialize();
        }


        public override void Update(GameTime gameTime)
        {
            // Standard WSAD keyboard movement.
            if (Keyboard.GetState().IsKeyDown(Keys.W))
                CameraPosition += CameraDirection;
            if (Keyboard.GetState().IsKeyDown(Keys.S))
                CameraPosition -= CameraDirection;
            if (Keyboard.GetState( ).IsKeyDown(Keys.A))
                CameraPosition += Vector3.Cross(CameraUp, CameraDirection);
            if (Keyboard.GetState().IsKeyDown(Keys.D))
                CameraPosition -= Vector3.Cross(CameraUp, CameraDirection);

            // Yaw rotation (via mouse).
            CameraDirection = Vector3.Transform(CameraDirection,
                Matrix.CreateFromAxisAngle(CameraUp, (-MathHelper.PiOver4 / 150) *
                (Mouse.GetState().X - prevMouseState.X) 
                ));

            // Pitch rotation (via mouse).
            CameraDirection = Vector3.Transform(CameraDirection,
                Matrix.CreateFromAxisAngle(Vector3.Cross(CameraUp, CameraDirection),
                (MathHelper.PiOver4 / 100) *
                (Mouse.GetState().Y - prevMouseState.Y) 
                ));

            CameraUp = Vector3.Transform(CameraUp,
                Matrix.CreateFromAxisAngle(Vector3.Cross(CameraUp, CameraDirection),
                (MathHelper.PiOver4 / 100) *
                (Mouse.GetState().Y - prevMouseState.Y)
                ));

            prevMouseState = Mouse.GetState();

            CreateLookAt();
            base.Update(gameTime);
        }

        private void CreateLookAt()
        {
            View = Matrix.CreateLookAt(CameraPosition,
                CameraPosition + CameraDirection, CameraUp);
        }
    }
}

Can someone please check whether this code works for him? Any idea would be great!

//EDIT 1: In game's initialization I use code:

Camera cam = new Camera(this, new Vector3(0, 0, 100), Vector3.Zero, Vector3.Up);
Components.Add(cam);

and then I draw model. I use cam's view and projection matrices in model's BasicEffect.

//EDIT 2: Something's seriously wrong. I did some debuging and it seems that at some point those Vector3 objects have their X,Y,Z properties set to NaN. I couldn't find out how and when. Also (perhaps this is nothing) after running for some time gameTime shows that the elapsed game time is ONLY 16 miliseconds (like it skips frames?) and that the game is running slowly. This 16 miliseconds is always the same, no matter when I debug.

Is it possible that I somehow messed up XNA/C# settings? If so, can someone give me any hint what to do now?

    // Pitch rotation (via mouse).
    CameraDirection = Vector3.Transform(CameraDirection,
        Matrix.CreateFromAxisAngle(Vector3.Cross(CameraUp, CameraDirection),
        (MathHelper.PiOver4 / 100) *
        (Mouse.GetState().Y - prevMouseState.Y) 
        ));

    CameraUp = Vector3.Transform(CameraUp,
        Matrix.CreateFromAxisAngle(Vector3.Cross(CameraUp, CameraDirection),
        (MathHelper.PiOver4 / 100) *
        (Mouse.GetState().Y - prevMouseState.Y)
        ));

Whenever you use CreateFromAxisAngle, the first param (the axis) needs to be a unit length vector. If it isn't a unit length vector, it will result in a distorted (skewed) Matrix and one that is over (or under) rotated.

Whenever you cross two vectors the result in rarely a unit length vector. To make a result of a cross unit length. try this:

Vector3.Transform(CameraDirection, Matrix.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(CameraUp, CameraDirection)), ...

by adding the 'Normalize', it makes the result of the cross a unit length vector. Don't forget to do the same to the yaw line as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM