XNA / Monogame 3D растяжения и пропорции - PullRequest
0 голосов
/ 02 марта 2019

Я пытаюсь правильно нарисовать несколько 3D-моделей на экране с помощью подвижной камеры, но я сталкиваюсь с двумя проблемами.Первая проблема видна сразу: модели должны быть кубами, но рисуются в виде прямоугольных призм.Как будто их раздавливают / сжимают, но я не могу найти причину для этого.

Стороны кубов

Вторая проблема проявляется при взгляде внизна "кубах".Хотя они должны просто вращаться, при вращении они кажутся странными.

Глядя вниз

Все еще смотрю вниз, но повернул CW на 90 градусов

Вот мой код камеры:

public class Camera
{
    private Driver Driver;
    private int ScreenWidth { get { return Driver.GraphicsDevice.Viewport.Width; } }
    private int ScreenHeight { get { return Driver.GraphicsDevice.Viewport.Height; } } 

    public Matrix ViewMatrix { get; private set; }
    public Matrix ProjectionMatrix { get; private set; }

    private const float NearClippingPlane = 0.1f;
    private const float FarClippingPlane = 200.0f;

    public Vector3 Position { get; private set; }

    private Vector3 _direction; // Do not use _direction!
    private Vector3 Direction
    {
        get { return _direction; }
        set
        {
            if (value == Vector3.Zero) { }
            else
            {
                var normalizedTemp = value;
                normalizedTemp.Normalize();

                if (normalizedTemp.Y > -.9999f) _direction = normalizedTemp;
            }
        }
    }

    private Vector3 Up;

    private const float MovementSpeed = 10f;
    private const float PanSpeed = 10f;

    private MouseState previousMouseState;

    private Vector3 HorizontalPlaneDirection
    {
        get
        {
            var direction = new Vector3(Direction.X, 0, Direction.Z);
            if (direction != Vector3.Zero)
                direction.Normalize();
            return direction;
        }
    }

    public Camera(Driver game, Vector3 position, Vector3 target, Vector3 up)
    {
        Driver = game;

        // Build camera view matrix
        Position = position;
        Direction = target - position;
        Up = up;
        CreateLookAt();

        ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(60), ScreenWidth / ScreenHeight, NearClippingPlane, FarClippingPlane);
    }

    public void Initialize()
    {
        // Set mouse position and do initial get state
        Mouse.SetPosition(ScreenWidth / 2, ScreenHeight / 2);

        previousMouseState = Mouse.GetState();
    }

    public void Update(GameTime gameTime, KeyboardState keyboard, MouseState mouse)
    {
        float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
        float moveSpeed = MovementSpeed * elapsed;
        float panSpeed = PanSpeed * elapsed;

        if (keyboard.IsKeyDown(Keys.W))
            Position += HorizontalPlaneDirection * moveSpeed;
        if (keyboard.IsKeyDown(Keys.S))
            Position -= HorizontalPlaneDirection * moveSpeed;

        if (keyboard.IsKeyDown(Keys.A))
            Position += Vector3.Cross(Up, HorizontalPlaneDirection) * moveSpeed;
        if (keyboard.IsKeyDown(Keys.D))
            Position -= Vector3.Cross(Up, HorizontalPlaneDirection) * moveSpeed;

        if (keyboard.IsKeyDown(Keys.Space))
            Position += Up * moveSpeed;
        if (keyboard.IsKeyDown(Keys.LeftShift))
            Position -= Up * moveSpeed;

        // Rotation in the world
        Direction = Vector3.Transform(Direction, Matrix.CreateFromAxisAngle(Up, -MathHelper.ToRadians(1) * (mouse.X - previousMouseState.X) * panSpeed));

        Direction = Vector3.Transform(Direction, Matrix.CreateFromAxisAngle(Vector3.Cross(Up, HorizontalPlaneDirection), MathHelper.ToRadians(1) * (mouse.Y - previousMouseState.Y) * panSpeed));

        Driver.ResetMouseState();
        // Reset prevMouseState
        previousMouseState = Mouse.GetState();

        CreateLookAt();
    }

    private void CreateLookAt()
    {
        ViewMatrix = Matrix.CreateLookAt(Position, Position + Direction, Up);
    }
}

И код для рисования модели:

public void Draw(Camera Camera)
    {
        foreach (var mesh in Model.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                //effect.EnableDefaultLighting();
                //effect.PreferPerPixelLighting = true;

                effect.World = GetWorldMatrix();
                effect.View = Camera.ViewMatrix;
                effect.Projection = Camera.ProjectionMatrix;
            }

            mesh.Draw();
        }
    }

Я знаю, что биты кода длинные и, вероятно, их трудно найти, но я очень ценю любую помощь.Спасибо!

1 Ответ

0 голосов
/ 03 марта 2019

Ну, я тупой.Решение простое - проблема в матрице проекции.

В моем коде, когда я устанавливаю ProjectionMatrix, я устанавливаю соотношение сторон на ScreenWidth / ScreenHeight.Однако, поскольку оба они целые числа , результатом является также целое число .Таким образом, вместо правильного соотношения сторон 16: 9, что является неинтегральным результатом ScreenWidth / ScreenHeight, оно приводится к целому числу, и мое соотношение сторон заканчивается как ScreenWidth / ScreenHeight = 1920 / 1080 = (int)1.7778 = 1.

Очевидно, чтоРешение простое.Прикрепите поплавок к делителю, и вы получите правильный ответ.ScreenWidth / (float)ScreenHeight = 1920 / 1080.0f = 1.7778f.

Я надеюсь, что мой день борьбы смог помочь кому-то еще в этом вопросе.Кроме того, если у вас возникают другие проблемы с созданием 3D-камеры в XNA, я бы посоветовал вам проверить этот пример кода.Он разработан для телефона (по какой-то причине?) И поставляется в виде DLL, что означает, что вы не сможете его запустить (вам придется добавить исполняемый проект, обратиться к DLL и перестроить исполняемый проект любойвремя, когда вы вносите изменения в DLL), но тем не менее это служит хорошей отправной точкой / точкой отсчета.

Великолепные кубики с правильными аспектами

...