2-мерный glRotatef()

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

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmt, 1, 0, 0 );

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

Что ж, я частично разобрался, но теперь у меня новая проблема (как сложить два вращения?).

МОЕ РЕШЕНИЕ:

Допустим, вы хотите повернуть куб влево на 90, а затем вниз на 90. Попробуйте сделать так:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 1, 0, 0 );

Это не работает. Вторая функция ведет себя странно, потому что первая функция поменяла местами оси X и Z. Итак, вы попробуйте это:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 0, 0, 1 );

Теперь у вас есть желаемый результат, но если вы измените величину поворота по оси Y в первой функции на 180, 45 или что-то еще, снова произойдет сбой. Желаемый вектор поворота зависит от величины поворота Y от первой функции. Желаемый результат достигается при этом:

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmnt, cos(yAmt), 0, sin(yAmt) );

А что, если вы хотите сначала повернуть вверх и вниз, а затем слева направо? Это последнее решение не работает, потому что, во-первых, функции расположены в неправильном порядке, а во-вторых, ось Y также зависит от поворота по оси X. Вы должны учитывать это, И вы должны объединить две функции, в результате чего:

glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

Где xFactor и yFactor складываются в желаемый вектор вращения (1,0 для вверх и вниз, 0,1 для левого и правого, sqrt(.5), sqrt(.5) для диагонального вращения).

МОЯ ПРОБЛЕМА:

Проблема возникает, когда пользователь заканчивает одно вращение и начинает новое. Вы должны помнить и «воспроизводить» предыдущее вращение, иначе вы получите нежелательный «скачок» обратно к 0 вращению. Один новый поворот — это нормально, я могу реализовать touchesEnded, чтобы запомнить параметры glRotatef, а затем подключить их к новому повороту следующим образом:

glRotatef( amt_old, x_old, y_old, z_old );
glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

Но во втором новом вращении у меня теперь есть два вращения, чтобы «переиграть». Я не могу понять, какие значения присвоить amt_old, x_old, y_old и z_old. К чему это сводится, так это... как суммировать два вращения glRotatef?


person user617123    schedule 11.04.2011    source источник


Ответы (2)


xAmt и yAmt в пикселях? Является ли ввод glRotatef в градусах (EDIT: я имел в виду радианы, конечно)? Если да, умножьте на небольшое число; попробуйте (float)(M_PI/180) для одного пикселя на градус.

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


EDIT: Возможно, вам нужны glGetMatrix() и glLoadMatrix().

person tc.    schedule 12.04.2011
comment
На самом деле для меня хорошо работает соотношение пикселя к градусу 1:1. Во всяком случае, я добился прогресса. Смотрите обновленный вопрос. - person user617123; 12.04.2011

Получил ответ от пользователя на другом форуме:

// инициализируем матрицу

... просмотреть метод инициализации

theCurrentMatrix = CATransform3DIdentity;

...

// вычисление поворота при касании экрана пользователем:

- (void) rotateX:(float)inX Y:(float)inY
{
     GLfloat lAngle=sqrt(inX*inX+inY*inY);

 if (lAngle != 0.0f)
 {
      static const float _degToRad = M_PI / 180.0;
            // we compute a rotation matrix (in radians)
      CATransform3D lRotation = CATransform3DMakeRotation(lAngle * _degToRad, inX, inY, 0.0f);

            // apply the rotation to the current matrix (cumulative effect)
            // order is important
      theCurrentMatrix = CATransform3DConcat(theCurrentMatrix, lRotation);
 }

}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     // Get touch
     UITouch *touch = [[touches allObjects] objectAtIndex:0];

     if ([touches count] == 1)
     {
          UITouch *touch = [[touches allObjects] objectAtIndex:0];
          CGPoint location = [touch locationInView:touch.view];
      CGPoint previousLocation = [touch previousLocationInView:touch.view];

      CGFloat lDeltaX = (location.x - previousLocation.x)*1.0;
      CGFloat lDeltaY = (location.y - previousLocation.y)*1.0;

      // rotate the current matrix
      [self rotateX:lDeltaYY:lDeltaX];
 }

}

// Применение поворота(ов) ...

glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();


 glTranslatef(0.0f,0.0f,-100.0f);   // move a little to see the object


 glMultMatrixf(theCurrenMatrixPtr]);

... нарисуй свои объекты

person user617123    schedule 14.06.2011