Неожиданный результат при отмене проецирования координат экрана в DirectX

Чтобы иметь возможность определить, щелкнул ли пользователь какой-либо из моих 3D-объектов, я пытаюсь преобразовать экранные координаты щелчка в вектор, который затем использую для проверки того, попал ли какой-либо из моих треугольников. Для этого я использую XMVector3Unproject, предоставляемый DirectX, и я реализую все на C++/CX.

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

Вектор, полученный в результате непроецирования Положение курсора в момент щелчка (выделено желтым цветом) видно в изометрическом виде слева. Как только я нажимаю, вектор, полученный в результате непроецирования, появляется за моделью, обозначенной на изображениях белой линией, пронизывающей модель. Таким образом, вместо того, чтобы исходить из местоположения курсора и выходить на экран в изометрическом виде, он появляется в совершенно другом месте.

Когда я перемещаю мышь в изометрическом виде по горизонтали, щелкая и после этого перемещая мышь по вертикали и щелкая, появляется рисунок ниже. Все линии на двух изображениях представляют собой векторы, полученные в результате щелчка. Модель удалена для лучшей видимости.

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

Другой ракурс, другое происхождение векторов

Вот фрагменты кода, которые я использую, чтобы придумать это. Прежде всего, я получаю положение курсора, используя приведенный ниже код, и передаю его моему методу «SelectObject» вместе с шириной и высотой области рисования:

void Demo::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
{
  Point currentPosition = e->CurrentPoint->Position;

  if(m_model->SelectObject(currentPosition.X, currentPosition.Y, m_renderTargetWidth, m_renderTargetHeight))
  {
    m_RefreshImage = true;
  }
}

Метод SelectObject выглядит следующим образом:

bool Model::SelectObject(float screenX, float screenY, float screenWidth, float screenHeight)
{
  XMMATRIX projectionMatrix = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->projection);
  XMMATRIX viewMatrix       = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->view);
  XMMATRIX modelMatrix      = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->model);

  XMVECTOR v = XMVector3Unproject(XMVectorSet(screenX, screenY, 5.0f, 0.0f),
                                  0.0f,
                                  0.0f,
                                  screenWidth,
                                  screenHeight,
                                  0.0f,
                                  1.0f,
                                  projectionMatrix,
                                  viewMatrix,
                                  modelMatrix);

  XMVECTOR rayOrigin = XMVector3Unproject(XMVectorSet(screenX, screenY, 0.0f, 0.0f),
                                          0.0f,
                                          0.0f,
                                          screenWidth,
                                          screenHeight,
                                          0.0f,
                                          1.0f,
                                          projectionMatrix,
                                          viewMatrix,
                                          modelMatrix);

  // Code to retrieve v0, v1 and v2 is omitted

  if(Intersects(rayOrigin, XMVector3Normalize(v - rayOrigin), v0, v1, v2, depth))
  {
    return true;
  }
}

В конечном итоге рассчитанный вектор используется Intersects пространства имен DirectX::TriangleTests для определения попадания в треугольник. Я опустил код в приведенном выше фрагменте, потому что он не имеет отношения к этой проблеме.

Для рендеринга этих изображений я использую матрицу ортогональной проекции и камеру, которую можно вращать вокруг обеих осей x и y, что создает матрицу вида. Матрица мира всегда остается неизменной, то есть это просто единичная матрица.

Матрица вида рассчитывается следующим образом (на примере книги Фрэнка Луны «Программирование 3D-игр»):

