3D Object rotation by Quaternion and Tweener
3Dオブジェクトをマウスの向きに合わせて回転させる
* 軸回転ではなく、クォータニオンを使って回転を制御
*
* ついでにTweenerで姿勢制御をアニメーションさせてみる
* Cubeをドラッグで回転させた後、
* resetボタンを押すとアニメーションしながら初期値に戻る
*
* [参考したサイト]
* http://yamasv.blog92.fc2.com/blog-entry-129.html
* http://yamasv.blog92.fc2.com/blog-entry-146.html
* http://blog.r3c7.net/?p=152
* http://forum.papervision3d.org/viewtopic.php?f=20&t=690
/**
* Copyright fukusin ( http://wonderfl.net/user/fukusin )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/4kEq
*/
/*
* 3Dオブジェクトをマウスの向きに合わせて回転させる
* 軸回転ではなく、クォータニオンを使って回転を制御
*
* ついでにTweenerで姿勢制御をアニメーションさせてみる
* Cubeをドラッグで回転させた後、
* resetボタンを押すとアニメーションしながら初期値に戻る
*
* [参考したサイト]
* http://yamasv.blog92.fc2.com/blog-entry-129.html
* http://yamasv.blog92.fc2.com/blog-entry-146.html
* http://blog.r3c7.net/?p=152
* http://forum.papervision3d.org/viewtopic.php?f=20&t=690
*/
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
//import fl.controls.*;
//
//import org.papervision3d.core.*;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.math.*;
import org.papervision3d.scenes.* ;
import org.papervision3d.objects.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.cameras.*;
import org.papervision3d.materials.*;
import org.papervision3d.materials.utils.*;
import org.papervision3d.view.*;
import org.papervision3d.render.*;
import org.papervision3d.materials.special.* ;
import org.papervision3d.events.*;
//
import caurina.transitions.Tweener;
import net.hires.debug.Stats;
//
public class Main extends BasicView {
//
//
//==========================
//var
//==========================
private var mouseDown:Boolean = false;
private var mousePos:Point;
private var pose:org.papervision3d.core.math.Matrix3D;
private var cube:Cube;
private var reset_button:Sprite;
private var rot:Object;
private var vector:Object;
//
//
//==========================
//コンストラクタ
//==========================
public function Main():void
{
super(240, 400, true, true, CameraType.TARGET);
rot = new Object();
rot.x = 0;
rot.y = 0;
vector = new Object();
vector.x = 0;
vector.y = 0;
//リセットボタン
reset_button = new Sprite();
reset_button.x = 10;
reset_button.y = 10;
addChild(reset_button);
reset_button.graphics.beginFill(0x000000, 1);
reset_button.graphics.drawRect(0, 0, 60, 30);
var t:TextField = new TextField();
//
t.x = 10;
t.y = 2;
t.text = "reset";
t.textColor = 0xffffff;
t.selectable = false;
//
var tf:TextFormat = new TextFormat();
tf.size = 18;
t.setTextFormat(tf);
//
reset_button.addChild(t);
reset_button.addEventListener(MouseEvent.CLICK, onButtonClick);
//
//addChild( new Stats() );
//
init3D();
}
//
//
//==========================
//init3D
//==========================
private function init3D():void
{
camera.x = 1500;
camera.y = 600;
camera.z = -1500;
camera.focus = 2000;
camera.zoom = 1;
//
var cm:ColorMaterial = new ColorMaterial(0x0099ff);
var wm:WireframeMaterial = new WireframeMaterial(0x33ffff);
var compo_material:CompositeMaterial = new CompositeMaterial();
compo_material.addMaterial(cm);
compo_material.addMaterial(wm);
cube = new Cube(new MaterialsList( { all:compo_material } ), 200, 100, 300);
scene.addChild(cube);
//
stage.addEventListener(MouseEvent.MOUSE_DOWN, mousedown);
startRendering();
}
//
//
//==========================
//onButtonClick
//==========================
private function onButtonClick(e:MouseEvent):void
{
removeEventListener(Event.ENTER_FRAME, throwing);
//
var m:org.papervision3d.core.math.Matrix3D = cube.transform;
// 回転軸ベクトル
var rv:Number3D = new Number3D( m.n32 - m.n23, m.n13 - m.n31, m.n21 - m.n12);
rv.normalize();
//
// 回転角
//Matrix3Dにtraceプロパティがなくなった(なんでだろ?)ので自作メソッドで対応
//var rad:Number = Math.acos((m.trace - 2 ) / 2);
var rad:Number = Math.acos((getTrace(m) - 2 ) / 2);
// 逆回転して元の位置に戻す回転行列
var r:org.papervision3d.core.math.Matrix3D = org.papervision3d.core.math.Matrix3D.rotationMatrix(rv.x, rv.y, rv.z, -rad);
//cube.transform = org.papervision3d.core.math.Matrix3D.multiply(r, cube.transform);
//
//Tweenerで姿勢制御
//------------
var tm:org.papervision3d.core.math.Matrix3D = org.papervision3d.core.math.Matrix3D.multiply(r, cube.transform);
//最初の姿勢クォータニオン生成
var pos1:Quaternion = Quaternion.createFromOrthoMatrix(cube.transform);
//最終的な姿勢クォータニオン生成
var pos2:Quaternion = Quaternion.createFromOrthoMatrix(tm);
pos1.normalize();
pos2.normalize();
//slerpを0→1にTweenさせるとアニメーションする
//Quaternion.slerp(最初の姿勢クォータニオン, 最終的な姿勢クォータニオン, slerp)
var extraObject:Object = {slerp:0};
cube.extra = extraObject;
Tweener.addTween(cube.extra, {time:1, slerp:1, onUpdate:function():void { cube.transform = Quaternion.slerp(pos1, pos2, extraObject.slerp).matrix }, onComplete:endTween } );
//------------
}
//
//
//==========================
//endTween
//==========================
private function endTween():void
{
}
//
//
//==========================
//mousedown
//==========================
private function mousedown(e:MouseEvent):void
{
mouseDown = true;
mousePos = new Point(stage.mouseX, stage.mouseY);
pose = org.papervision3d.core.math.Matrix3D.clone(cube.transform);
//
removeEventListener(Event.ENTER_FRAME, throwing);
//
stage.addEventListener(MouseEvent.MOUSE_MOVE, mousemove);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseup);
}
//
//
//==========================
//mousemove
//==========================
private function mousemove(e:MouseEvent):void{
if (mouseDown) {
var rot_buffer:Object = Object({x:rot.x, y: rot.y});
//
rot.x = stage.mouseX -mousePos.x;
rot.y = stage.mouseY - mousePos.y;
//
vector.x = rot.x - rot_buffer.x;
vector.y = rot.y - rot_buffer.y;
//
rotate();
}
}
//
//
//==========================
//mouseup
//==========================
private function mouseup(e:MouseEvent):void
{
mouseDown = false;
addEventListener(Event.ENTER_FRAME, throwing);
//
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mousemove);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseup);
}
//
//
//==========================
//throwing
//==========================
private function throwing(e:Event):void
{
vector.x *= 0.9;
vector.y *= 0.9;
//
if (Math.abs(vector.x) < 0.01 && Math.abs(vector.y) < 0.01) {
vector.x = 0;
vector.y = 0;
removeEventListener(Event.ENTER_FRAME, throwing);
}else {
rot.x += vector.x;
rot.y += vector.y;
}
//
rotate();
}
//
//
//==========================
//rotate
//==========================
private function rotate():void
{
// X方向(Y軸周り)に回転する回転行列
var my:org.papervision3d.core.math.Matrix3D = org.papervision3d.core.math.Matrix3D.rotationMatrix(0, 1, 0, -0.02 * rot.x);
// Y方向(X軸周り)に回転する回転行列
var mx:org.papervision3d.core.math.Matrix3D = org.papervision3d.core.math.Matrix3D.rotationMatrix(1, 0, 0, -0.02 * rot.y);
// 回転の合成
var m:org.papervision3d.core.math.Matrix3D = org.papervision3d.core.math.Matrix3D.multiply(mx, my);
cube.transform = org.papervision3d.core.math.Matrix3D.multiply(m, pose);
}
//
//
//==========================
//getTrace
//==========================
public function getTrace(m:org.papervision3d.core.math.Matrix3D):Number
{
return m.n11 + m.n22 + m.n33 + 1;
}
}
//
//
}