In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Matrix3D.transformVectors による 3D 表現の雛形

MaMatrix3D.transformVectors による 3D 表現の雛形
@author YOSHIDA, Akio (Aquioux)
解説ページ http://aquioux.blog48.fc2.com/blog-entry-648.html
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cA3I
 */

// forked from Aquioux's Utils3D.projectVectors による 3D 表現の雛形
package {
	import flash.display.Sprite;
	import flash.events.Event;
	[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
	/**
	 * MaMatrix3D.transformVectors による 3D 表現の雛形
	 * @author YOSHIDA, Akio (Aquioux)
	 * 解説ページ http://aquioux.blog48.fc2.com/blog-entry-648.html
	 */
	public class Main extends Sprite {

		public function Main() {
			// 座標データを生成
			var data:DataFactory1 = new DataFactory1(200.0);	// 環
			//var data:DataFactory2 = new DataFactory2(100.0);	// 立方体
			data.addEventListener(Event.COMPLETE, completeHandler);
			data.start();
		}

		private function completeHandler(event:Event):void {
			// Model を生成
			var model:Model = new Model(event.target.verts.concat());
			model.offsetX = stage.stageWidth / 2;
			model.offsetY = stage.stageHeight / 2;
			model.offsetZ = -100;
			model.speed = 0.01;
			//model.fieldOfView = 55;
			model.fieldOfView = 75;

			// View を生成
			var view:View = new View(model);
			addChild(view);
			
			// Controller を生成
			var controller:Controller = new Controller(model);
			controller.setup(stage);
		}
	}
}


	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	class DataFactory1 extends EventDispatcher {
		// 外部に渡すデータ
		public function get verts():Vector.<Number> { return _verts; }
		private var _verts:Vector.<Number> = new Vector.<Number>();

		private var length:Number;
		public function DataFactory1(length:Number) {
			this.length = length;
		}

		internal function start():void{
			var NUM_OF_DOT:uint = 8;
			var baseRadian:Number = Math.PI * 2 / NUM_OF_DOT;
			for (var i:int = 0; i < NUM_OF_DOT; i++) {
				var point:Point = Point.polar(length, baseRadian * i);
				_verts.push(point.x, point.y, 0);
			}
			_verts.fixed = true;

			dispatchEvent(new Event(Event.COMPLETE));
		}
	}


	import flash.events.Event;
	import flash.events.EventDispatcher;
	class DataFactory2 extends EventDispatcher {
		// 外部に渡すデータ
		public function get verts():Vector.<Number> { return _verts; }
		private var _verts:Vector.<Number> = new Vector.<Number>();

		private var length:Number;
		public function DataFactory2(length:Number) {
			this.length = length;
		}
		
		internal function start():void {
			_verts.push( length,  length,  length);
			_verts.push( length, -length,  length);
			_verts.push(-length, -length,  length);
			_verts.push(-length,  length,  length);
			_verts.push( length,  length, -length);
			_verts.push( length, -length, -length);
			_verts.push(-length, -length, -length);
			_verts.push(-length,  length, -length);
			_verts.fixed = true;

			dispatchEvent(new Event(Event.COMPLETE));
		}
	}


	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Matrix3D;
	import flash.geom.PerspectiveProjection;
	import flash.geom.Vector3D;
	import flash.geom.Utils3D;
	class Model extends EventDispatcher {
		// 外部へ渡すデータ
		public function get data():Vector.<Number> { return _data; }
		private var _data:Vector.<Number>;

		// 外部から受けるデータ

		// 引数として受ける
		private var vin:Vector.<Number>;

		// セッターで受ける
		// X座標オフセット
		public function set offsetX(value:Number):void {
			_offsetX = value;
		}
		private var _offsetX:Number = 0;
		// Y座標オフセット
		public function set offsetY(value:Number):void {
			_offsetY = value;
		}
		private var _offsetY:Number = 0;
		// Z座標オフセット
		public function set offsetZ(value:Number):void {
			_offsetZ = value;
		}
		private var _offsetZ:Number = 500;
		// マウス位置を Matrix3D の回転に変換するときに使用する変数
		public function set speed(value:Number):void {
			_speed = value;
		}
		private var _speed:Number = 0.025;
		// 内部パースペクティブプロジェクションの fieldOfView
		public function set fieldOfView(value:Number):void {
			projection.fieldOfView = value;
		}
		private var _fieldOfView:Number;

		private const NUM_OF_BLOCK:uint = 3;
		private var vx:Number = 0;
		private var vy:Number = 0;
		// Controller から呼び出される
		internal function update(valueX:Number, valueY:Number):void {
			// Controller から渡された値を加工
			vx += (_offsetX - valueX) * _speed;
			vy -= (_offsetY - valueY) * _speed;

			// Controller から渡された値を回転に変換
			m.identity();
			m.appendRotation(vy, Vector3D.X_AXIS);
			m.appendRotation(vx, Vector3D.Y_AXIS);
			m.appendTranslation(0, 0, _offsetZ);

			// 外部データに回転を適用
			m.transformVectors(vin, vout);

			// 回転を適用した外部データを zsort
			var n:uint = vout.length / NUM_OF_BLOCK;
			for (var i:int = 0; i < n; i++) {
				var vector3D:Vector3D = new Vector3D();
				vector3D.x = vout[i * NUM_OF_BLOCK];
				vector3D.y = vout[i * NUM_OF_BLOCK + 1];
				vector3D.z = vout[i * NUM_OF_BLOCK + 2];
				vector3D.w = projection.focalLength / (projection.focalLength + vector3D.z);
				vector3D.project();
				sorted[i] = vector3D;
			}
			sorted.sortOn("z", Array.NUMERIC);
			
			// sort した Array から必要なデータを抽出・生成し、Vector.<Number> に代入
			for (i = 0; i < n; i++) {
				vector3D = sorted[i];
				_data[i * NUM_OF_BLOCK]     = vector3D.x + _offsetX;
				_data[i * NUM_OF_BLOCK + 1] = vector3D.y + _offsetY;
				_data[i * NUM_OF_BLOCK + 2] = 1 / vector3D.w;
			}
			
			// リスナー(View)へ通知
			notifyListeners();
		}


		private var vout:Vector.<Number>;
		private var sorted:Array;
		private var projection:PerspectiveProjection;
		private var m:Matrix3D;
		public function Model(vin:Vector.<Number>) {
			// 外部から受けるデータを引数として受ける
			this.vin = vin;
			var n:uint = vin.length;
			
			// 外部に渡すデータの初期化
			_data = new Vector.<Number>(n, true);

			// 内部でのみ使用する Vector の初期化
			vout = new Vector.<Number>(n, true);
			
			// 内部でのみ使用する Array の初期化
			sorted = [];
			
			// 内部でのみ使用する PerspectiveProjection の生成
			projection = new PerspectiveProjection();
			
			// 内部でのみ使用する外部データに適用する Matrix3D
			m = new Matrix3D();
		}

		// View へ伝える
		private function notifyListeners():void {
			dispatchEvent(new Event(Event.CHANGE));
		}
	}


	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Vector3D;
	class View extends Sprite {

		private function changeHandler(event:Event):void {
			// Model からデータを受ける
			var data:Vector.<Number> = model.data;

			// 描画
			canvas.graphics.clear();
			const NUM_OF_BLOCK:uint = 3;
			var n:uint = data.length / NUM_OF_BLOCK;
			for (var i:int = 0; i < n; i++) {
				var posX:Number  = data[i * NUM_OF_BLOCK];
				var posY:Number  = data[i * NUM_OF_BLOCK + 1];
				var scale:Number = data[i * NUM_OF_BLOCK + 2];
				var c:uint = 0xFF * scale;
				c = c > 0xFF ? 0xFF : c;
				canvas.graphics.beginFill(c << 16 | c << 8 | c);
				canvas.graphics.drawCircle(posX, posY, 20 * scale);
				canvas.graphics.endFill();
			}
		}

		private var model:Model;
		public function View(model:Model) {
			this.model = model;
			this.model.addEventListener(Event.CHANGE, changeHandler);
			addEventListener(Event.ADDED_TO_STAGE, setup);
		}
		private var canvas:Sprite;
		private function setup(event:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, setup);
			canvas = new Sprite();
			addChild(canvas);
		}
	}


	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	/**
	 * ENTER_FRAME のタイミングでマウスの位置を Model に渡す
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Controller {

		private var stage:Stage;
		internal function setup(stage:Stage):void {
			this.stage = stage;
			stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}

		private function enterFrameHandler(event:Event):void {
			model.update(stage.mouseX, stage.mouseY);
		}

		private var model:Model;
		public function Controller(model:Model) {
			this.model = model;
		}
	}