[BetweenAS3] Papervision Matrix3D Tween
/**
* Copyright yonatan ( http://wonderfl.net/user/yonatan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/1iHb
*/
// forked from nitoyon's [BetweenAS3] Random Text Tween
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.ui.Mouse;
import flash.ui.MouseCursor;
import org.libspark.betweenas3.easing.*;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.PaperPlane;
import org.papervision3d.view.BasicView;
[SWF (backgroundColor="0x000000")]
public class FlashTest extends BasicView {
public function FlashTest() {
_camera.zoom = 100;
Mouse.cursor = MouseCursor.BUTTON;
var light:PointLight3D;
light = new PointLight3D(false);
light.x = 0;
light.y = 100;
light.z = -1000;
var mat:FlatShadeMaterial = new FlatShadeMaterial(light, 0xFFCC44);
mat.doubleSided = true;
var p:PaperPlane = new PaperPlane(mat);
scene.addChild(p);
var dst:DisplayObject3D = new DisplayObject3D;
dst.x = 100;
dst.copyTransform(dst);
var tween:PVMatrixTween = new PVMatrixTween();
tween.target = p;
tween.easing = Sine.easeOut;
tween.matrix = dst.transform;
tween.time = 1;
function onClick(e:Event):void {
dst.x = -100 + 200*Math.random();
dst.y = -100 + 200*Math.random();
dst.z = -100 + 200*Math.random();
dst.scaleX = 1+Math.random();
dst.scaleY = 1+Math.random();
dst.scaleZ = 1+Math.random();
dst.rotationX = 360*Math.random();
dst.rotationY = 360*Math.random();
dst.copyTransform(dst);
tween.target = p; // reset initial matrix to the current one.
tween.play();
}
stage.addEventListener("click", onClick);
onClick(null);
startRendering();
}
}
}
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.core.easing.IEasing;
import org.libspark.betweenas3.core.ticker.ITicker;
import org.libspark.betweenas3.core.tweens.AbstractTween;
import org.libspark.betweenas3.core.tweens.IITween;
import org.papervision3d.core.math.Matrix3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.objects.DisplayObject3D;
class PVMatrixTween extends AbstractTween
{
/**
* static ITicker cache.
*/
private static var _ticker:ITicker;
/**
* initial Matrix3D storage.
*/
private var _start:Matrix3D;
/**
* DisplayObject3D.
*/
public function get target():DisplayObject3D { return _target; }
public function set target(value:DisplayObject3D):void {
value.copyTransform(value); // hack -- make sure the do3d's transform is up to date.
_start = Matrix3D.clone(value.transform);
_target = value;
}
private var _target:DisplayObject3D;
/**
* Tween easing.
*/
public function get easing():IEasing { return _easing; }
public function set easing(value:IEasing):void { _easing = value; }
private var _easing:IEasing;
/**
* Destination transform matrix.
*/
public function get matrix():Matrix3D { return _matrix; }
public function set matrix(value:Matrix3D):void { _matrix = value; }
private var _matrix:Matrix3D;
/**
* Set or get duration.
*/
public function get time():Number { return _duration; }
public function set time(value:Number):void { _duration = value; }
/**
* Constructor.
*
* @param duration sleep duration.
* @param ticker ticker object.
* @param position initial position.
*/
public function PVMatrixTween(ticker:ITicker = null, position:Number = 0) {
if (!_ticker) {
// create tmp tween to get the BetweenAS3's static ticker.
var tmpTween:IITween = BetweenAS3.parallel() as IITween;
_ticker = tmpTween.ticker;
}
super(ticker || _ticker, position);
}
/**
* 更新処理を行う。
*/
protected override function internalUpdate(time:Number):void
{
// check
if (!_target) { throw new Error("target is not set"); }
if (!_easing) { throw new Error("easing is not set"); }
if (!_matrix) { throw new Error("matrix is not set"); }
// get the factor (0.0~1.0)
var factor:Number = 0.0;
if (time > 0.0) {
if (time < _duration) {
factor = _easing.calculate(time, 0.0, 1.0, _duration);
}
else {
factor = 1.0;
}
}
// update the matrix
_target.copyTransform(interpolateMatrix3D(_start, _matrix, factor));
}
/**
* 3D utils
*/
private function interpolateMatrix3D(thisMat:Matrix3D,toMat:Matrix3D,percent:Number):Matrix3D{
// decomposition:
// we need to give Quaternion.createFromMatrix rotation-only matrices (with normalized axii),
// otherwise we choke on scaling matrices
var thisQuat:Quaternion = Quaternion.createFromMatrix( getRotationMatrix( thisMat ) );
var toQuat:Quaternion = Quaternion.createFromMatrix( getRotationMatrix( toMat ) );
var thisScale:Number3D = getScaleFromMatrix3D( thisMat );
var toScale:Number3D = getScaleFromMatrix3D( toMat );
var thisTranslation:Number3D = new Number3D( thisMat.n14, thisMat.n24, thisMat.n34 );
var toTranslation:Number3D = new Number3D( toMat.n14, toMat.n24, toMat.n34 );
// interpolation:
var scale_x:Number = thisScale.x*(1-percent) + toScale.x*percent;
var scale_y:Number = thisScale.y*(1-percent) + toScale.y*percent;
var scale_z:Number = thisScale.z*(1-percent) + toScale.z*percent;
var tx:Number = thisTranslation.x*(1-percent) + toTranslation.x*percent;
var ty:Number = thisTranslation.y*(1-percent) + toTranslation.y*percent;
var tz:Number = thisTranslation.z*(1-percent) + toTranslation.z*percent;
var q:Quaternion = Quaternion.slerp( thisQuat, toQuat, percent );
// recomposition:
var x:Number = q.x;
var y:Number = q.y;
var z:Number = q.z;
var w:Number = q.w;
var ret:Matrix3D = new Matrix3D;
// apparently mxmlc optimizes away the duplicate multiplications,
// so there's no need to do it manually
ret.n11 = (1-2*y*y-2*z*z)*scale_x;
ret.n21 = (2*x*y+2*w*z)*scale_x;
ret.n31 = (2*x*z-2*w*y)*scale_x;
ret.n41 = 0;
ret.n12 = (2*x*y-2*w*z)*scale_y;
ret.n22 = (1-2*x*x-2*z*z)*scale_y;
ret.n32 = (2*y*z+2*w*x)*scale_y;
ret.n42 = 0;
ret.n13 = (2*x*z+2*w*y)*scale_z;
ret.n23 = (2*y*z-2*w*x)*scale_z;
ret.n33 = (1-2*x*x-2*y*y)*scale_z;
ret.n43 = 0;
ret.n14 = tx;
ret.n24 = ty;
ret.n34 = tz;
ret.n44 = 1;
return ret;
}
// scale values can't be negative!
private function getScaleFromMatrix3D( m:Matrix3D ):Number3D {
var x:Number = Math.sqrt( m.n11*m.n11 + m.n21*m.n21 + m.n31*m.n31 );
var y:Number = Math.sqrt( m.n12*m.n12 + m.n22*m.n22 + m.n32*m.n32 );
var z:Number = Math.sqrt( m.n13*m.n13 + m.n23*m.n23 + m.n33*m.n33 );
return( new Number3D( x, y, z ) );
}
// returns a rotation-only matrix (no scale/translate)
private function getRotationMatrix( m:Matrix3D ):Matrix3D {
var scale:Number3D = getScaleFromMatrix3D( m );
return( new Matrix3D ( [
m.n11 / scale.x, m.n12 / scale.y, m.n13 / scale.z, 0,
m.n21 / scale.x, m.n22 / scale.y, m.n23 / scale.z, 0,
m.n31 / scale.x, m.n32 / scale.y, m.n33 / scale.z, 0,
0, 0, 0, 1
] ) );
}
}