В моей программе есть функция, которая вращает точку (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;
}
Что почти делает код:
Есть две проблемы:
Поэтому в этом случае использование матриц и векторной математики поможет:
b = p - m
b = RotationMatrixAroundX(wn_x) * b
b = RotationMatrixAroundY(wn_y) * b
n = m + b
Попробуйте использовать векторную математику. решить, в каком порядке вы вращаетесь, сначала вдоль 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 угла. Но вы правы — для трансформации точек достаточно 2 углов. Подробности уточняйте Википедия …
Но когда вы работаете с OpenGL, вы действительно должны использовать функции OpenGL, такие как glRotatef
, Эти функции будут рассчитываться на GPU, а не на CPU, как ваша функция. Документ является Вот.
Как и многие другие, вы должны использовать glRotatef, чтобы повернуть его для рендеринга. Для обработки столкновений вы можете получить его позицию в мировом пространстве, умножив вектор положения на матрицу OpenGL ModelView на вершине стека в точке его рендеринга. Получите эту матрицу с помощью glGetFloatv, а затем умножьте ее на свою собственную функцию умножения векторной матрицы или используйте одну из многих, которые вы можете легко получить в Интернете.
Но это будет боль! Вместо этого изучите использование буфера обратной связи GL. Этот буфер будет просто хранить точки, в которых был бы нарисован примитив, вместо того, чтобы фактически рисовать примитив, и тогда вы сможете получить к ним доступ оттуда.
это хорошая отправная точка.