Повернуть 3D-точку вокруг другой

В моей программе есть функция, которая вращает точку (x_p, y_p, z_p) вокруг другой точки (x_m, y_m, z_m) на углы w_nx & w_ny. Новые координаты хранятся в глобальных переменных x_n, y_n и z_n. Вращение вокруг оси y (таким образом, изменяя значение w_nx — так, чтобы значения y не были повреждены), работает правильно, но как только я делаю вращение вокруг оси x или z (изменяя значение w_ny) координаты больше не точны. Я прокомментировал строку, в которой, я думаю, моя вина, но я не могу понять, что не так с этим кодом.

Может кто-нибудь мне помочь?

void rotate(float x_m, float y_m, float z_m, float x_p, float y_p, float z_p, float w_nx ,float w_ny)
{
float z_b = z_p - z_m;
float x_b = x_p - x_m;
float y_b = y_p - y_m;
float length_ = sqrt((z_b*z_b)+(x_b*x_b)+(y_b*y_b));
float w_bx = asin(z_b/sqrt((x_b*x_b)+(z_b*z_b))) + w_nx;
float w_by = asin(x_b/sqrt((x_b*x_b)+(y_b*y_b))) + w_ny; //<- there must be that fault
x_n = cos(w_bx)*sin(w_by)*length_+x_m;
z_n = sin(w_bx)*sin(w_by)*length_+z_m;
y_n = cos(w_by)*length_+y_m;
}

0

Решение

Что почти делает код:

  • вычислить разность векторов
  • преобразовать вектор в сферические координаты
  • добавьте w_nx и wn_y к углу наклона и азимута (см. ссылку для терминологии)
  • преобразовать измененные сферические координаты обратно в декартовы

Есть две проблемы:

  • преобразование неверно, вычисление выполняется для двух векторов наклона (один по оси x, другой по оси y)
  • даже если вычисления были правильными, преобразование в сферические координаты не совпадает с вращением вокруг двух осей

Поэтому в этом случае использование матриц и векторной математики поможет:

b = p - m
b = RotationMatrixAroundX(wn_x) * b
b = RotationMatrixAroundY(wn_y) * b
n = m + b

основные матрицы вращения.

4

Другие решения

Попробуйте использовать векторную математику. решить, в каком порядке вы вращаетесь, сначала вдоль x, а затем, возможно, вдоль y.

Если вы вращаетесь вдоль z, [z ‘= z]

x' = x*cos a - y*sin a;
y' = x*sin a + y*cos a;

То же самое повторяется для оси y: [y » = y ‘]

x'' = x'*cos b - z' * sin b;
z'' = x'*sin b + z' * cos b;

Снова вращаясь вдоль оси x: [x » ‘= x’ ‘]

y''' = y'' * cos c - z'' * sin c
z''' = y'' * sin c + z'' * cos c

И, наконец, вопрос о вращении вокруг какой-то определенной «точки»:

Сначала вычтите точку из координат, затем примените повороты и, наконец, добавьте точку обратно к результату.

Проблема, насколько я вижу, близка к «карданной блокировке». Угол w_ny можно измерить не относительно фиксированной системы координат xyz, а относительно системы координат, которая поворачивается с применением угла w_nx.

Как заметил kakTuZ, ваш код конвертирует точку в сферические координаты. В этом нет ничего плохого — с долготой и широтой можно добраться до всех мест на Земле. И если кто-то не заботится о наклоне экваториальной плоскости Земли относительно ее траектории вокруг Солнца, это нормально для меня.

Результат не вращается следующей осью отсчета вдоль первой w_ny в том, что две точки, которые находятся в 1 км часть друг от друга на экваторе, ближе друг к другу у полюсов и на широте 90 градусов, они соприкасаются. Хотя очевидная цель состоит в том, чтобы держать их на расстоянии 1 км друг от друга, где бы они ни вращались.

3

если вы хотите преобразовать системы координат, а не только точки, вам нужно 3 угла. Но вы правы — для трансформации точек достаточно 2 углов. Подробности уточняйте Википедия

Но когда вы работаете с OpenGL, вы действительно должны использовать функции OpenGL, такие как glRotatef, Эти функции будут рассчитываться на GPU, а не на CPU, как ваша функция. Документ является Вот.

0

Как и многие другие, вы должны использовать glRotatef, чтобы повернуть его для рендеринга. Для обработки столкновений вы можете получить его позицию в мировом пространстве, умножив вектор положения на матрицу OpenGL ModelView на вершине стека в точке его рендеринга. Получите эту матрицу с помощью glGetFloatv, а затем умножьте ее на свою собственную функцию умножения векторной матрицы или используйте одну из многих, которые вы можете легко получить в Интернете.

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

0
По вопросам рекламы [email protected]