iOS OpenGL ES 2.0 Quaternions вращение с импульсом после пролистывания

Я изучаю OpenGL ES 2.0 для iOS и с помощью нескольких опорных пунктов могу вращать и масштабировать простой объект сферы с помощью кватернионов. Мне бы хотелось, чтобы глобус продолжал вращаться с уменьшающейся скоростью, когда пользователь убирает палец с экрана после завершения удара, поэтому я хотел бы придать сфере импульс. Я использовал этот блог, чтобы узнать о вращении: http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl. Кто-нибудь может предоставить некоторые чтения или примеры импульса? Как я могу реализовать импульс с кватернионами? Спасибо!

    // Set up the frustrum and projection matrix
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
self.effect.transform.projectionMatrix = projectionMatrix;

// Now perform the interpolation step
//[self slerpToNewLocation];

// Move the globe back so we can see it
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, GLOBAL_EARTH_Z_LOCATION);

// In update, we convert the quaternion into a rotation matrix, and apply it to the model view matrix as usual.
GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat);
GLKMatrix4 rotateMatrix = GLKMatrix4RotateWithVector3(rotation,momentumVar/200,GLKQuaternionAxis(_quat));
_quat = GLKQuaternionMakeWithMatrix4(rotateMatrix);

modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotateMatrix);

// Cap the zoom scale factor max and mins
// only if slerping so that the auto-zoom out and back
// in still works during auto-rotation
if ( !_slerping ) {
    if ( scale > 2.0 ) {
        scale = 2.0;
    }
    if ( scale < 1.15 ) {
        scale = 1.15;
    }
}

// Apply the zoom factors
if ( _slerping ) {
    //NSLog(@"final scale %f",scale);
}

modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, scale, scale, scale);

// Assign the drawer modelViewMatrix
self.effect.transform.modelviewMatrix = modelViewMatrix;

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

// Called when touches are ended
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

    // The momentum var is initialized to a value
    momentumVar = 0.025;

    // Now since we stopped touching, decay the rotation to simulate momentum
    momentumTimer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                     target:self
                                   selector:@selector(decayGLKQuaternion)
                                   userInfo:nil
                                    repeats:YES];

}

// Slerp about the current axis after touches ended but for a greater angle ( radians )
- (void)decayGLKQuaternion {

    if ( momentumVar < 0.001 ) {

        // Stop the momentum and timer
        momentumVar = 1.0;
        [momentumTimer invalidate];

    }
    else {

        // What is the current angle for the quaternion?
        float currentQuatAngle = GLKQuaternionAngle(_quat);

        // Decay the value each time
        momentumVar = currentQuatAngle * 0.95;

    }

}

ОБНОВЛЕНИЕ: Я все еще пытаюсь выяснить это, я попытался преобразовать текущий кватернион в методе обновления в Matrix4 и повернуть эту матрицу вокруг оси кватернионов для значения, которое обновляется и уменьшается из таймера, который запускается, когда TouchesEnded в мое приложение. В результате получается вращение, но ось выглядит не совсем правильно (кажется, что она близка), а угол создает противоположное направление вращения, которое я ожидаю - поэтому, если я проведу пальцем вниз и подниму палец, шар вращается вверх с уменьшающейся скоростью. Изменение знака значения угла не помогает. Как правильно извлечь ось вращения из кватерниона, повернуть ее на нужный угол и сделать это с уменьшающейся скоростью? Спасибо -

// In update, we convert the quaternion into a rotation matrix, and apply it to the model view matrix as usual.
    GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat);
    GLKMatrix4 rotateMatrix = GLKMatrix4RotateWithVector3(rotation,momentumVar/200,GLKQuaternionAxis(_quat));
    _quat = GLKQuaternionMakeWithMatrix4(rotateMatrix);

    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotateMatrix);

1 ответ

Вы можете полностью избежать необходимости реализовывать физику импульса, используя класс UIScrollView в UIKit. Вы можете расположить UIScrollView, который на самом деле не рисует какой-либо контент поверх вашего представления OpenGL, и настроить его так, чтобы у вас были свойства contentSize (область прокрутки) и прокрутки, которые вы хотите. Затем вы можете настроить один из ваших классов на UIScrollViewDelegate и сделать экземпляр этого класса делегатом вашего UIScrollView. Затем, когда пользователь взаимодействует с вашим невидимым представлением прокрутки (поверх вашего представления OpenGL), ваш класс делегата представления прокрутки будет уведомлен о взаимодействиях пользователя. Следующий метод делегата может быть особенно полезен для реализации.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

Там вы можете получить недавно обновленный contentOffset и использовать его для обновления вашей 3D-модели, которую вы можете затем визуализировать с помощью OpenGL в представление OpenGL. Таким образом, вы используете только представление прокрутки в качестве механизма обнаружения взаимодействия с пользователем, которое будет обрабатывать все приятные плавные обновления и физику импульса, с которыми знакомы пользователи iOS.

Я настоятельно рекомендую посмотреть сессию 223 WWDC 2012 "Улучшение взаимодействия с представлениями прокрутки" вместе с Джошем Шаффером. В этом выступлении он обсуждает использование этой техники очень подробно и с примерами.

Другие вопросы по тегам