Open GL Android 3D проблема вращения объектов - PullRequest
0 голосов
/ 23 февраля 2012

У меня проблемы с вращением моих 3D объектов в Open GL. Я начинаю каждый кадр рисования с загрузки идентификатора (glLoadIdentity ()), а затем нажимаю и вставляю в стек в соответствии с тем, что мне нужно (для камеры и т. Д.). Затем я хочу, чтобы трехмерные объекты могли вращаться, наклоняться и рыскать, а затем правильно отображать их.

Вот в чем подвох ... Я хочу иметь возможность делать дополнительные вращения, как если бы я летал на самолете. Таким образом, каждый раз, когда нажимается кнопка «вверх», объект вращается вокруг своей оси X. Но затем, если объект наклонен вниз и выбирает отклонение от курса, вращение должно быть вокруг вектора вверх объекта, а не оси Y.

Я пытался сделать следующее:

glRotatef (pitchTotal, 1,0,0);
glRotatef (yawTotal, 0,1,0);
glRotate (rollTotal, 0,0,1);

и те, кажется, не работают. (Помня, что векторы вычисляются правильно)
Я тоже пробовал ...

glRotatef (pitchTotal, 1,0,0);
glRotatef (yawTotal, 0,1,0);
glRotate (rollTotal, 0,0,1);

и я все еще получаю странные повороты.

Короче говоря ... Как правильно повернуть трехмерный объект в Open GL, используя вид объекта, вектор вправо и вверх?

Ответы [ 3 ]

0 голосов
/ 23 февраля 2012

Накопительные вращения будут страдать от блокировки карданного подвеса.Посмотрите на это так: предположим, вы находитесь в самолете, летите ровно.Вы применяете поворот на 90 градусов против часовой стрелки.Затем вы применяете поворот на 90 градусов по часовой стрелке.Затем вы применяете поворот на 90 градусов по часовой стрелке.

Теперь ваша плоскость направлена ​​прямо вниз - общий эффект составляет шаг 90 градусов по часовой стрелке.Но если вы просто попытаетесь сложить различные повороты, то в итоге вы получите крен в 90 градусов, и никакого шага вообще не будет, потому что вы нигде не применили шаг к плоскости.

Попытка сохранить и обновитьвращение как три отдельных угла не работает.

Наиболее часто цитируемые решения - использовать кватернион или сохранять ориентацию объекта непосредственно в виде матрицы.Матричное решение легче построить, потому что вы можете создать его с помощью встроенных матричных стеков OpenGL.Большинству людей кажется, что матрицы проще для понимания, чем кватернионы.

Итак, если вы хотите перейти к матрице, ваш прототип может сделать что-то вроде: (пожалуйста, простите мне отсутствие приличных знаний Java; я собираюсь написатьC по существу):

GLfloat myOrientation[16];

// to draw the object:
glMultMatrixf(myOrientation);
/* drawing here */

// to apply roll, assuming the modelview stack is active:
glPushMatrix();                    // backup what's already on the stack
    glLoadIdentity();              // start with the identity
    glRotatef(angle, 0, 0, 1);
    glMultMatrixf(myOrientation);  // premultiply the current orientation by the roll

    // update our record of orientation
    glGetFloatv(GL_MODELVIEW_MATRIX, myOrientation);
glPopMatrix();

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

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

0 голосов
/ 29 февраля 2012

Спасибо за ответы. Первый ответ указал мне правильное направление, второй ответ тоже немного помог, но в конечном итоге он сводился к комбинации обоих. Первоначально ваш 3D-объект должен иметь переменную-член размером с массив с плавающей запятой 16. [0-15]. Затем вы должны инициализировать его в матрицу идентичности. Тогда методы-члены вашего трехмерного объекта, такие как "yawObject (float amount)", просто знают, что вы поворачиваете объект с "точки зрения объектов", а не с мира, что позволило бы инкрементное вращение. Внутри метода yawObject (или pitch, roll ojbect) вам нужно вызвать Matrix.rotateM (myfloatarray, 0, angle, 0,1,0). Это будет хранить новую матрицу вращения (как описано в первом ответе). Затем, когда вы собираетесь рисовать свой объект, вы можете умножить матрицу модели на матрицу myfloatarray, используя gl.glMultMatrix.

Удачи, и дайте мне знать, если вам нужно больше информации, чем это.

0 голосов
/ 23 февраля 2012

Вам нужно сделать вращение вокруг (вокруг Y) до того, как совершите шаг. В противном случае поле будет отключено.

например. у вас 45 градусов вниз и 180 градусов рыскания. Делая шаг сначала, а затем вращая рыскание вокруг вектора Y самолета, самолет в конечном итоге будет направлен вверх и назад, несмотря на то, что угол наклона вниз. Выполнив сначала рыскание, плоскость направлена ​​назад, а затем шаг вокруг вектора X плоскости сделает его правильно направленным вниз.

Та же логика применяется к броску, который должен применяться последним.

Итак, ваш код должен быть:

glRotatef(yawTotal, 0,1,0);
glRotatef(pitchTotal, 1,0,0);
glRotatef(rollTotal, 0,0,1);
...