void Camera::SetViewMatrix()
{
  XMFLOAT3 cameraPosition;
  XMFLOAT3 cameraXAxis;
  XMFLOAT3 cameraYAxis;
  XMFLOAT3 cameraZAxis;

  XMFLOAT4X4 viewMatrix;

  // Keep camera's axes orthogonal to each other and of unit length.
  m_cameraZAxis = XMVector3Normalize(m_cameraZAxis);
  m_cameraYAxis = XMVector3Normalize(XMVector3Cross(m_cameraZAxis, m_cameraXAxis));

  // m_cameraYAxis and m_cameraZAxis are already normalized, so there is no need
  // to normalize the below cross product of the two.
  m_cameraXAxis = XMVector3Cross(m_cameraYAxis, m_cameraZAxis);

  // Fill in the view matrix entries.
  float x = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraXAxis));
  float y = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraYAxis));
  float z = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraZAxis));

  XMStoreFloat3(&cameraPosition, m_cameraPosition);
  XMStoreFloat3(&cameraXAxis   , m_cameraXAxis);
  XMStoreFloat3(&cameraYAxis   , m_cameraYAxis);
  XMStoreFloat3(&cameraZAxis   , m_cameraZAxis);

  viewMatrix(0, 0) = cameraXAxis.x;
  viewMatrix(1, 0) = cameraXAxis.y;
  viewMatrix(2, 0) = cameraXAxis.z;
  viewMatrix(3, 0) = x;

  viewMatrix(0, 1) = cameraYAxis.x;
  viewMatrix(1, 1) = cameraYAxis.y;
  viewMatrix(2, 1) = cameraYAxis.z;
  viewMatrix(3, 1) = y;

  viewMatrix(0, 2) = cameraZAxis.x;
  viewMatrix(1, 2) = cameraZAxis.y;
  viewMatrix(2, 2) = cameraZAxis.z;
  viewMatrix(3, 2) = z;

  viewMatrix(0, 3) = 0.0f;
  viewMatrix(1, 3) = 0.0f;
  viewMatrix(2, 3) = 0.0f;
  viewMatrix(3, 3) = 1.0f;

  m_modelViewProjectionConstantBufferData->view = viewMatrix;
}

На него влияют два метода, которые вращают камеру вокруг осей x и y камеры:

void Camera::ChangeCameraPitch(float angle)
{
  XMMATRIX rotationMatrix = XMMatrixRotationAxis(m_cameraXAxis, angle);

  m_cameraYAxis = XMVector3TransformNormal(m_cameraYAxis, rotationMatrix);
  m_cameraZAxis = XMVector3TransformNormal(m_cameraZAxis, rotationMatrix);
}

void Camera::ChangeCameraYaw(float angle)
{
  XMMATRIX rotationMatrix = XMMatrixRotationAxis(m_cameraYAxis, angle);

  m_cameraXAxis = XMVector3TransformNormal(m_cameraXAxis, rotationMatrix);
  m_cameraZAxis = XMVector3TransformNormal(m_cameraZAxis, rotationMatrix);
}

Матрица мира/модели и матрица проекции вычисляются следующим образом:

void Model::SetProjectionMatrix(float width, float height, float nearZ, float farZ)
{
  XMMATRIX orthographicProjectionMatrix = XMMatrixOrthographicRH(width, height, nearZ, farZ);

  XMFLOAT4X4 orientation = XMFLOAT4X4
  (
    1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f
  );

  XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);

  XMStoreFloat4x4(&m_modelViewProjectionConstantBufferData->projection, XMMatrixTranspose(orthographicProjectionMatrix * orientationMatrix));
}

void Model::SetModelMatrix()
{
  XMFLOAT4X4 orientation = XMFLOAT4X4
  (
    1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f
  );

  XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);

  XMStoreFloat4x4(&m_modelViewProjectionConstantBufferData->model, XMMatrixTranspose(orientationMatrix));
}

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

Изменить 1:

Я предполагаю, что это связано с тем, что моя камера находится в точке (0, 0, 0) в мировых координатах. Камера вращается вокруг своих локальных осей x и y. Насколько я понимаю, матрица обзора, созданная камерой, строит плоскость, на которую проецируется изображение. Если это так, то это объясняет, почему луч находится в каком-то «неожиданном» месте.

Мое предположение состоит в том, что мне нужно сместить камеру из центра, чтобы она находилась за пределами объекта. Однако, если просто изменить переменную-член m_cameraPosition камеры, моя модель будет полностью искажена.

Кто-нибудь может и хочет помочь?


