XNA / Monogame 3D拉伸和Aspect比率

问题描述 投票:0回答:1

我正在尝试使用可移动相机正确地将一些3D模型绘制到屏幕上,但我遇到了两个问题。第一个问题立即可见:模型应该是立方体,但是绘制为矩形棱柱。这就像他们被压扁/压缩,但我找不到它的理由。

Sides of cubes

在俯视“立方体”时会出现第二个问题。虽然它们应该只是旋转,但它们在旋转时似乎以奇怪的方式伸展。

Looking down

Still looking down, but rotated CW 90 degrees

这是我的相机代码:

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

我知道代码位很长并且可能难以理解,但我非常感谢任何帮助。谢谢!

3d xna directx monogame xna-4.0
1个回答
0
投票

好吧,我很蠢。解决方案很简单 - 投影矩阵就是问题所在。

在我的代码中,当我设置ProjectionMatrix时,我将其宽高比设置为ScreenWidth / ScreenHeight。但是,由于这两个都是整数,因此结果也是整数。因此,不是使用16:9的正确纵横比,这是ScreenWidth / ScreenHeight的非整数结果,而是将其转换为整数,我的纵横比最终为ScreenWidth / ScreenHeight = 1920 / 1080 = (int)1.7778 = 1

显然,解决方案很简单。将浮子贴在除数上,最后得到正确的答案。 ScreenWidth / (float)ScreenHeight = 1920 / 1080.0f = 1.7778f

我希望我的挣扎能够帮助其他人解决这个问题。此外,如果您在使用XNA创建3D相机时遇到任何其他问题,我建议您查看this代码示例。它是为手机设计的(出于某种原因?)它是一个DLL,这意味着你将无法运行它(你必须添加一个可执行项目,引用DLL,并重建任何可执行项目你编辑DLL的时间),但它仍然是一个很好的起点/参考点。

Glorious correctly-aspected cubes

© www.soinside.com 2019 - 2024. All rights reserved.