Что не так с моей камерой? - PullRequest
0 голосов
/ 26 июля 2011

Я использую VS2010 вместе с C # и XNA 4.0.Я слежу за книгой "Изучение XNA 4.0" Аарона Рида.Я добавил компонент игры с камерой в свой проект, но эта камера ведет себя очень странно.Движущаяся мышь заставляет ее «прыгать», а затем падает.Я не знаю, что вызывает это.Похоже, что код почти идентичен тому, что написано в книге.Это работало раньше, но теперь это не так, хотя я не могу вспомнить, изменил ли я что-нибудь в этом (я думаю, нет).Обратите внимание, что я только регистрирую этот компонент в игре, не более того.Это должно работать, но это не так.Любая помощь будет отличной.Вот код:

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);
        }
    }
}

Может кто-нибудь проверить, работает ли этот код у него?Любая идея была бы отличной!

// РЕДАКТИРОВАТЬ 1: В инициализации игры я использую код:

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

и затем рисую модель.Я использую матрицы вида и проекции камеры в BasicEffect модели.

// РЕДАКТИРОВАТЬ 2: Что-то серьезно не так.Я сделал некоторую отладку, и кажется, что в какой-то момент эти объекты Vector3 имеют свойства X, Y, Z, установленные на NaN.Я не мог узнать, как и когда.Также (возможно, это ничто) после запуска в течение некоторого времени gameTime показывает, что истекшее время игры составляет ТОЛЬКО 16 миллисекунд (как если бы он пропускал кадры?) И что игра работает медленно.Эти 16 миллисекунд всегда одинаковы, независимо от того, когда я отлаживаю.

Возможно ли, что я каким-то образом испортил настройки XNA / C #?Если да, может ли кто-нибудь дать мне подсказку, что делать сейчас?

1 Ответ

2 голосов
/ 26 июля 2011
    // 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)
        ));

Каждый раз, когда вы используете CreateFromAxisAngle, первый параметр (ось) должен быть вектором единичной длины.Если это не вектор единичной длины, это приведет к искаженной (перекошенной) матрице и повернутой над (или ниже) матрицей.

Всякий раз, когда вы пересекаете два вектора, результат редко дает вектор единичной длины,Чтобы сделать результат поперечной единицы длины.попробуйте это:

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

, добавив 'Normalize', это делает результат пересечения вектором единичной длины.Не забудьте также сделать то же самое с линией рыскания.

...