person ackh    schedule 15.06.2016    source источник
comment
Я не знаком с аргументом, но, как я видел в XMVectorSet(screenX, screenY, 5.0f, 0.0f), вы использовали 4D-вектор. Итак, вы работаете в 4D-пространстве, и то, что вы видите, является его 2D-проекцией. я правильно понимаю или нет?   -  person George Kourtis    schedule 25.06.2016
comment
См. это, возможно: stackoverflow.com/a/26662222/1306012   -  person Bruno Bieri    schedule 28.06.2016
comment
На самом деле я использую трехмерные векторы, четвертая часть (0.0f) координат просто подразумевает, что это вектор. Установка его на 1.0f означает, что это точка.   -  person ackh    schedule 28.06.2016


Ответы (4)


Спасибо за подсказку, Капил. Я попробовал метод XMMatrixLookAtRH, но не смог изменить шаг/рыскание камеры, используя этот подход, поэтому я отказался от этого подхода и придумал генерировать матрицу самостоятельно.

Что решило мою проблему, так это транспонирование матрицы модели, представления и проекции с использованием XMMatrixTranspose перед передачей их в XMVector3Unproject. Итак, вместо того, чтобы иметь следующий код

  XMMATRIX projectionMatrix = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->projection);
  XMMATRIX viewMatrix       = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->view);
  XMMATRIX modelMatrix      = XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->model);

  XMVECTOR rayBegin = XMVector3Unproject(XMVectorSet(screenX, screenY, -m_boundingSphereRadius, 0.0f),
                                         0.0f,
                                         0.0f,
                                         screenWidth,
                                         screenHeight,
                                         0.0f,
                                         1.0f,
                                         projectionMatrix,
                                         viewMatrix,
                                         modelMatrix);

это должно быть

  XMMATRIX projectionMatrix = XMMatrixTranspose(XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->projection));
  XMMATRIX viewMatrix       = XMMatrixTranspose(XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->view));
  XMMATRIX modelMatrix      = XMMatrixTranspose(XMLoadFloat4x4(&m_modelViewProjectionConstantBufferData->model));

  XMVECTOR rayBegin = XMVector3Unproject(XMVectorSet(screenX, screenY, -m_boundingSphereRadius, 0.0f),
                                         0.0f,
                                         0.0f,
                                         screenWidth,
                                         screenHeight,
                                         0.0f,
                                         1.0f,
                                         projectionMatrix,
                                         viewMatrix,
                                         modelMatrix);

Мне не совсем понятно, зачем нужно транспонировать матрицы перед передачей их в метод unproject. Однако я подозреваю, что это связано с проблемой, с которой я сталкиваюсь, когда перемещаю камеру. Эта проблема уже была описана здесь, в StackOverflow, этим постинг.

Мне пока не удалось решить эту проблему. Простое транспонирование матрицы представления не решает ее. Тем не менее, моя основная проблема решена, и моя модель наконец-то кликабельна.

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

person ackh    schedule 28.06.2016

Я использовал XMMatrixLookAtRH API в функции Model::SetViewMatrix() для расчета матрицы представления и получил приличные значения векторов v и rayOrigin.

Например:

XMStoreFloat4x4(
        &m_modelViewProjectionConstantBufferData->view,
        XMMatrixLookAtRH(m_cameraPosition, XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), 
        XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f))
        );

Хотя мне не удалось визуализировать вывод на экране, я проверил результат, вычислив простые значения в консольном приложении, и векторные значения кажутся правильными. Пожалуйста, проверьте ваше приложение и подтвердите.

ПРИМЕЧАНИЕ. Чтобы использовать XMMatrixLookAtRH API вместо текущего подхода, необходимо указать параметры вектора фокальная точка и направление вверх.

person Kapil Dhaimade    schedule 28.06.2016

Я могу получить равные значения векторов v и rayOrigin, используя метод XMMatrixLookAtRH, а также вашу пользовательскую матрицу представления с помощью этого кода без необходимости операций транспонирования матрицы:

#include <directxmath.h>

using namespace DirectX;

XMVECTOR m_cameraXAxis;
XMVECTOR m_cameraYAxis;
XMVECTOR m_cameraZAxis;
XMVECTOR m_cameraPosition;

XMMATRIX gView;
XMMATRIX gView2;
XMMATRIX gProj;
XMMATRIX gModel;

void SetViewMatrix()
{
    XMVECTOR lTarget = XMVectorSet(2.0f, 2.0f, 2.0f, 1.0f);

    m_cameraPosition = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
    m_cameraZAxis = XMVector3Normalize(XMVectorSubtract(m_cameraPosition, lTarget));
    m_cameraXAxis = XMVector3Normalize(XMVector3Cross(XMVectorSet(1.0f, -1.0f, -1.0f, 0.0f), m_cameraZAxis));

    XMFLOAT3 cameraPosition;
    XMFLOAT3 cameraXAxis;
    XMFLOAT3 cameraYAxis;
    XMFLOAT3 cameraZAxis;

    XMFLOAT4X4 viewMatrix;

    // Keep camera's axes orthogonal to each other and of unit length.
    m_cameraZAxis = XMVector3Normalize(m_cameraZAxis);
    m_cameraYAxis = XMVector3Normalize(XMVector3Cross(m_cameraZAxis, m_cameraXAxis));

    // m_cameraYAxis and m_cameraZAxis are already normalized, so there is no need
    // to normalize the below cross product of the two.
    m_cameraXAxis = XMVector3Cross(m_cameraYAxis, m_cameraZAxis);

    // Fill in the view matrix entries.
    float x = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraXAxis));
    float y = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraYAxis));
    float z = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraZAxis));

    XMStoreFloat3(&cameraPosition, m_cameraPosition);
    XMStoreFloat3(&cameraXAxis, m_cameraXAxis);
    XMStoreFloat3(&cameraYAxis, m_cameraYAxis);
    XMStoreFloat3(&cameraZAxis, m_cameraZAxis);

    viewMatrix(0, 0) = cameraXAxis.x;
    viewMatrix(1, 0) = cameraXAxis.y;
    viewMatrix(2, 0) = cameraXAxis.z;
    viewMatrix(3, 0) = x;

    viewMatrix(0, 1) = cameraYAxis.x;
    viewMatrix(1, 1) = cameraYAxis.y;
    viewMatrix(2, 1) = cameraYAxis.z;
    viewMatrix(3, 1) = y;

    viewMatrix(0, 2) = cameraZAxis.x;
    viewMatrix(1, 2) = cameraZAxis.y;
    viewMatrix(2, 2) = cameraZAxis.z;
    viewMatrix(3, 2) = z;

    viewMatrix(0, 3) = 0.0f;
    viewMatrix(1, 3) = 0.0f;
    viewMatrix(2, 3) = 0.0f;
    viewMatrix(3, 3) = 1.0f;

    gView = XMLoadFloat4x4(&viewMatrix);

    gView2 = XMMatrixLookAtRH(m_cameraPosition, XMVectorSet(2.0f, 2.0f, 2.0f, 1.0f),
            XMVectorSet(1.0f, -1.0f, -1.0f, 0.0f));

    //m_modelViewProjectionConstantBufferData->view = viewMatrix;
    printf("yo");
}

void SetProjectionMatrix(float width, float height, float nearZ, float farZ)
{
    XMMATRIX orthographicProjectionMatrix = XMMatrixOrthographicRH(width, height, nearZ, farZ);

    XMFLOAT4X4 orientation = XMFLOAT4X4
        (
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
            );

    XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);

    gProj = XMMatrixTranspose( XMMatrixMultiply(orthographicProjectionMatrix, orientationMatrix));
}

void SetModelMatrix()
{
    XMFLOAT4X4 orientation = XMFLOAT4X4
        (
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
            );

    XMMATRIX orientationMatrix = XMMatrixTranspose( XMLoadFloat4x4(&orientation));

    gModel = orientationMatrix;
}

