Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quaternion cube rotation animation

I created this Rubiks Cube with Papervison3D. With some resources I created a Cube with 27 minicubes inside (3*3*3 = 27). Rotating the Rubiks Cube on mouse move is already done. (I do not rotate the camera.)

All the behavior of a Rubiks Cube is in there already. But I'm a bit stuck in the final phase.

When I play with it like I would do with a normal Rubiks Cube it's working ok, besides I know that the default Euler rotation values aren't reliable anymore after a while. What I need is to rotate the Rubiks Cube to the selected side and after that rotate the Rubiks Cube over the z-axis so the minicube face faces up. I prefer to animate it with TweenMax but I'm really stuck since I need quaternion rotations.

I know the selected face of the Rubiks Cube itself. I know the Euler rotation of the Rubiks Cube using Matrix3D.matrix2euler(_rubiksCube.transform); What I need is to rotate it to the selected face for instance when the current rotation is x: -20, y: 35, z: 10 and I select the back face of the rubiksCube it must rotate to x:0, y: 180, z: 0.

What I need is to change this to Quaternion values and rotate the Rubiks Cube to the new Quaternion value. After that it must rotate the Rubiks Cube over it's z axis to face the selected minicube face up.

This is the code I use when dragging/ rotating the Rubiks Cube

private function onMouseMove( e : MouseEvent) : void {
    var m : Matrix3D;
    m = Matrix3D.rotationY( (mouseX - _mouseDownPoint.x) / 120 );
    m = Matrix3D.multiply( m, Matrix3D.rotationX( -(mouseY - _mouseDownPoint.y) / 120 ));
    _rubiksCube.transform = Matrix3D.multiply( m, _rubiksCube.transform );
    _mouseDownPoint.x = mouseX;
    _mouseDownPoint.y = mouseY;
}
like image 602
Jos Koomen Avatar asked Jan 14 '11 09:01

Jos Koomen


1 Answers

Quaternions are definitely the way to go. It's been a while since I used PV3D, but it goes something like this:

  1. Store the euler angles in separate variables (eg, u, v, w). Accumulate these variables in the calculation.
  2. Create a quaternion using Quaternion.createFromEuler();
  3. Transform using quaternion.matrix

Eg:

var yRotation:Number = 0;
var xRotation:Number = 0;

function mouseHandler(e:MouseEvent):void {
    yRotation += (mouseX - _mouseDownPoint.x) / 120;
    xRotation += -(mouseY - _mouseDownPoint.y) / 120);

    var q:Quaternion = Quaternion.createFromEuler(xRotation, yRotation, zRotation, true);  
    _rubiksCube.transform = q.matrix;
    _mouseDownPoint.x = mouseX;
    _mouseDownPoint.y = mouseY;
}

Update: Ah, I read your question again. It sounds like you want to smoothly interpolate from the current orientation to the new orientation. What worked for me before is this:

  1. Get your current euler position and convert to a quaternion using Quaternion.createFromEuler().
  2. Get the destination quaternion.
  3. Interpolate over time from the source quaternion to the target using quaternion.slerp().

Eg:

function clickHandler(e:MouseEvent):void {
    qSource = qCurrent;
    qTarget = quaternion.createFromEuler(....);
    t = getTimer();
}

function frameHandler(e:Event):void {
    if (isAnimating) {
        tDelta = (getTimer() - t) / 10000; // 10000 = 10 seconds
        qCurrent = slerp(qSource, qTarget, tDelta);
        _rubiksCube.transform = qCurrent.matrix;
    }
}
like image 159
Luke Van In Avatar answered Oct 05 '22 15:10

Luke Van In