Написание функции LookAt - PullRequest
0 голосов
/ 04 ноября 2018

В настоящее время я пытаюсь написать функцию LookAt на C ++ с помощью Source SDK. Я провел некоторое исследование и нашел много ссылок, но многие из них касались Unity или Glm и использовали кватернионы и матрицу вращения, но мне это не нужно.

Итак, вот моя проблема:
Я на Портале 2. У меня есть Цель с координатами позиции x, y, z, и у меня есть позиция моего игрока и его вращение в градусах (рыскание, тангаж, крен). Когда я использую свою функцию с координатами цели в качестве параметров, я хочу, чтобы мой игрок смотрел на цель.
Я нашел это: Точка взгляда на точку , но она работает не очень хорошо, окончательный угол никогда не был хорошим.

Я думаю, это потому, что в Portal 2 я ссылаюсь на это изображение :
Для вращения ось рыскания соответствует координате y в игре, высотой шага является единица z (сзади игрока), а броском является единица x.

Для перевода:
Ось z изображения соответствует оси z в игре, у - это х, а у - у.

Мне довольно сложно адаптировать коды, которые я нашел в интернете, к своим потребностям.
Не могли бы вы помочь мне в этом?

Заранее спасибо.

Код, который у меня сейчас есть, такой:

float xdistance = pos.x - target.x;
float ydistance = pos.y - target.y;
float zdistance = pos.z - target.z;
float xzdistance = sqrtf(xdistance * xdistance + zdistance * zdistance);

//Final angle: 
QAngle a = { RAD2DEG((atan2f(ydistance, zdistance))), RAD2DEG(-(atan2f(xdistance, zdistance))), 0 };

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Большое спасибо за ваш ответ! Это действительно помогло мне.

Ваш пост помог мне получить более четкое представление о том, что я должен делать, чтобы эта функция работала.

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

void TasTools::AimAtPoint(float x, float y, float z)
{
    Vector target = { y, x, z };

    //The camera is 64 units higher than the player:
    Vector campos = client->GetAbsOrigin() + client->GetViewOffset();
    campos = { campos.y, campos.x, campos.z };

    // Axis in the game, need to know it to fix up:
    //              : L - R  ; F - B ;  U - D
    // Rotation Axis:   x        z        y
    // Translation  :   y        x        z

    float xdis = target.x - campos.x;
    float ydis = target.z - campos.z;
    float zdis = target.y - campos.y;
    float xzdis = sqrtf(xdis * xdis + zdis * zdis);

    QAngle angles = { RAD2DEG(-atan2f(ydis, xzdis)), RAD2DEG(-(atan2f(-xdis, zdis))), 0 };

    engine->SetAngles(angles);
}

Еще раз спасибо!

0 голосов
/ 05 ноября 2018

Полагаю, вы хотели, чтобы камера представляла собой матрицу однородного преобразования 4x4

Для правильной реализации взгляда вам нужно:

  1. положение камеры pos

    как для игрока, так что ваша позиция фиксирована и известна ...

  2. целевая позиция target

  3. направление просмотра dir

    может быть просто вычислено:

    dir = target-pos
    dir /= |dir|
    
  4. некоторое направление выравнивания (например, UP)

    это зависит от вашей игры ... для игр на местности можно использовать вектор UP (например, (0,1,0)) или нормаль к поверхности и т. Д. ... для 6 приложений на основе DOF вы можете использовать локальный вектор какого-то игрока ... Будьте внимательны, этот вектор выравнивания не должен быть параллельным dir, иначе последнее перекрестное произведение не будет работать должным образом. В таком случае вы можете выбрать другой вектор выравнивания, например, RIGHT, NORT и т. Д.

Чтобы построить матрицу трехмерного преобразования, вам нужны позиции O и 3 базисных вектора (X,Y,Z), которые являются единичными и перпендикулярными друг другу. Позиция - pos, а один из базовых векторов - dir (который зависит от того, какая ось у вас выглядит, например, перспектива, которую OpenGL использует обычно -Z). Итак, вам нужно вычислить два других базисных вектора. Давайте рассмотрим, что мы будем смотреть в направлении -Z так:

-Z =  dir
 Z = -dir

чтобы получить 2 других базисных вектора, просто используйте кросс-произведение ...

X = cross(UP,Z)
X /= |X|
Y = cross(Z,X)
Y /= |Y|

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

O = pos

Порядок операндов внутри cross будет определять знак результата, поэтому, если вы перевернули какую-либо ось, просто поменяйте местами операнды ...

Теперь просто введите O,X,Y,Z в матрицу блока 4x4. Как зависит от обозначения вашего двигателя. Поскольку камера обычно инвертируется (также зависит от обозначений), инвертируйте ее, и вы получите свою результирующую матрицу. Здесь макет OpenGL:

OpenGL matrix layout

Если вам нужны углы Эйлера, извлеките их из матрицы с помощью гониометрии ...

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