bool SelectObject(float screenX, float screenY, float screenWidth, float screenHeight)
{
    XMMATRIX projectionMatrix = gProj;
    XMMATRIX viewMatrix = gView;
    XMMATRIX modelMatrix = gModel;
    XMMATRIX viewMatrix2 = gView2;

    XMVECTOR v = XMVector3Unproject(XMVectorSet(screenX, screenY, 5.0f, 0.0f),
        0.0f,
        0.0f,
        screenWidth,
        screenHeight,
        0.0f,
        1.0f,
        projectionMatrix,
        viewMatrix,
        modelMatrix);

    XMVECTOR rayOrigin = XMVector3Unproject(XMVectorSet(screenX, screenY, 0.0f, 0.0f),
        0.0f,
        0.0f,
        screenWidth,
        screenHeight,
        0.0f,
        1.0f,
        projectionMatrix,
        viewMatrix,
        modelMatrix);

    // Code to retrieve v0, v1 and v2 is omitted
    auto diff = v - rayOrigin;
    auto diffNorm = XMVector3Normalize(diff);

    XMVECTOR v2 = XMVector3Unproject(XMVectorSet(screenX, screenY, 5.0f, 0.0f),
        0.0f,
        0.0f,
        screenWidth,
        screenHeight,
        0.0f,
        1.0f,
        projectionMatrix,
        viewMatrix2,
        modelMatrix);

    XMVECTOR rayOrigin2 = XMVector3Unproject(XMVectorSet(screenX, screenY, 0.0f, 0.0f),
        0.0f,
        0.0f,
        screenWidth,
        screenHeight,
        0.0f,
        1.0f,
        projectionMatrix,
        viewMatrix2,
        modelMatrix);

    auto diff2 = v2 - rayOrigin2;
    auto diffNorm2 = XMVector3Normalize(diff2);

    printf("hi");
    return true;
}

int main()
{
    SetViewMatrix();
    SetProjectionMatrix(1000, 1000, 0.0f, 1.0f);
    SetModelMatrix();

    SelectObject(500, 500, 1000, 1000);

    return 0;
}

Пожалуйста, проверьте ваше приложение с этим кодом и подтвердите. Вы увидите, что код такой же, как и ваш предыдущий код. Единственным дополнением являются начальные значения параметров камеры, вычисление матрицы 2-го вида в SetViewMatrix() методом XMMatrixLookAtRH и вычисление векторов с использованием обеих матриц вида в SelectObject().

Транспонировать не нужно

Мне не пришлось транспонировать какую-либо матрицу. Транспонирование не требуется для матриц Projection и Model, поскольку обе они являются диагональными матрицами, и их транспонирование даст одну и ту же матрицу. Я также не думаю, что требуется транспонирование матрицы View. Формула XMMatrixLookAtRH объясняется здесь предоставляет матрицу представления точно такую ​​же, как у вас. Кроме того, приведенный здесь пример проекта не транспонирует матрицы при проверке пересечения. Вы можете скачать и проверить образец проекта.

Возможные источники проблем

1) Инициализация: единственный код, который я не смог увидеть, это ваша инициализация параметров m_cameraZAxis, m_cameraXAxis, nearZ, farZ и т. д. Кроме того, я не использовал ваши функции вращения камеры. Как видите, я инициализировал камеру, используя для расчета векторы положения, цели и направления. Проверьте, соответствует ли ваш первоначальный расчет m_cameraZAxis моему примеру кода.

2) Внешний вид LH/RH. Убедитесь, что в коде нет случайного перепутывания левого и правого вида.

3) Убедитесь, что ваш код вращения (ChangeCameraPitch или ChangeCameraYaw) случайно не создает оси камеры, которые не ортогональны. Вы используете ось Y камеры в качестве входных данных в ChangeCameraYaw и в качестве выходных данных в ChangeCameraPitch. Но ось Y сбрасывается в SetViewMatrix векторным произведением или осями X и Z. Таким образом, более раннее значение оси Y может быть потеряно.

Удачи с вашим приложением! Сообщите, если вы найдете правильное решение и основную причину вашей проблемы.

person Kapil Dhaimade    schedule 28.06.2016
comment
@ackh, обратите внимание, что в опубликованном коде я также установил положение камеры как 1,1,1,1, то есть вне источника. Даже тогда я получаю правильные значения вектора экрана. Единственная проблема в том, что я все еще не могу визуализировать вывод, кроме проверки векторных значений в отладчике Visual Studio. Я начертил векторы с этими значениями на бумаге, и они кажутся правильными. Пожалуйста, проверьте ваше приложение с графическим интерфейсом. - person Kapil Dhaimade; 29.06.2016
comment
Большое спасибо за ваши усилия здесь. Я попробую то, что вы предложили, и снова сообщу. К сожалению, это побочный проект, и потребуется некоторое время, прежде чем я смогу к нему вернуться. - person ackh; 29.06.2016

