iosopengl-es-2.0powervr-sgx

rotation along x and y axis


I'm using GLKit along with PowerVR library for my opengl-es 2.0 3D app. The 3D scene loads with several meshes, which simulate a garage environment. I have a car in the center of the garage. I am trying to add touch handling to the app, where the user can rotate the room around (e.g., to see all 4 walls surrounding the car). I also want to allow a rotation on the x axis, though limited to a small range. Basically they can see from a little bit of the top of the car to just above the floor level.

I am able to rotate on the Y OR on the X, but not both. As soon as I rotate on both axis, the car is thrown off-axis. The car isn't level with the camera anymore. I wish I could explain this better, but hopefully you guys will understand.

Here is my touches implementation:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch * touch = [touches anyObject];
    CGPoint location = [touch locationInView:self.view];    
    CGPoint lastLoc = [touch previousLocationInView:self.view];
    CGPoint diff = CGPointMake(lastLoc.x - location.x, lastLoc.y - location.y);

    float rotX = -1 * GLKMathDegreesToRadians(diff.x / 4.0);
    float rotY = GLKMathDegreesToRadians(diff.y / 5.0);

    PVRTVec3 xAxis = PVRTVec3(1, 0, 0);
    PVRTVec3 yAxis = PVRTVec3(0,1,0);

    PVRTMat4 yRotMatrix, xRotMatrix;

    // create rotation matrices with angle
    PVRTMatrixRotationXF(yRotMatrix, rotY);
    PVRTMatrixRotationYF(xRotMatrix, -rotX);

    _rotationY = _rotationY * yRotMatrix;
    _rotationX = _rotationX * xRotMatrix;
}

Here's my update method:

- (void)update {

    // Use the loaded effect
    m_pEffect->Activate();


    PVRTVec3    vFrom, vTo, vUp;
    VERTTYPE    fFOV;
    vUp.x = 0.0f;
    vUp.y = 1.0f;
    vUp.z = 0.0f;

    // We can get the camera position, target and field of view (fov) with GetCameraPos()
    fFOV = m_Scene.GetCameraPos(vFrom, vTo, 0);

    /*
     We can build the world view matrix from the camera position, target and an up vector.
     For this we use PVRTMat4LookAtRH().
     */
    m_mView = PVRTMat4::LookAtRH(vFrom, vTo, vUp);

    // rotate the camera based on the users swipe in the X direction (THIS WORKS)
    m_mView = m_mView * _rotationX;

    // Calculates the projection matrix
    bool bRotate = false;
    m_mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)1024.0/768.0, CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
}

I've tried multiplying the new X rotation matrix to the current scene rotation first, and then multiplying the new Y rotation matrix second. I've tried the reverse of that, thinking the order of multiplication was my problem. That didn't help. Then I tried adding the new X and Y rotation matrices together before multiplying to the current rotation, but that didn't work either. I feel that I'm close, but at this point I'm just out of ideas.

Can you guys help? Thanks. -Valerie

Update: In an effort to solve this, I'm trying to simplify it a little. I've updated the above code, removing any limit in the range of the Y rotation. Basically I calculate the X and Y rotation based on the user swipe on the screen.

If I understand this correctly, I think I want to rotate the View matrix (camera/eye) with the calculation for the _rotationX.

I think I need to use the World matrix (origin 0,0,0) for the _rotationY calculation. I'll try and get some images of exactly what I'm talking about.


Solution

  • Wahoo, got this working! I rotated the view matrix (created by LookAt method) with the X rotation matrix. I rotated the model view matrix with the Y rotation Matrix.

    Here's the modified Update method:

    - (void)update {
    
        PVRTVec3    vFrom, vTo, vUp;
        VERTTYPE    fFOV;
    
        // We can get the camera position, target and field of view (fov) with GetCameraPos()
        fFOV = m_Scene.GetCameraPos(vFrom, vTo, 0);
    
        /*
         We can build the world view matrix from the camera position, target and an up vector.
         For this we use PVRTMat4LookAtRH().
         */
        m_mView = PVRTMat4::LookAtRH(vFrom, vTo, PVRTVec3(0.0f, 1.0f, 0.0f));
    
        // rotate on the X axis (finger swipe Y direction)
        m_mView = m_mView * _rotationY;
    
        // Calculates the projection matrix
        m_mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)1024.0/768.0, CAM_NEAR, CAM_FAR, PVRTMat4::OGL, false);
    
    }
    

    Here's the modified touch moved method:

    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    
        UITouch * touch = [touches anyObject];
        CGPoint location = [touch locationInView:self.view];    
        CGPoint lastLoc = [touch previousLocationInView:self.view];
        CGPoint diff = CGPointMake(lastLoc.x - location.x, lastLoc.y - location.y);
    
        float rotX = -1 * GLKMathDegreesToRadians(diff.x / 2.5);
        float rotY = GLKMathDegreesToRadians(diff.y / 2.5);
    
        PVRTMat4 rotMatrixX, rotMatrixY;
    
        // create rotation matrices with angle
        PVRTMatrixRotationYF(rotMatrixX, -rotX);
        PVRTMatrixRotationXF(rotMatrixY, rotY);
    
        _rotationX = _rotationX * rotMatrixX;
        _rotationY = _rotationY * rotMatrixY;
    
    }