Question

I've built a 6 faces 3D dice using the CATransformLayer, using it as a container layer griping 6 transformed layers into a 3D object that can spin around in space. I got the idea from here. It's working well and I can rotate the "dice" calling CATransform3DMakeRotation on the top layer, the dice rotates and works well.

Next step was to insert "bullet physics" into the program. I've it working however I'm stuck because I don't know how to convert from "bullet physics 'quaternion' orientation" of the dice in its physics world into a rotation angles that I can pass to my container CALayer method.

Here is what I'm doing:

1) Call to "bullet physics" to obtain the orientation of the dice:

// QUATERNION: Get the orientation
btQuaternion quatO = TObject->getOrientation();

2) Convert the quaternion to euler (lot of time googling for an answer found a method copied below to do so) qW = quatO.getW(); qX = quatO.getX(); qY = quatO.getY(); qZ = quatO.getZ(); [self quaternionToEuler];

3) Apply the new euler angles to my CALayer (sCtrl)

[sCtrl rotaX:eX rotaY:eY rotaZ:eZ];

Note1: this is the method 'm using to rotate my calayer

- (CATransform3D) rotaX:(CGFloat) anguloX  rotaY:(CGFloat) anguloY rotaZ:(CGFloat) anguloZ
{         
    CATransform3D rX;
    CATransform3D rY;
    CATransform3D rZ;
    CATransform3D ret;

    // Apply all the rotations in order (x, y, z)
    rX = CATransform3DMakeRotation([self gradosARadianes:(anguloX)], 1.0f, 0.0f, 0.0f);
    ret = CATransform3DConcat(baseTransform, rX);
    rY = CATransform3DMakeRotation([self gradosARadianes:(anguloY)], 0.0f, 1.0f, 0.0f);
    ret = CATransform3DConcat(rX, rY);
    rZ = CATransform3DMakeRotation([self gradosARadianes:(anguloZ)], 0.0f, 0.0f, 1.0f);
    ret = CATransform3DConcat(rY, rZ);


    // Store finished result for next time start from there... 
    baseTransform = ret;

    return ret;
}

Note2: This is me method I found to convert quaternion to euler.

-(void) quaternionToEuler
{
    float matrix[3][3];
    float cx,sx;
    float cy,sy,yr;
    float cz,sz;
    matrix[0][0] = 1.0f - 2.0f * (qY * qY + qZ * qZ);
    matrix[0][1] = (2.0f * qX * qY) - (2.0f * qW * qZ);
    matrix[1][0] = 2.0f * (qX * qY + qW * qZ);
    matrix[1][1] = 1.0f - (2.0f * qX * qX) - (2.0f * qZ * qZ);
    matrix[2][0] = 2.0f * (qX * qZ - qW * qY);
    matrix[2][1] = 2.0f * (qY * qZ + qW * qX);
    matrix[2][2] = 1.0f - 2.0f * (qX * qX - qY * qY);


    sy = -matrix[2][0];
    cy = sqrt(1 - (sy * sy));
    yr = (float)atan2(sy,cy);
    eY = (yr * 180.0f) / (float)M_PI;

    if (sy != 1.0f && sy != -1.0f)   
    {
        cx = matrix[2][2] / cy;
        sx = matrix[2][1] / cy;
        eX = ((float)atan2(sx,cx) * 180.0f) / (float)M_PI;   // RAD TO DEG

        cz = matrix[0][0] / cy;
        sz = matrix[1][0] / cy;
        eZ = ((float)atan2(sz,cz) * 180.0f) / (float)M_PI;   // RAD TO DEG
    }
    else
    {
        cx = matrix[1][1];
        sx = -matrix[1][2];
        eX = ((float)atan2(sx,cx) * 180.0f) / (float)M_PI;   // RAD TO DEG

        cz = 1.0f;
        sz = 0.0f;
        eZ = ((float)atan2(sz,cz) * 180.0f) / (float)M_PI;   // RAD TO DEG
    }    
}

In summary, my objective: represent a "bullet physics" BOX (dice) in my program using CALayer's (not OpenGL). In order to to so I'm using CATransformLayer as a container of 6 transformed layers into a 3D object.

-- The results I'm getting now is not good, the graphical dice rotates but obviously incorrectly... so I'm doing something completely wrong here...

Question is: Given that I can get the "orientation or rotation" of the BOX in the bullet physics world, how I can convert the returned quaternion to something (angles) usable with CATransform3DMakeRotation.

Thanks a lot in advance,

Luis

Was it helpful?

Solution

This is a terrible approach. You’re starting with a matrix, turning it into a quaternion, turning that into Euler angles, then turning those into a matrix.

Instead of getOrientation(), call getCenterOfMassTransform().getBasis() to get a btMatrix3x3. Pack this into the top left of the CATransform3D, and fill out the rest with zeros (except m44, which should be 1).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top