奇怪的第一人称相机旋转XNA

时间:2013-11-19 07:16:47

标签: c# xna camera rotational-matrices

我正在尝试在XNA 4.0中创建第一人称视图相机。我让相机工作,我的场景渲染得很好。我用W,A,S,D的动作也很好,但是我无法弄清楚为什么我的鼠标旋转搞乱了。

当我试着用相机向上看时,它会让我的整个世界倾斜并且看向左边和右边。右边做同样的事情,两个都看向同一个方向。最终,我的整个世界翻转:S。

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Brandon
{
    public class FPC : GameComponent
    {   
        private KeyboardState OldKeyboardState;
        private MouseState OldMouseState;

        private Vector3 Target = Vector3.Zero;
        private Vector3 UpVector = Vector3.Up;
        private Vector3 Position = new Vector3(0.0f, 0.0f, 1.0f);
        private Vector2 Velocity = Vector2.Zero;
        private Matrix View = Matrix.Identity;
        private Matrix Projection = Matrix.Identity;
        private BasicEffect Effects = null;
        private float Speed = 5.0f;
        private float WalkingSpeed = 1.0f;
        private float RotationSpeed = 0.1f;
        private float AngleX = 0.0f;
        private float AngleY = 0.0f;

        public BasicEffect Effect
        {
            get { return this.Effects; }
        }

        public FPC(Game game) : base(game)
        {
            Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
            Game.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
            this.Effects = new BasicEffect(Game.GraphicsDevice);
            this.OldMouseState = Mouse.GetState();
        }

        public override void Initialize()
        {
            base.Initialize();
        }

        public void LookAt(float FOV_Degrees, float NearPlaneDistance, float FarPlaneDistance, Vector3 Position, Vector3 Target, Vector3 UpVector)
        {
            this.Position = Position;
            this.Target = Target;
            this.UpVector = UpVector;
            this.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(FOV_Degrees), Game.GraphicsDevice.Viewport.AspectRatio, NearPlaneDistance, FarPlaneDistance);
            this.View = Matrix.CreateLookAt(Position, Target, UpVector);
        }

        private void UpdateView(Matrix rotationMatrix)
        {
            Vector3 finalTarget = this.Position + Vector3.Transform(this.Target, rotationMatrix);
            Vector3 finalUp = Vector3.Transform(this.UpVector, rotationMatrix);
            this.View = Matrix.CreateLookAt(this.Position, finalTarget, finalUp);
        }

        private void ProcessInput(GameTime gameTime)
        {
            bool isWalking = false;
            KeyboardState CurrentKeyboardState = Keyboard.GetState();

            Vector3 pos = Vector3.Zero;
            if (CurrentKeyboardState.IsKeyDown(Keys.W)) pos.Z -= 1.0f;
            if (CurrentKeyboardState.IsKeyDown(Keys.S)) pos.Z += 1.0f;
            if (CurrentKeyboardState.IsKeyDown(Keys.A)) pos.X -= 1.0f;
            if (CurrentKeyboardState.IsKeyDown(Keys.D)) pos.X += 1.0f;
            if (CurrentKeyboardState.IsKeyDown(Keys.LeftShift)) isWalking = true;
            this.OldKeyboardState = CurrentKeyboardState;

            if (pos != Vector3.Zero)
            {
                pos.Normalize(); //So we don't move faster diagonally
                pos *= (float)gameTime.ElapsedGameTime.TotalSeconds * (isWalking ? this.WalkingSpeed : this.Speed); //Smooth movement
            }

            this.ProcessMouseInput(gameTime);

            Matrix rotationMatrix = Matrix.CreateRotationX(this.AngleX) * Matrix.CreateRotationY(this.AngleY);
            this.Position += (isWalking ? this.WalkingSpeed : this.Speed) * Vector3.Transform(pos, rotationMatrix);
            this.UpdateView(rotationMatrix);
        }


        //Rotate the camera using the mouse.
        private void ProcessMouseInput(GameTime gameTime)
        {
            float amount = (float)gameTime.ElapsedGameTime.TotalSeconds;
            MouseState mouse = Mouse.GetState();
            if (mouse != this.OldMouseState)
            {
                int xDist = mouse.X - (Game.GraphicsDevice.Viewport.Width / 2);
                int yDist = mouse.Y - (Game.GraphicsDevice.Viewport.Height / 2);
                this.AngleX -= RotationSpeed * xDist * amount;
                this.AngleY -= RotationSpeed * yDist * amount;
            }

            Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
            this.OldMouseState = mouse;
        }

        //Return a matrix for use with rendering hands holding weapons.
        public Matrix ModelWorldMatrix(float xOffset, float yOffset, float zOffset, float scale)
        {
            Vector3 ModelPos = this.Position;
            ModelPos += this.Target * zOffset;
            ModelPos += Vector3.UnitY * yOffset;
            ModelPos += Vector3.UnitX * xOffset;

            return Matrix.CreateScale(scale) * Matrix.CreateRotationX(MathHelper.ToRadians(this.AngleX)) * Matrix.CreateRotationY(MathHelper.ToRadians(this.AngleY)) * Matrix.CreateTranslation(ModelPos);
        }

        public override void Update(GameTime gameTime)
        {
            ProcessInput(gameTime);
            this.Effects.View = View;
            this.Effects.Projection = Projection;
            this.Effects.World = Matrix.Identity;
            base.Update(gameTime);
        }
    }
}

我尝试了各种示例代码并遵循了我能找到的所有教程,但没有一个我遇到同样的问题。它们要么不起作用,要么落后一吨!

任何想法我做错了什么?

1 个答案:

答案 0 :(得分:2)

您将this.Target初始化为0,0,0。这个值永远不会改变。

然后在UpdateView方法中,您可以通过将finalTarget转换为仅代表轮换的矩阵来计算this.Target

的结果

Vector3.Transform(this.Target, rotationMatrix)

基本相同

Vector3.Transform(Vector3.Zero, rotationMatrix)

实际上,始终会导致(0,0,0)将finalTarget置于与this.Position相同的位置,除了浮点错误,每个组件的小值会导致您的问题。

首先尝试给this.Target值0,0,-1(这会导致初始查找方向与您当前代码尝试的方向相同,但会给出{{1}和某些东西一起工作)你应该没问题。