// forked from yonatan's forked from: [BetweenAS3] Papervision Matrix3D Tween // forked from yonatan's [BetweenAS3] Papervision Matrix3D Tween // forked from nitoyon's [BetweenAS3] Random Text Tween package { import flash.display.Sprite; import flash.events.Event; import flash.utils.*; import org.libspark.betweenas3.easing.*; import org.libspark.betweenas3.*; 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; import frocessing.color.ColorHSV; [SWF (backgroundColor="0xffffff")] public class FlashTest extends BasicView { public function FlashTest() { _camera.zoom = 30; var light:PointLight3D; light = new PointLight3D(false); light.y = 1000; var planes:Array = []; for(var i:uint=0; i < 64; i++) { var hsv:ColorHSV = new ColorHSV(i*4, 0.9, 0.8); var mat:FlatShadeMaterial = new FlatShadeMaterial(light, hsv.value32); mat.doubleSided = true; var p:PaperPlane = new PaperPlane(mat); scene.addChild(p); planes.push(p); } function doTweens():void { var sx:Number = Math.random()*3; var sy:Number = Math.random()*3; var sz:Number = Math.random()*2; var yaw:Number = Math.random()*1000; var pitch:Number = Math.random()*1200; var dist:Number = Math.random()*500 + 250; var lookAt0:Boolean = Math.random() < 0.5; for(var i:uint=0; i < planes.length; i++) { var n:Number = i/planes.length - 0.5; var dst:DisplayObject3D = new DisplayObject3D; dst.yaw(yaw-yaw*n); dst.pitch(pitch-pitch*n); dst.moveForward(dist); dst.scaleX = sx; dst.scaleY = sy; dst.scaleZ = sz; if(lookAt0) { dst.lookAt(DisplayObject3D.ZERO); } dst.copyTransform(dst); var tween:PVMatrixTween = new PVMatrixTween(); tween.target = planes[i]; tween.easing = Sine.easeOut; tween.matrix = dst.transform; tween.time = 1; BetweenAS3.delay(tween, Math.abs(i-32)*20/1000).play(); } } setInterval(doTweens, 1750); addEventListener("enterFrame", function(e:*):void { light.x = _camera.x = Math.sin(getTimer()/3000) * 1000; light.z = _camera.z = Math.cos(getTimer()/3000) * 1000; }); 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 ] ) ); } } forked from: forked from: [BetweenAS3] Papervision Matrix3D Tween