XNA 4.0: 2D-камеры Y и X движутся в неправильном направлении

Итак, я знаю, что есть несколько вопросов/ответов относительно создания 2D-камеры для XNA, однако люди, похоже, просто счастливы публиковать свой код без объяснения причин. Я ищу больше объяснений того, что я делаю неправильно.

Во-первых, я понимаю весь Мир -> Вид -> Проекция -> Трансформация экрана.

Моя цель состоит в том, чтобы объект камеры находился в центре окна просмотра, и когда положение камеры перемещается вверх, оно коррелирует с перемещением вверх в окне просмотра, а когда оно перемещается вправо, оно коррелирует с перемещением вправо в окне просмотра.

У меня возникли трудности с реализацией этой функции, потому что значение Y области просмотра инвертировано.

//In Camera Class
private void UpdateViewTransform()
{
//My thinking here was that I would create a projection matrix to center the camera and then flip the Y axis appropriately
     Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0)) * 
                   Matrix.CreateScale(new Vector3(1f, -1f, 1f));

//Here is the camera Matrix. I have to give the Inverse of this matrix to the Spritebatch I believe since I want to go from World Coordinates to Camera Coordinates
     _viewMatrix = Matrix.CreateRotationZ(_rotation) *
                  Matrix.CreateScale(new Vector3(_zoom, _zoom, 1.0f)) *
                  Matrix.CreateTranslation(_position.X, _position.Y, 0.0f);

     _viewMatrix = proj * _viewMatrix;

}

Может ли кто-нибудь помочь мне понять, как я могу построить свое преобразование представления для передачи в SpriteBatch, чтобы я достиг того, что ищу.

ИЗМЕНИТЬ

Кажется, что это преобразование работает, но я не уверен, почему. Может кто-нибудь, возможно, сломать это для меня в понимании:

Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0));
    _viewMatrix = Matrix.CreateRotationZ(_rotation) *
                 Matrix.CreateScale(new Vector3(_zoom, _zoom, 1.0f)) *
                 Matrix.CreateTranslation(-1 * _position.X, _position.Y, 0.0f);

    _viewMatrix = proj * _viewMatrix;

Раньше я создавал трассировщик лучей, поэтому я должен понять ваше понимание, мое замешательство связано с тем фактом, что он 2D и что SpriteBatch скрывает от меня то, что он делает. Спасибо! Фарид


person Setheron    schedule 18.08.2011    source источник
comment
Вы пробовали просто использовать 1f в своей шкале, а не -1f?   -  person ChrisF    schedule 19.08.2011
comment
Однако использование 1f привело к инвертированию перевода x :(   -  person Setheron    schedule 19.08.2011


Ответы (3)


Если вы переворачиваете все по оси Y с помощью своей масштабной матрицы, это означает, что вы переворачиваете модели, которые рисует SpriteBatch (текстурированные четырехугольники). Это означает, что вы также должны изменить порядок намотки (то есть: отсечение обратной стороны интерпретирует то, что вы рисуете обратную сторону треугольников, обращенных к камере, поэтому оно отбрасывает их, поэтому вам нужно изменить правило, которое оно использует).

По умолчанию SpriteBatch использует RasterizerState.CullCounterClockwise. Когда вы вызываете SpriteBatch.Begin, вместо этого вам нужно передать RasterizerState.CullClockwise.

И, конечно же, Begin — это место, где вы проходите в своей матрице преобразования.

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

person Andrew Russell    schedule 19.08.2011
comment
Таким образом, нет никакого способа получить мою ось координат, как я ожидал бы, через преобразование? - person Setheron; 19.08.2011
comment
@Setheron: Суть моего ответа в том, что да, можете. Просто инвертирование оси потребует и инвертирования порядка намотки. И что я не знаю точных матричных операций, которые нужно использовать, навскидку. Хотя, возможно, посмотрите на эта статья, в которой показана внутренняя матрица, которую использует SpriteBatch, применительно к BasicEffect. (Возможно, вы могли бы даже использовать этот код, чтобы использовать BasicEffect с SpriteBatch и напрямую инвертировать матрицу проекции.) - person Andrew Russell; 19.08.2011
comment
Я смог заставить свою систему координат работать, как и ожидалось (с положительной осью Y), и рендеринг моих спрайтов, следуя предложению Эндрю. - person BrettMStory; 18.06.2016

Я много боролся с XNA, пытаясь сделать его похожим на другие движки, с которыми я работал раньше... моя рекомендация: это того не стоит.. Просто придерживайтесь стандартов XNA и используйте вспомогательные методы Matrix для создания матриц Perspective/Viewport.

person James    schedule 02.03.2012

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

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

Создание матрицы представления

  1. Примените вращение камеры. Мы делаем это по оси Z только потому, что это для 2D-камеры.
  2. Apply the transformation of the Camera. This make sense since we want the World coordinate which is the sum of the camera coordinate and the object relative to the camera.
    1. You might notice that I multiplied the Y Component by -1. This is so that increasing the Camera's Y Position correlates to moving up since the screen's Y value points downward.
  3. Применить зум камеры

Теперь обратная матрица будет выполнять World Coordinate -> View Coordinates.

Я также решил расположить камеру по центру экрана, поэтому включил предварительно добавленный перевод.

Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0));

        _viewMatrix = Matrix.CreateRotationZ(moveComponent.Rotation) *
                    Matrix.CreateTranslation(moveComponent.Position.X, -1 * moveComponent.Position.Y, 0.0f) *
                     Matrix.CreateScale(new Vector3(zoomComponent.Zoom, zoomComponent.Zoom, 1.0f));

        _viewMatrix = proj * Matrix.Invert(_viewMatrix);
person Setheron    schedule 19.08.2011