Определить угол между положением камеры и мировой точкой в ​​3D-движке - PullRequest
0 голосов
/ 12 марта 2020

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

Моя линейная алгебра немного заржавела, но, учитывая направление вперед, вверх и вправо камеры, например:

camForward = [0 0 1];
camUp = [0 1 0];
camRight = [1 0 0];

И камера положение и мировая точка, например:

camPosition = [1 2 3];
worldPoint = [5 6 4];

Требуемые углы должны быть определены, сначала беря разницу в положениях:

delta = worldPoint-camPosition;

Затем проецируя ее на оси камеры используя точечные произведения:

deltaHorizontal = dot(delta,camRight);
deltaVertical = dot(delta,camUp);
deltaDepth = dot(delta,camForward);

И, наконец, вычисляем углы как:

angleHorizontal = atan(deltaHorizontal/deltaDepth);
angleVertical = atan(deltaVertical/deltaDepth);

В этом примере это дает, что оба угла становятся ~ 76 °, что кажется разумным; изменение положения и осей также, по-видимому, дает приемлемые результаты.

Таким образом, если я не получаю ожидаемые углы, это должно быть связано с тем, что я использую либо неправильное положение, и / или оси камеры. Стоит отметить, что 3D-движок использует OpenGL и GLM.

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

glm::vec3 worldPoint = glm::unProject( glm::vec3(windowX, windowY, windowZ), viewMatrix, projectionMatrix, glm::vec4(0,0,windowWidth,windowHeight));

glm::vec3 delta = glm::vec3(worldPoint.x, worldPoint.y, worldPoint.z);

float horizontalDistance = glm::dot(delta, cameraData->right);
float verticalDistance = glm::dot(delta, cameraData->up);
float depthDistance = glm::dot(delta, cameraData->forward);

float horizontalAngle = glm::atan(horizontalDistance/depthDistance)
float verticalAngle = glm::atan(verticalDistance/depthDistance)

Каждый кадр forward, up и right считывается из матрицы вида, viewMatrix, которая, в свою очередь, производится путем преобразования кватерниона Q, который удерживает вращение камеры, управляемое мышью:

void updateView(CameraData * cameraData, MouseData * mouseData, MouseParameters * mouseParameters){

    float deltaX = mouseData->currentX - mouseData->lastX;
    float deltaY = mouseData->currentY - mouseData->lastY;

    mouseData->lastX = mouseData->currentX;
    mouseData->lastY = mouseData->currentY;

    float pitch = mouseParameters->sensitivityY * deltaY;
    float yaw   = mouseParameters->sensitivityX * deltaX;

    glm::quat pitch_Q = glm::quat(glm::vec3(pitch, 0.0f, 0.0f));
    glm::quat yaw_Q = glm::quat(glm::vec3(0.0f, yaw, 0.0f)); 

    cameraData->Q = pitch_Q * cameraData->Q * yaw_Q;
    cameraData->Q = glm::normalize(cameraData->Q);

    glm::mat4 rotation = glm::toMat4(cameraData->Q); 

    glm::mat4 translation = glm::mat4(1.0f);
    translation = glm::translate(translation, -(cameraData->position));

    cameraData->viewMatrix = rotation * translation;

    cameraData->forward = (cameraData->viewMatrix)[2];
    cameraData->up = (cameraData->viewMatrix)[1];
    cameraData->right = (cameraData->viewMatrix)[0];
 }

Однако что-то идет не так, и правильные углы, по-видимому, создаются только при взгляде вдоль, или перпендикулярно мировой оси z ([0 0 1]). Где я ошибаюсь? Любая помощь будет наиболее ценится!

Спасибо

...