Смущен градусами и движением / поворотом камеры OpenGL / GLUT - PullRequest
2 голосов
/ 06 марта 2011

ВНИМАНИЕ: я отредактировал приведенный ниже вопрос, который больше относится к моей реальной проблеме, чем текст, приведенный ниже, вы можете пропустить его, если не хотите, но я оставлю его здесь по историческим причинам.

Чтобы понять, правильно ли я понял, значение float в C совпадает со значением в радианах, верно? Я имею в виду, 360º = 6,28318531 радиан, и я только что заметил в своем приложении OpenGL, что полный оборот идет от 0,0 до 6,28, что, кажется, правильно складывается. Я просто хочу убедиться, что я правильно понял.

Я использую float (назовем это anglePitch) от 0,0 до 360,0 (легче читать в градусах и избегает приведения int к float все время) и весь код, который я вижу в сети используется какой-то макрос DEG2RAD(), который определяется как DEG2RAD 3.141593f / 180. В конце концов это будет примерно так:

anglePitch += direction * 1; // direction will be 1 or -1
refY = tan(anglePitch * DEG2RAD);

Это действительно делает полный оборот, но этот полный оборот будет, когда anglePitch = 180 и anglePitch * DEG2RAD = 3.14, но полный оборот должен быть 360 | 6.28. Если я изменю макрос на любой из следующих:

#define DEG2RAD 3.141593f / 360
#define DEG2RAD 3.141593f / 2 / 180

Работает как положено, полный поворот произойдет, когда anglePitch = 360.

Что мне здесь не хватает и что мне следует использовать для правильного преобразования углов в радианы / поплавки?

ВАЖНОЕ РЕДАКТИРОВАНИЕ (РЕАЛЬНЫЙ ВОПРОС):
Теперь я понимаю код, который я вижу повсюду в Интернете о DEG2RAD, я просто слишком туп в математике (да, я знаю, это важно при работе с такими вещами). Поэтому я перефразирую свой вопрос:

Я добавил это в свой код:

#define PI         3.141592654f
#define DEG2RAD(d) (d * PI / 180)

Теперь, когда работаем с углами тангажа / зевания в градусах, которые равны floats, еще раз, чтобы избежать приведения постоянно, я просто использую макрос DEG2RAD, и значение градуса будет правильно преобразовано в радианы. Эти значения будут переданы в функции sin / cos / tan и вернут правильные значения, которые будут использоваться в камере GLUT.

Теперь реальный вопрос, где я был действительно смущен прежде, но не мог объяснить себя лучше:

angleYaw += direction * ROTATE_SPEED;
refX = sin(DEG2RAD(angleYaw));
refZ = -cos(DEG2RAD(angleYaw));

Этот код будет выполнен, когда я нажму клавиши ВЛЕВО / ВПРАВО, и камера будет соответственно поворачиваться по оси Y. Полный оборот идет от 0º до 360º.

anglePitch += direction * ROTATE_SPEED;
refY = tan(DEG2RAD(anglePitch));

Это аналогичный код, и он будет выполнен, когда я нажму клавиши ВВЕРХ / ВНИЗ, и камера будет вращаться по оси X. Но в этой ситуации полный поворот идет от 0 ° до 180 °, и это меня действительно смущает. Я уверен, что это как-то связано с функцией тангенса, но я не могу разобраться с этим.

Есть ли способ, которым я мог бы использовать sin / cos (как я делаю в коде зевания), чтобы добиться того же вращения? Какой правильный путь, самый простой код, который я могу добавить / исправить, и что имеет больше смысла для создания полного поворота высоты тона от 0º до 360º?

Ответы [ 3 ]

3 голосов
/ 06 марта 2011

360 ° = 2 * Pi, Pi = 3.141593…

Радианы определяются длиной дуги угла по окружности радиуса 1. Длина окружности составляет 2 * r * Pi, поэтомуодин полный оборот единичного круга имеет длину дуги 2 * Pi = 6,28…

Мера углов в градусах основана на том факте, что, выровняв 6 равносторонних треугольников, вы проходите полный оборот.Таким образом, у нас есть 6 треугольников, каждый из которых составляет 6-й ход, поэтому старые вавилоняне делили круг на части 1 / (6 * 6) = 1/36, и для дальнейшего уточнения он был разделен на 10. Поэтомумы закончили с 360 ° в полном круге.Это число выбирается произвольно.

Так что, если есть 2 * Пи / 360 °, это дает Пи / 180 ° = 3,141593… / 180 °, что является коэффициентом пересчета из градусов в радианы.Взаимное, 180 ° / Pi = 180 / 3.141593…

Почему на земле старая функция OpenGL glRotate и GLU в зависимости от ГЛП использовали градусы вместо радианов, которые я не могу понять.С математической точки зрения только радианы имеют смысл.Что, я думаю, наиболее красиво продемонстрировано уравнением Эйлера

e^(i*Pi) - 1 = 0

Там есть все важные числа математики в одном уравнении.Какое отношение это имеет к углам?Ну:

e^(i*alpha) = cos(alpha) + i * sin(alpha), alpha is in radians!

РЕДАКТИРОВАТЬ, в связи с измененным вопросом:

Ваши углы, будучи плавающими, в порядке.Почему вы даже думаете, что degress - целые числа, я не могу понять.Обычно вам не нужно определять PI самостоятельно, он предопределен в math.h, обычно называемом M_PI, M_2PI и M_PI2 для Pi, 2 * Pi и Pi / 2.Вы также должны изменить свой макрос, способ, которым он написан сейчас, может создавать странные эффекты.

#define DEG2RAD(d) ( (d) * M_PI/180. )

GLUT не имеет камеры вообще.GLUT - довольно тупой фреймворк OpenGL, который я рекомендую не использовать.Вы, вероятно, ссылаетесь на gluLookAt .

Эти препятствия на пути, давайте посмотрим, что вы там делаете.Помните, что тригонометрические функции работают на единичной окружности.Пусть угол 0 направлен вправо, а углы увеличиваются против часовой стрелки.Тогда sin (a) определяется как количество правых, а cos (a) и количество форвардов для достижения точки под углом a на единичной окружности.Это то, что присваивается refX и refZ.

refY однако не имеет смысла записываться таким образом. tan = sin / cos , поэтому, когда мы приближаемся к n * pi / 2 (т.е. 90 °), оно расходится до +/- бесконечности.По крайней мере, это объясняет ваш циклический диапазон пи / 180 °, потому что это период tan .

Сначала я думал, что tan , возможно, использовался для нормализациивектор направления, но тоже не имеет смысла.Коэффициент был бы 1./sqrt(sin²(Pitch) + 1) Я дважды проверил: использование tan делает правильную вещь.

EDIT2: Iне вижу, где ваша проблема: Угол наклона составляет от -90 ° до + 90 °, что имеет смысл.Получите себе глобус (земли): координаты восток-запад (долгота) идут от -180 ° до + 180 °, координата юг-север (широта) идет от -90 ° до + 90 °.Подумайте об этом: любой больший диапазон координат вызовет неоднозначность.

Единственное хорошее предложение, которое я предлагаю вам, это: возьмите какой-нибудь учебник по математике и сосредоточитесь на сферических координатах! Извините, что говорю вамсюда.Все, что у вас есть, работает отлично, вам просто нужно понимать геометрию сперики.

Вы используете термины Yaw и Pitch.Они обычно используются в углах Эйлера.Теперь, к сожалению, углы Эйлера, которые вначале неотразимы, позже вызывают серьезные проблемы (например, блокировка карданного подвеса).Вы не должны использовать их вообще.Это также может быть хорошей идеей, если вы использовали некоторые карандаши / палки / что угодно, чтобы разложить вращения, которые вы намереваетесь своими руками, чтобы понять их механику.


И, между прочим:целые степениПросто прыгайте на http://maps.google.com, чтобы увидеть их в действии (просто выберите место и позвольте http://maps.google.com дать вам ссылку на него).

3 голосов
/ 06 марта 2011

'float' - это тип, например int или double. радианы и градусы - это единицы измерения, которые могут быть представлены с любой точностью, которую вы хотите. то есть, нет причины, по которой у вас не может быть 22,5 градуса, и сохраняйте это значение в плавающей запятой.

полное вращение в радианах составляет 2 * пи, около 6,283, тогда как полное вращение в градусах составляет 360. Вы можете конвертировать между ними, разделив полный круг начальной единицы, а затем умножив ее на полный круг желаемой единицы.

например, чтобы получить от 90 градусов до радианов, сначала разделите градусы. 90 за 360 - это 0,25 (обратите внимание, что это значение указано в «оборотах»). Теперь умножьте это 0,25 на 6,283, чтобы получить 1,571 радиан.

продолжение

причина, по которой вы видите, что ваш цикл основного тона в два раза быстрее, чем должен, именно потому, что вы используете tan (pitch) для вычисления компонента Y. То, что вы должны иметь, это то, что компонент Y зависит от греха (высоты тона). то есть попробуйте изменить

refY = tan(DEG2RAD(anglePitch));

до

refY = sin(DEG2RAD(anglePitch));

техническая деталь: все числа, входящие в матрицу вида, должны быть в диапазоне от -1 до +1, и если вы должны были проверить значения, которые вы вводите для refY, и запустить свой шаг за пределами - От 45 до +45 градусов, вы увидите проблему; tan () убегает до бесконечности при +/- 90 градусов.

также обратите внимание, что приведение значения от int к значению с плавающей точкой ни в каком смысле не преобразует градусы в радианы. приведение просто дает вам ближайшее эквивалентное значение в новом типе хранилища. например, если вы приведете целое число 22 к числу с плавающей запятой, вы получите 22.0f, тогда как если вы приведете 33.3333f к типу int, у вас останется 33. При работе с углами вы действительно должны просто придерживаться плавающей запятой, если вы не ограничены работой со встроенным процессором или чем-то еще. это особенно важно в радианах, где приращения целых чисел представляют скачки (около) 57,3 градусов.

1 голос
/ 06 марта 2011

Предполагая, что ваши ref-компоненты предназначены для использования в качестве вектора обзора, я думаю, что вам нужно

refY = sin(DEG2RAD(anglePitch)); 
XZfactor = cos(DEG2RAD(anglePitch));
refX = XZfactor*sin(DEG2RAD(angleYaw));
refZ = -XZfactor*cos(DEG2RAD(angleYaw));
...