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;
}
Quaternions are definitely the way to go. It's been a while since I used PV3D, but it goes something like this:
- Store the euler angles in separate variables (eg, u, v, w). Accumulate these variables in the calculation.
- Create a quaternion using Quaternion.createFromEuler();
- 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:
- Get your current euler position and convert to a quaternion using Quaternion.createFromEuler().
- Get the destination quaternion.
- 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;
}
}
精彩评论