如何使用iPhone加速度计的重力矢量控制openGL中的摄像头

时间:2009-07-13 10:03:09

标签: iphone opengl-es accelerometer

我有一个摄像头结构,可以保存位置,向上和方向向量。我想根据我从iPhone的加速度计得到的重力矢量更新这些矢量。我想要的效果是:当手机顶部偏离你时,相机会朝地面看。换句话说,场景/几何体遵循重力矢量的方向,而相机则遵循手机本身的方向。

我想我可以将我从相机矢量构建的矩阵乘以重力矢量构建的矩阵,然后将新的向上和方向向量拉出来,但我认为我不能完全理解这个过程。不能让它发挥作用。我非常感谢任何帮助。谢谢!

4 个答案:

答案 0 :(得分:1)

您只需更新相机的查找方向即可。您不必更改世界矩阵,openGL“gluLookAt()”方法会在幕后自动为您执行此操作。

如果您有摄像机类设置,只需创建一个功能来设置摄像机的向上方向向量,您需要根据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框架包含从罗盘中读取值所需的代码位,但尚未对该部分进行编码。

祝你好运。

答案 1 :(得分:1)

我认为Apple的sample GLGravity application完全符合您的要求,除非我错误地阅读您的请求。

答案 2 :(得分:0)

我应该先说,我对这些东西很新,所以要警惕,但是......

我看了上面的布鲁克的代码和他的解释,我想我想出了一个围绕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,所以当我得到加速代码有线,我会试着记住在这里发布。

另外,如果我错过了别人可以添加一些亮光的东西,我很乐意听到。

感谢,

约翰

答案 3 :(得分:0)

你真正想要的是一个基于加速度值的新投影矩阵。乌龙提供这个crazy math来做那个(不是我的)。

/*
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