Как управлять камерой в openGL с помощью вектора гравитации от акселерометра iPhone - PullRequest
1 голос
/ 13 июля 2009

У меня есть структура камеры, которая содержит векторы местоположения, направления вверх и направления. Я хотел бы обновить эти векторы на основе вектора силы тяжести, который я получаю от акселерометра iPhone. Эффект, которого я добиваюсь: когда верх телефона отклонен от вас, камера смотрит на землю. Другими словами, сцена / геометрия следует ориентации вектора гравитации, а камера - ориентации самого телефона.

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

Ответы [ 4 ]

1 голос
/ 13 июля 2009

Я думаю, что пример приложения Apple от GLGravity делает именно то, что вы хотите, если только я неправильно прочитал ваш запрос.

1 голос
/ 13 июля 2009

Вам просто нужно обновить направление, в котором смотрит ваша камера. Вам не нужно менять матрицу мира, метод openGL "gluLookAt ()" сделает это автоматически за кулисами.

Если у вас есть настройка класса камеры, просто создайте функцию для установки вектора направления вверх камеры, который вам потребуется для расчета на основе значения типа float / double (я полагаю) из компаса iPhone. Когда ваша камера обновится в позиции lookAt (), она должна изменить камеру, чтобы она смотрела в правильном месте.

Это не сильно отличается от того, что вы делаете, когда вращаете камеру в игре на основе FPS. Разница в том, что вы хотите вращать камеру вдоль оси X вместо оси Y.

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

Вот некоторый C ++ код, который я написал, который может дать вам представление о том, как должен работать ваш класс камеры:

/* This reshapes the camera using the perspective projection */
void Camera::ReshapePerspectiveForPicking( void )
{   
    glMatrixMode(GL_PROJECTION);

    // Sets the clipping volume
    gluPerspective( m_FieldOfView, (float)m_width/(float)m_height, m_zNear, m_zFar );

    gluLookAt(  camPos.x, camPos.y, camPos.z, 
            camPos.x + camView.x,   camPos.y + camView.y,   camPos.z + camView.z,
            0.0f, 1.0f, 0.0f );

    glMatrixMode( GL_MODELVIEW );
}

Обратите внимание на строку выше (0.0f, 1.0f, 0.0f). Это вектор направления ВВЕРХ. Это было статично для моей игры, потому что камера никогда не должна была смотреть вниз. Вам просто нужно изменить этот вектор, создав новый вектор на ориентации компаса.

Метод, приведенный ниже, был просто альтернативным методом, который нам иногда требовался для обновления камеры, передавая ей специальный вектор. Вы, вероятно, можете игнорировать это, я просто включил его, чтобы вы могли поучиться у него.

   /* This updates the camera to look at the changed camera position. This uses a passed in camPosition and camView GameMath::Vector */
    void Camera::Update( GameMath::Vector camPos, GameMath::Vector camView )
    {
        glMatrixMode( GL_PROJECTION );
        gluLookAt(  camPos.x, camPos.y, camPos.z, 
                camPos.x + camView.x,   camPos.y + camView.y,   camPos.z + camView.z,
                0.0f, 1.0f,0.0f );
    }

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

void Camera::Rotate( void )
{
    if ( m_rotateCamera == true )
    {
        // Keep the radians within 2 pi, roughly
        float minimumRadiansRotate = 0.00;
        float maximumRadiansRotate = 6.2831853072;
        m_YRotateAngle = GameMath::Wrap( m_YRotateAngle, minimumRadiansRotate, maximumRadiansRotate );

        m_YRotateAngle += m_rotateSpeed * m_rotateDirection;    // Add to the camera's current angle value
        camView.x = sin( m_YRotateAngle );
        camView.z = -cos( m_YRotateAngle );
    }
}

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

Среда CoreLocation содержит биты кода, которые вам понадобятся для считывания значений с компаса, если вы еще не закодировали эту часть.

Удачи.

0 голосов
/ 18 сентября 2009

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

/*
Oolong Engine for the iPhone / iPod touch
Copyright (c) 2007-2008 Wolfgang Engel  http://code.google.com/p/oolongengine/

This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, 
including commercial applications, and to alter it and redistribute it freely, 
subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

#import "Accelerometer.h"

#define FILTERINGFACTOR 0.1

@implementation Accel

- (void) SetupAccelerometer: (float) AcclerometerFrequency
{
        //Configure and start accelerometer
        [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / AcclerometerFrequency)];
        [[UIAccelerometer sharedAccelerometer] setDelegate:self];
}



- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)Acceleration
{
        // use a basic low-pass filter to only keep the gravity in the accelerometer values
        _accelerometer[0] = Acceleration.x * FILTERINGFACTOR + _accelerometer[0] * (1.0 - FILTERINGFACTOR);
        _accelerometer[1] = Acceleration.y * FILTERINGFACTOR + _accelerometer[1] * (1.0 - FILTERINGFACTOR);
        _accelerometer[2] = Acceleration.z * FILTERINGFACTOR + _accelerometer[2] * (1.0 - FILTERINGFACTOR);
}

- (void) GetAccelerometerMatrix:(GLfloat *) matrix
{

        GLfloat length = sqrtf(_accelerometer[0] * _accelerometer[0] + _accelerometer[1] * _accelerometer[1] + _accelerometer[2] * _accelerometer[2]);

        //Clear matrix to be used to rotate from the current referential to one based on the gravity vector
        bzero(matrix, sizeof(matrix));
        matrix[15] = 1.0f;
        //matrix[3][3] = 1.0;

        //Setup first matrix column as gravity vector
        matrix[0] = _accelerometer[0] / length;
        matrix[1] = _accelerometer[1] / length;
        matrix[2] = _accelerometer[2] / length;

        //Setup second matrix column as an arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz} defined by by the equation "Gx * x + Gy * y + Gz * z = 0" in which we arbitrarily set x=0 and y=1
        matrix[4] = 0.0;
        matrix[5] = 1.0;
        matrix[6] = -_accelerometer[1] / _accelerometer[2];
        length = sqrtf(matrix[4] * matrix[4] + matrix[5] * matrix[5] + matrix[6] * matrix[6]);
        matrix[4] /= length;
        matrix[5] /= length;
        matrix[6] /= length;

        //Setup third matrix column as the cross product of the first two
        matrix[8] = matrix[1] * matrix[6] - matrix[2] * matrix[5];
        matrix[9] = matrix[4] * matrix[2] - matrix[6] * matrix[0];
        matrix[10] = matrix[0] * matrix[5] - matrix[1] * matrix[4];
}

- (void) GetAccelerometerVector:(double *) AccelValue;
{
        // the vector is read-only, so make a copy of it and do not expose a pointer to it
        AccelValue[0] = (double)_accelerometer[0];
        AccelValue[1] = (double)_accelerometer[1];
        AccelValue[2] = (double)_accelerometer[2];
}

@end
0 голосов
/ 31 июля 2009

Я должен начать с говорить, я очень новичок в этом, так что будьте осторожны, но ...

Я посмотрел на код Брока выше и его объяснение, и я думаю, что я придумал камеру, вращающуюся вокруг оси x и y. на самом деле, моя камера тоже вращается вокруг z, но я думаю, что это другая история (я просто передаю отфильтрованные значения из значений акселерометра x & y прямо в вектор «вверх», чтобы создать иллюзию того, что мои объекты подвержены действию гравитации ... работает довольно хорошо).

так ... вот что я придумал:

float lx = sin(DEGREES_TO_RADIANS(horzAngle));
float ly = sin(DEGREES_TO_RADIANS(vertAngle));
float lz = -cos(DEGREES_TO_RADIANS(horzAngle));

float x;
float y;
float z;

    // get the default camera eye for the object
    // this will center the object on the screen
[sprite.camera restore];
[sprite.camera eyeX:&x eyeY:&y eyeZ:&z];

// add distance calcs
x = x + (-1 * sprite.distance)*(lx);
z = z + (-1 * sprite.distance)*(-1);

[sprite.camera setEyeX:x eyeY:y eyeZ:z];
[sprite.camera setCenterX:x + lx centerY:y + ly centerZ:z + lz];

это использует библиотеку cocos2d (очень простую в использовании) ... она оборачивает содержимое камеры так, что в итоге она вызовет gluLookAt, например:

    gluLookAt( eyeX, eyeY, eyeZ,
            centerX, centerY, centerZ,
            upX, upY, upZ
            );

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

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

спасибо,

джон

...