四元数立方体旋转动画

时间:2011-01-14 09:14:17

标签: flash math papervision3d quaternions

我用Papervison3D创建了这个Rubiks Cube。通过一些资源,我创建了一个内部有27个微型管的立方体(3 * 3 * 3 = 27)。在鼠标移动时旋转Rubiks立方体已经完成。 (我不旋转相机。)

Rubiks Cube的所有行为都在那里。但是我在最后阶段有点陷入困境。

当我使用它时,就像我使用普通的Rubiks Cube一样,它工作正常,此外我知道默认的Euler旋转值在一段时间后不再可靠。我需要的是将Rubiks立方体旋转到选定的一侧,然后在Z轴上旋转Rubiks立方体,使小型立面朝上。我更喜欢使用TweenMax为它设置动画,但我真的被卡住,因为我需要四元数旋转。

我知道Rubiks Cube本身的选定面孔。我知道使用Matrix3D.matrix2euler(_rubiksCube.transform);的Rubiks立方体的Euler旋转我需要的是将它旋转到选定的面,例如当前旋转为x: -20, y: 35, z: 10并且我选择它必须旋转的rubiksCube的背面到x:0, y: 180, z: 0

我需要的是将其更改为Quaternion值并将Rubiks Cube旋转到新的Quaternion值。之后,必须将Rubiks立方体旋转到其z轴上,使其朝向所选的微型立面。

这是我在拖动/旋转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;
}

1 个答案:

答案 0 :(得分:4)

四元数肯定是要走的路。自从我使用PV3D以来已经有一段时间了,但它是这样的:

  1. 将欧拉角存储在单独的变量中(例如,u,v,w)。在计算中累计这些变量。
  2. 使用Quaternion.createFromEuler();
  3. 创建四元数
  4. 使用quaternion.matrix进行转换
  5. 例如:

    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;
    }
    

    更新:啊,我又读了你的问题。听起来你想要从当前方向平滑插值到新方向。以前对我有用的是:

    1. 使用Quaternion.createFromEuler()获取当前的euler位置并转换为四元数。
    2. 获取目标四元数。
    3. 使用quaternion.slerp()随时间从源四元数到目标进行插值。
    4. 例如:

      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;
          }
      }