簡體   English   中英

iOS OpenGL ES 2.0四元數旋轉限制到XYZ位置

[英]iOS OpenGL ES 2.0 Quaternion Rotation Slerp to XYZ Position

我正在跟蹤四元數教程: 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”向量。 我認為這可能與up向量有關,但我已經嘗試了所有有意義的方法。

我在做什么錯-如何定義最終的四元數,當我完成旋轉后,將其看向地球表面XYZ的向量? 謝謝!

含義如下:您的地球儀中心為(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;
}

這個問題的答案是以下RotateTo函數與Ray的教程中的代碼更改( http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-觸摸opengl )。 正如對該文章的評論之一說,在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);

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM