Понимание матрицы проекции - PullRequest
1 голос
/ 24 мая 2011

Я пытаюсь понять, каков диапазон значений проецируемых векторов.Кажется, это расходится с тем, что говорит MSDN.

Код ниже выводит цветной треугольник.Треугольник полностью виден.Я ожидаю, что после проецирования вершин будет выполнено следующее:

X и Y находятся в диапазоне от -1 до 1. Z находится в диапазоне от 0 до 1.

Я получил эту информацию отсюда: http://msdn.microsoft.com/en-us/library/bb195665.aspx

Однако, когда я вручную преобразовываю вершины треугольника, используя произведение вида и матрицы проекции, они имеют следующие значения:

{X: 1,8 Y: 0 Z: 3,991996} {X: 0 Y: 3 Z: 3,991996} {X: -1,8 Y: 0 Z: 3,991996}

Почему значения выходят за пределы видимого диапазона, а треугольник полностью виден?

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using Microsoft.Xna.Framework.Input;

namespace WasMachtDieProjektion
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        Matrix _view;
        Matrix _projection;
        VertexPositionColor[] _verticies;
        Vector3[] _vectors;
        BasicEffect _effect;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void LoadContent()
        {
            _vectors = new Vector3[] {
                new Vector3(-3,0,0),
                new Vector3(0,3,0),
                new Vector3(3,0,0)
            };

            _verticies = new VertexPositionColor[] {
                new VertexPositionColor(_vectors[0], Color.AliceBlue),
                new VertexPositionColor(_vectors[1], Color.Yellow),
                new VertexPositionColor(_vectors[2], Color.Red)
            };

            _effect = new BasicEffect(graphics.GraphicsDevice);
            _effect.VertexColorEnabled = true;

            GraphicsDevice.RasterizerState = new RasterizerState() { CullMode = CullMode.None };
        }

        protected override void Update(GameTime gameTime)
        {
            _view = Matrix.CreateLookAt(new Vector3(0, 0, -4f), new Vector3(0, 0, 0), Vector3.Up);
            _projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.Viewport.AspectRatio, 0.01f, 20f);

            Vector3[] transformed = new Vector3[3];
            Matrix trans = _view * _projection;
            Vector3.Transform(_vectors, ref trans, transformed);

            foreach (var v in transformed)
            {
                Console.WriteLine(v);
            }
            Console.WriteLine("---");

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            _effect.View = _view;
            _effect.Projection = _projection;

            foreach (var pass in _effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, _verticies, 0, 1);
            }

            base.Draw(gameTime);
        }
    }
}

Ответы [ 2 ]

3 голосов
/ 24 мая 2011

Не забывайте перспективное деление после проекции.Это означает, что после умножения на матрицу проекции, делим преобразованные вектора x, y и z на их значения w.Таким образом, вы должны работать с 4D однородными векторами вместо 3D векторов.Ваши начальные векторы просто (x,y,z,1), но после применения проекционной матрицы (которая не является аффинным преобразованием) их w может (и должно) быть != 1, поэтому вы должны отказаться от того, что реализуетфактическое искажение перспективы:

(x', y', z', w') = trans * (x, y, z, 1);
(x'', y'', z'') = (x'/w', y'/w', z'/w');

Обратитесь к некоторым вводным материалам о трехмерных преобразованиях, проекциях и однородных координатах для получения дополнительной информации.

РЕДАКТИРОВАТЬ: Я только что увидел другую ошибкуваш код.trans должно быть _projection * _view, чтобы _view применялся первым при умножении вектора на trans.За исключением случаев, когда XNA использует математически неверное соглашение row_vector * matrix.Если это так, ваш заказ должен это сделать.

0 голосов
/ 24 мая 2011

Не уверен на 100%, но я думаю, что это может быть потому, что это проекционный вид, который, независимо от того, что это за матрица, всегда будет ее представлять. Если бы это был ортогональный вид, он бы тогда не отображал полный треугольник.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...