Расчет положения 3D-камеры на основе 2D-камеры

У меня есть 2D-движок с боковой прокруткой, и я хочу иметь возможность добавлять 3D-объекты. Итак, мне нужна 3D-камера. Чтобы 2D-объекты выглядели точно так же, как раньше, мне нужно вычислить положение 3D-камеры, но почему-то мои расчеты неверны: слишком большое увеличение. Ситуация:

  • Все мои 2D-объекты находятся на Z = 0.
  • Моя 2D-камера определяется как положение (X, Y) и ширина.
  • Соотношение сторон вида автоматически определяет высоту камеры.
  • Для 3D-камеры пользователь устанавливает FOVx.

Итак, я думаю, вопрос на самом деле заключается в следующем: как рассчитать положение камеры по оси Z на основе ширины и FOVx?

Я подумал, что могу просто использовать загар. Глядя на это изображение:

camera
(источник: proun-game.com)

Я подумал, что могу рассчитать камеру Z следующим образом:

cameraPos.z = width / 2 / tan(FOVx / 2)

Однако результат неверный: камера слишком сильно увеличена. Насколько далеко зависит от FOVx, который я установил, так что это даже не соответствует.

Это общий код, используемый для этого:

float cameraZ = -cameraWidth / 2 / tan(FOVx.valueRadians() / 2);
D3DXMATRIX viewMatrix;
D3DXMatrixLookAtLH(&viewMatrix,
                   &D3DXVECTOR3(cameraPos.x, cameraPos.y, cameraZ), // the eye point
                   &D3DXVECTOR3(cameraPos.x, cameraPos.y, 0),       // the camera look-at target
                   &D3DXVECTOR3(0.0f, 1.0f, 0.0f));                 // the current world's up direction

D3DXMATRIX projectionMatrix;
D3DXMatrixPerspectiveFovLH(&projectionMatrix,
                           FOVx.valueRadians() / aspectRatio,   // Field of view in the y direction, in radians
                           aspectRatio,                         // Aspect ratio, defined as view space width divided by height
                           0.01f,                               // Z-value of the near view-plane
                           100.0f);                             // Z-value of the far view-plane

DXMatrix multiplied = worldMatrix * viewMatrix * projectionMatrix;
D3DXMatrixTranspose(&totalMatrixForCurrentObject, &multiplied);

Что я здесь делаю неправильно?

(Я нашел этот похожий вопрос и позаимствовал их изображение, но, к сожалению, ответ там слишком общий, чтобы быть полезным.)


person Oogst    schedule 31.12.2016    source источник


Ответы (2)


В документации для D3DXMatrixLookAtLH сказано, что FOV указывается в направлении y, поэтому вы, вероятно, захотите выполнить расчет на основе высоты, а не ширины.

https://msdn.microsoft.com/en-us/library/windows/desktop/bb205350(v=vs.85).aspx

person Frank    schedule 01.01.2017
comment
Спасибо за ответ! :) Как вы можете видеть в опубликованном мной коде DirectX, я уже компенсирую это, разделив соотношение сторон: FOVx.valueRadians() / aspectRatio. Вы упустили это из виду или имеете в виду, что я неправильно перехожу от FOVx к FOVy? - person Oogst; 02.01.2017

Тем временем я, наконец, решил свою проблему. :) Ошибка оказалась в том, что переход от fovX к fovY — это не просто деление на соотношение сторон. Итак, эта строка была проблемой:

fovX.valueRadians() / aspectRatio

Переход от fovX к fovY может быть выполнен несколькими способами в зависимости от того, какие параметры вы используете. Вот один из способов сделать это:

fovY = 2 * atan((cameraHeight / 2) / ((cameraWidth / 2) / tan(fovX / 2)))

Положение камеры по оси Z, которое я рассчитывал, уже было правильным! :)

person Oogst    schedule 22.01.2017