【问题标题】:How do I control a camera in openGL with a gravity vector from the iPhone's accelerometer如何使用来自 iPhone 加速度计的重力矢量控制 openGL 中的相机
【发布时间】:2023-03-09 07:33:01
【问题描述】:

我有一个包含位置、向上和方向向量的相机结构。我想根据从 iPhone 的加速度计获得的重力矢量来更新这些矢量。我想要的效果是:当手机的顶部远离你倾斜时,相机会看向地面。换句话说,场景/几何图形遵循重力矢量的方向,而相机遵循手机本身的方向。

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

【问题讨论】:

    标签: iphone opengl-es accelerometer


    【解决方案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 框架包含您需要从指南针读取值的代码位,以防您尚未对该部分进行编码。

    祝你好运。

    【讨论】:

    • 这适用于具有内置指南针的较新 iPhone(除非我误解了您的解释),但我只使用加速度计,所以我在任何特定时刻所拥有的只是新的向上向量。另外,新的上向量不保证垂直于相机的x轴,那么如何确定相机的新方向呢?
    【解决方案2】:

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

    【讨论】:

    • 是的,这与我想要实现的目标非常相似。这就是我开始研究它的原因。但是,在存储方向向量供以后使用的同时获得这种效果是我发现困难的地方。谢谢!
    【解决方案3】:

    我得先说,我对这些东西很陌生,所以要小心,但是...

    我查看了上面 brock 的代码和他的解释,我想我想出了一个围绕 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,所以当我得到加速度代码时连接好,我会尽量记住在这里发布。

    另外,如果我错过了其他人可以添加一些亮点的东西,我很想听听。

    谢谢,

    约翰

    【讨论】:

      【解决方案4】:

      您真正想要的是一个基于加速度值的新投影矩阵。乌龙提供了这个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
      

      【讨论】:

        猜你喜欢
        • 2011-03-03
        • 2020-11-14
        • 2011-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多