Как постепенно двигаться в трехмерном мире, используя glRotatef () и glTranslatef () - PullRequest
2 голосов
/ 15 ноября 2010

У меня есть несколько 3D-моделей, которые я отображаю в OpenGL в 3D-пространстве, и у меня возникают некоторые головные боли при перемещении 'персонажа' (то есть камеры ) с вращения и перевод в этом мире.

Я получаю входные данные (то есть координаты, куда перемещать / поворачивать оси) из какого-либо внешнего события (изображение пользовательского ввода или некоторые данные с устройства GPS + компас), и тип события вращение ИЛИ перевод .

Я написал этот метод для управления этими событиями:

- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{

    [super startDrawingFrame];
    if (degrees != 0)
    {
        glRotatef(degrees, 0, 0, 1);
    }

    if (translatedLat != 0)
    {
        glTranslatef(translatedLat, -translatedLong, 0);
    }

   [self redrawView];
}

Тогда в redrawView Я на самом деле рисую сцену и мои модели. Это что-то вроде:

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

NSInteger nModels = [models count];

for (NSInteger i = 0; i < nModels; i++) 
{
    MD2Object * mdobj = [models objectAtIndex:i];
    glPushMatrix();
    double * deltas = calloc(sizeof(double),2);

    deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
    deltas[1] = currentCoords[1] - mdobj.modelPosition[1];

    glTranslatef(deltas[0], -deltas[1], 0);

    free(deltas);
    [mdobj setupForRenderGL];
    [mdobj renderGL];   
    [mdobj cleanupAfterRenderGL];
    glPopMatrix();

}
[super drawView];

Проблема в том, что при трансляции события поворота вызываются одно за другим: например, когда я вращаюсь постепенно для некоторых итераций (все еще вокруг начала координат), я перевожу и, наконец, снова вращаюсь, но кажется, что последнее вращение происходит не вокруг текущей (переведенной) позиции, а вокруг старой (старой). Я хорошо знаю, что это происходит, когда порядок преобразований переворачивается, но я полагал, что после рисования новый центр мира был дан переведенной системой.

Что мне не хватает? Как я могу это исправить? (любая ссылка на OpenGL тоже будет оценена)

Ответы [ 2 ]

1 голос
/ 15 ноября 2010

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

Псевдокод:

someEvent(lat, long, deg)
{
  currentLat += lat;
  currentLong += long;
  currentDeg += deg;
}

redraw()
{
  glClear()
  glRotatef(currentDeg, 0, 0, 1);
  glTranslatef(currentLat, -currentLong, 0);
  ... // draw stuff
}
1 голос
/ 15 ноября 2010

Похоже, у вас есть несколько вещей, которые происходят здесь:

Во-первых, вам нужно знать, что вокруг источника происходят повороты. Поэтому, когда вы переводите, а затем вращаетесь, вы вращаетесь не вокруг того, что вы считаете источником, а с новым источником, который является T -1 0 (источник, преобразованный инверсией вашего перевода).

Во-вторых, вы делаете вещи немного сложнее, чем вам действительно нужно. Вместо этого вы можете использовать gluLookAt . По сути, вы задаете ему положение в вашей сцене и точку в вашей сцене, на которую нужно смотреть, и вектор «вверх», и это правильно настроит сцену. Чтобы правильно использовать его, проследите за тем, где находится ваша камера, назовите этот вектор p , а вектор n (для обычного ... указывает направление, которое вы смотрите) и u (ваш восходящий вектор). Для более сложных функций будет проще, если n и u являются ортонормированными векторами (т.е. они ортогональны друг другу и имеют единичную длину). Если вы сделаете это, вы можете вычислить r = n x u (ваш «правый» вектор), который будет нормальным вектором, ортогональным к другому два. Затем вы «смотрите» на p + n и предоставляете u в качестве вектора повышения.

В идеале ваши n , u и r имеют некоторую каноническую форму, например:

<b>n</b> = <0, 0, 1>
<b>u</b> = <0, 1, 0>
<b>r</b> = <1, 0, 0>

Затем вы постепенно накапливаете свои вращения и применяете их к каноническому для ваших векторов ориентации. Вы можете использовать Euler Rotations или Quaternion Rotations , чтобы накапливать ваши вращения (я очень ценю кватернионный подход по множеству причин ). 1049 *

...