【问题标题】:iOS OpenGL ES 2.0 Quaternion Rotation Slerp to XYZ PositioniOS OpenGL ES 2.0 四元数旋转 Slerp 到 XYZ 位置
【发布时间】:2013-06-05 00:32:24
【问题描述】:

我正在学习四元数教程:http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl 并尝试将地球仪旋转到某个 XYZ 位置。我有一个初始四元数并在地球表面生成一个随机 XYZ 位置。我将该 XYZ 位置传递给以下函数。这个想法是用 GLKMatrix4MakeLookAt 生成一个lookAt向量,并从lookAt矩阵定义slerp步骤的结束四元数。

- (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {

    // Turn on the interpolation for smooth rotation
    _slerping = YES; // Begin auto rotating to this location
    _slerpCur = 0;
    _slerpMax = 1.0;
    _slerpStart = _quat;

    // The eye location is defined by the look at location multiplied by this modifier
    float modifier = 1.0;

    // Create a look at vector for which we will create a GLK4Matrix from
    float xEye = x;
    float yEye = y;
    float zEye = z;
    //NSLog(@"%f %f %f %f %f %f",xEye, yEye, zEye, x, y, z);
    _currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
    _currentSatelliteLocation = GLKMatrix4Multiply(_currentSatelliteLocation,self.effect.transform.modelviewMatrix);

    // Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
    //_currentSatelliteLocation = GLKMatrix4Translate(_currentSatelliteLocation, 0.0f, 0.0f, GLOBAL_EARTH_Z_LOCATION);
    _slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);

    // Print info on the quat
    GLKVector3 vec = GLKQuaternionAxis(_slerpEnd);
    float angle = GLKQuaternionAngle(_slerpEnd);
    //NSLog(@"%f %f %f %f",vec.x,vec.y,vec.z,angle);

    NSLog(@"Quat end:");
    [self printMatrix:_currentSatelliteLocation];
    //[self printMatrix:self.effect.transform.modelviewMatrix];

}

插值有效,我得到了一个平滑的旋转,但是结束位置从来不是我输入的 XYZ - 我知道这一点,因为我的地球是一个球体,我正在从 Lat Lon 计算 XYZ。我想在旋转后从地球表面的纬度/经度位置直接向下看向地球中心的“lookAt”矢量。我认为这可能与向上向量有关,但我已经尝试了所有有意义的方法。

我做错了什么 - 如何定义一个最终四元数,当我完成旋转时,它会向下看一个向量到地球表面的 XYZ?谢谢!

【问题讨论】:

    标签: iphone ios opengl-es opengl-es-2.0 glkit


    【解决方案1】:

    以下是你的意思吗: 你的地球中心是 (0, 0, 0),半径是 R,起始位置是 (0, 0, R),你的最终位置是 (0, R, 0),所以将地球绕 X 轴旋转 90 度? 如果是这样,只需将lookat功能的眼睛位置设置为您的最终位置,将参数设置为地球中心。

    m_target.x = 0.0f;
    m_target.y = 0.0f;
    m_target.z = 1.0f;
    
    m_right.x = 1.0f;
    m_right.y = 0.0f;
    m_right.z = 0.0f;
    
    m_up.x = 0.0f;
    m_up.y = 1.0f;
    m_up.z = 0.0f;
    void CCamera::RotateX( float amount )
    {
        Point3D target = m_target;
        Point3D up = m_up;
    
        amount = amount / 180 * PI;
    
        m_target.x = (cos(PI / 2 - amount) * up.x) + (cos(amount) * target.x);
        m_target.y = (cos(PI / 2 - amount) * up.y) + (cos(amount) * target.y);
        m_target.z = (cos(PI / 2 - amount) * up.z) + (cos(amount) * target.z);
    
        m_up.x = (cos(amount) * up.x) + (cos(PI / 2 + amount) * target.x);
        m_up.y = (cos(amount) * up.y) + (cos(PI / 2 + amount) * target.y);
        m_up.z = (cos(amount) * up.z) + (cos(PI / 2 + amount) * target.z);
    
        Normalize(m_target);
        Normalize(m_up);
    }
    
    void CCamera::RotateY( float amount )
    {
        Point3D target = m_target;
        Point3D right = m_right;
    
        amount = amount / 180 * PI;
    
        m_target.x = (cos(PI / 2 + amount) * right.x) + (cos(amount) * target.x);
        m_target.y = (cos(PI / 2 + amount) * right.y) + (cos(amount) * target.y);
        m_target.z = (cos(PI / 2 + amount) * right.z) + (cos(amount) * target.z);
    
        m_right.x  = (cos(amount) * right.x) + (cos(PI / 2 - amount) * target.x);
        m_right.y  = (cos(amount) * right.y) + (cos(PI / 2 - amount) * target.y);
        m_right.z  = (cos(amount) * right.z) + (cos(PI / 2 - amount) * target.z);
    
        Normalize(m_target);
        Normalize(m_right);
    }
    
    void CCamera::RotateZ( float amount )
    {
        Point3D right = m_right;
        Point3D up = m_up;
    
        amount = amount / 180 * PI;
    
        m_up.x = (cos(amount) * up.x) + (cos(PI / 2 - amount) * right.x);
        m_up.y = (cos(amount) * up.y) + (cos(PI / 2 - amount) * right.y);
        m_up.z = (cos(amount) * up.z) + (cos(PI / 2 - amount) * right.z);
    
        m_right.x = (cos(PI / 2 + amount) * up.x) + (cos(amount) * right.x);
        m_right.y = (cos(PI / 2 + amount) * up.y) + (cos(amount) * right.y);
        m_right.z = (cos(PI / 2 + amount) * up.z) + (cos(amount) * right.z);
    
        Normalize(m_right);
        Normalize(m_up);
    }
    
    void CCamera::Normalize( Point3D &p )
    {
        float length = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
        if (1 == length || 0 == length)
        {
            return;
        }
    
        float scaleFactor = 1.0 / length;
        p.x *= scaleFactor;
        p.y *= scaleFactor;
        p.z *= scaleFactor;
    }
    

    【讨论】:

    • 嗨,我尝试了你的建议,但我没有旋转到我输入的 xyz 坐标。我正在通过将 xyz 坐标乘以包含旋转的基本效果矩阵来考虑现有的旋转。有趣的是,每次我称之为“自动旋转”时,我都会得到一个不同的结束位置。你还有其他建议吗?谢谢!
    • @PhilBot 或者你可以计算绕x、y、z轴旋转的角度,然后在答案处尝试计算。
    【解决方案2】:

    这个问题的答案是下面的 rotateTo 函数和 Ray 教程 (http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl) 中对代码的更改的组合。正如那篇文章中的一位 cmets 所说,在 GLKQuaternion Q_rot = GLKQuaternionMakeWithAngleAndVector3Axis(angle * 2.0, axis); 中乘以 2.0 的任意因子。删除“2”并使用以下函数创建 _slerpEnd - 之后地球将平滑旋转到指定的 XYZ。

    // Rotate the globe using Slerp interpolation to an XYZ coordinate
    - (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {
    
        // Turn on the interpolation for smooth rotation
        _slerping = YES; // Begin auto rotating to this location
        _slerpCur = 0;
        _slerpMax = 1.0;
        _slerpStart = _quat;
    
        // Create a look at vector for which we will create a GLK4Matrix from
        float xEye = x;
        float yEye = y;
        float zEye = z;
        _currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
    
        // Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
        _slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      相关资源
      最近更新 更多