Missing z-axis rotation for transforming between two vectors

| | August 6, 2015

I’m trying to rotate a cube so that it’s facing up, but am getting hung up on the final implementation details. It now reliably will rotate the x,y axis to the correct side, but the z-axis is never rotating (See photos of before and after rotation). When I’m using the code below I always get ‘0’ for my rotationVector.z. What am I missing here?

// Define lookAt vector
lookAtVector = GLKVector3Make(0,0,1);

// Define axes vectors
axes[0] = GLKVector3Make(0,0,1);
axes[1] = GLKVector3Make(-1,0,0);
axes[2] = GLKVector3Make(0,1,0);
axes[3] = GLKVector3Make(1,0,0);
axes[4] = GLKVector3Make(0,-1,0);
axes[5] = GLKVector3Make(0,0,-1);

CGFloat highest_dot = -1.0;
GLKVector3 closest_axis;

for(int i = 0; i < 6; i++) {
    // multiply cube's axes by existing matrix
    GLKVector3 axis = GLKMatrix4MultiplyVector3(matrix, axes[i]);
    CGFloat dot = GLKVector3DotProduct(axis, lookAtVector);
    if(dot > highest_dot) {
        closest_axis = axis;
        highest_dot = dot;
    }
}

GLKVector3 rotationVector = GLKVector3CrossProduct(closest_axis, lookAtVector); 

// Get angle between vectors
CGFloat angle = atan2(GLKVector3Length(rotationVector), GLKVector3DotProduct(closest_axis, lookAtVector));

// normalize the rotation vector
rotationVector = GLKVector3Normalize(rotationVector);

// Create transform
CATransform3D rotationTransform = CATransform3DMakeRotation(angle,  rotationVector.x, rotationVector.y, rotationVector.z);

// add rotation transform to existing transformation
baseTransform = CATransform3DConcat(baseTransform, rotationTransform);
return baseTransform;

Before 3d Rotation
Before

After 3d Rotation
After

Implementation based on this post

3 Responses to “Missing z-axis rotation for transforming between two vectors”

  1. lookAtVector = GLKVector3Make(0,0,1); 
    (...) 
    GLKVector3 rotationVector = GLKVector3CrossProduct(closest_axis, lookAtVector);
    

    In 3D and higher dimensions, a cross-product returns a vector which is perpendicular to the two input vectors.

    lookAtVector is defined as (0,0,1).

    Hence, if you use it in a cross-product, no matter what the value of closest_axis might be, the result will have 0 as its z component, because if it did not, it would not be perpendicular to lookAtVector.

    You don’t say what you’re actually trying to do, so I can’t go on and explain how to actually do whatever your intent was. But I hope that the explanation of the maths is enough to help you solve your own issue, here!

  2. Remember that there are 4 possible orientations of the cube for any given face ‘up’.

    I made a game of rotating cubes before (search ‘Obecolo’).

    To avoid floating point approximation errors accumulating in each cubes model matrix, I set up a multiply-linked list of the 24 possible orientations. I.e., each entry would have links to the ‘adjacent’ orientations obtained by rotating +-90 degrees on each axis.

    I built the list on startup, one antry at a time, by multiplying basic ‘building block’ matrices (i.e., 90, 180 or 270 rotation on X, Y or Z).

    To write the code above, it helped a lot to have a cube on my desk with the faces labeled ‘TOP’, ‘BOTTOM’, ‘LEFT’, ‘RIGHT’, ‘FRONT’ and ‘BACK’. Also, texturing the cube faces with colors that provide a visual cue: RED for +X (cyan for -X), GREEN for +Y (magenta for -Y) and BLUE for +Z (yellow for -Z).

  3. I don’t think this is your entire problem, but you do at least need to be doing this:

    CGFloat highest_abs_dot = 0.0;
    GLKVector3 closest_axis;
    
    for(int i = 0; i < 6; i++) {
        // multiply cube's axes by existing matrix
        GLKVector3 axis = GLKMatrix4MultiplyVector3(matrix, axes[i]);
        CGFloat abs_dot = fabsf(GLKVector3DotProduct(axis, lookAtVector));
        if(abs_dot > highest_abs_dot) {
            closest_axis = axis;
            highest_abs_dot = abs_dot;
        }
    }
    

Leave a Reply