Первое, что я хотел бы сделать, чтобы упростить задачу, - это преобразовать координатное пространство, чтобы камера находилась в точке (0, 0, 0) и указывала прямо на одну из осей (так что направление называется (0, 0, 1)). Перевод таким образом, что камера находится в (0, 0, 0), довольно тривиальна, поэтому я не буду вдаваться в это. Вращение так, что направление камеры (0, 0, 1) немного сложнее ...
Один из способов сделать это, чтобы построить полный ортонормированный базис камеры, затем придерживаться этого в матрице вращения и применять Это. «Ортонормированный базис» камеры - это фантастический способ сказать три вектора, которые указывают вперед, вверх и прямо от камеры. Все они должны находиться под углом 90 градусов друг к другу (это то, что означает бит орто), и все они должны быть длиной 1 (что означает нормальный бит).
Вы можете получить эти векторы с крошечным обманом: поперечное произведение двух векторов перпендикулярно (на 90 градусов) для обоих.
Чтобы получить обратный вектор, мы можем просто перекрещивать вектор направления камеры с (0, 1, 0) (вектор, направленный вверх). Вам нужно будет нормализовать вектор, который вы выходите из кросс-продукта.
Чтобы получить векторный указатель камеры, мы можем перекрещивать вектор направления камеры с вектором, который мы только что вычислили. Предполагая, что оба входных вектора нормированы, это не требует нормализации.
Теперь у нас есть ортонормированный базис камеры. Если мы вставим эти векторы в строки матрицы 3x3, мы получим матрицу поворота, которая преобразует наше координатное пространство, чтобы камера указывала прямо на одну из осей (что зависит от того, в каком порядке вы вставляете векторы).
Теперь довольно легко вычислить азимут и возвышение объекта.
Чтобы получить азимут, просто сделайте atan2
по координатам x/z объекта.
Чтобы получить возвышение, проект объекта координат на х/г плоскости (только установить координату у 0), а затем сделать:
acos(dot(normalise(object coordinates), normalise(projected coordinates)))
Это всегда будет давать положительный угол - вы, вероятно, хочу, чтобы свести на нет, если у объекта координаты меньше 0.
код для все это будет выглядеть примерно так:
fwd = vec3(camDirectionX, camDirectionY, camDirectionZ)
cam = vec3(camX, camY, camZ)
obj = vec3(objectX, objectY, objectZ)
# if fwd is already normalised you can skip this
fwd = normalise(fwd)
# translate so the camera is at (0, 0, 0)
obj -= cam
# calculate the orthonormal basis of the camera
right = normalise(cross(fwd, (0, 1, 0)))
up = cross(right, fwd)
# rotate so the camera is pointing straight down the z axis
# (this is essentially a matrix multiplication)
obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))
azimuth = atan2(obj.x, obj.z)
proj = vec3(obj.x, 0, obj.z)
elevation = acos(dot(normalise(obj), normalise(proj)))
if obj.y < 0:
elevation = -elevation
Одна вещи, чтобы следить за то, тх t перекрестное произведение вашего исходного вектора камеры с (0, 1, 0) вернет вектор нулевой длины, когда ваша камера обращена вверх или вниз.Чтобы полностью определить ориентацию камеры, я предположил, что она всегда «прямая», но это ничего не значит, когда она направлена вверх или вниз - вам нужно другое правило.
большое спасибо за ваш ответ. У меня есть некоторые трудности для его реализации. Я получил первую часть об упрощении путем перевода и поворота. Но после этого я потерялся. Действительно, «теперь у нас есть ортонормированный базис» означает, что я должен использовать его для ссылки объекта? Как мне это сделать? потому что x/z по азимуту вычисляет x, z в новый базовый, правый ...? – gluon
@gluon Я обновил ответ с помощью некоторого псевдокода. Надеюсь, это сделает вещи более ясными. – dave
Я думаю, что ключ ... кватернион. Наверное, у меня должен был бы быть общий новый подход к использованию кватернионов. – gluon