Как уже упоминалось, проблема не была полностью решена, хотя щелчок теперь работает. Проблема с искажением модели при перемещении камеры, с которой я подозревал связанную, осталась. Что я имел в виду под «модель искажается», видно на следующем рисунке:

введите здесь описание изображения

На левом изображении показано, как выглядит модель, когда камера расположена в центре мира, то есть (0, 0, 0), а на правом изображении показано, что происходит, когда я перемещаю камеру в отрицательном направлении по оси Y. Как видно, модель расширяется внизу и уменьшается вверху, что соответствует поведению, описанному в ссылка я уже приводил выше.

Что я в конечном итоге сделал для решения обеих проблем:

  1. Транспонируйте матрицы перед передачей их в XMVector3Unproject (уже описано выше)
  2. Транспонировал мою матрицу представления, изменив код метода SetViewMatrix (код см. ниже)

Теперь метод SetViewMatrix выглядит следующим образом:

void Camera::SetViewMatrix()
{
  XMFLOAT3 cameraPosition;
  XMFLOAT3 cameraXAxis;
  XMFLOAT3 cameraYAxis;
  XMFLOAT3 cameraZAxis;

  XMFLOAT4X4 viewMatrix;

  // Keep camera's axes orthogonal to each other and of unit length.
  m_cameraZAxis = XMVector3Normalize(m_cameraZAxis);
  m_cameraYAxis = XMVector3Normalize(XMVector3Cross(m_cameraZAxis, m_cameraXAxis));

  // m_cameraYAxis and m_cameraZAxis are already normalized, so there is no need
  // to normalize the below cross product of the two.
  m_cameraXAxis = XMVector3Cross(m_cameraYAxis, m_cameraZAxis);

  // Fill in the view matrix entries.
  float x = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraXAxis));
  float y = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraYAxis));
  float z = -XMVectorGetX(XMVector3Dot(m_cameraPosition, m_cameraZAxis));

  //XMStoreFloat3(&cameraPosition, m_cameraPosition);
  XMStoreFloat3(&cameraXAxis, m_cameraXAxis);
  XMStoreFloat3(&cameraYAxis, m_cameraYAxis);
  XMStoreFloat3(&cameraZAxis, m_cameraZAxis);

  viewMatrix(0, 0) = cameraXAxis.x;
  viewMatrix(0, 1) = cameraXAxis.y;
  viewMatrix(0, 2) = cameraXAxis.z;
  viewMatrix(0, 3) = x;

  viewMatrix(1, 0) = cameraYAxis.x;
  viewMatrix(1, 1) = cameraYAxis.y;
  viewMatrix(1, 2) = cameraYAxis.z;
  viewMatrix(1, 3) = y;

  viewMatrix(2, 0) = cameraZAxis.x;
  viewMatrix(2, 1) = cameraZAxis.y;
  viewMatrix(2, 2) = cameraZAxis.z;
  viewMatrix(2, 3) = z;

  viewMatrix(3, 0) = 0.0f;
  viewMatrix(3, 1) = 0.0f;
  viewMatrix(3, 2) = 0.0f;
  viewMatrix(3, 3) = 1.0f;

  m_modelViewProjectionConstantBufferData->view = viewMatrix;
}

Поэтому я просто поменял координаты строк и столбцов. Обратите внимание, что я должен был убедиться, что мой метод ChangeCameraYaw вызывается перед моим методом ChangeCameraPitch. Это необходимо, потому что в противном случае ориентация модели не такая, как я хочу.

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

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix model;
  row_major matrix view;
  matrix projection;
};

Я наткнулся на эту идею в этом сообщении в блоге. Ключевое слово row_major влияет на то, как компилятор шейдера интерпретирует матрицу в памяти. Того же можно было бы добиться, изменив порядок векторного * матричного умножения в вершинном шейдере, т.е. используя pos = mul(view, pos); вместо pos = mul(pos, view);

Вот и все. Эти две проблемы действительно взаимосвязаны, но, используя то, что я разместил в этом вопросе, я смог решить обе проблемы, поэтому я принимаю свой собственный ответ как ответ на этот вопрос. Надеюсь, это поможет кому-то в будущем.

person ackh    schedule 07.07.2016