Home > 梅原 > [PV3D]CircleFlow(はじめてのPapervision3D)

[PV3D]CircleFlow(はじめてのPapervision3D)

20090708
Category:梅原 /Tags:,

[PV3D]CircleFlow(はじめてのPapervision3D)Flashの3Dにおいて、Papervision3Dって共通語になっているような気がしたので勉強開始。
BasicViewを使っているせいもあるかもしれないけど「めんどくさそうなこと」をずいぶんうまくつつみこんでいるなーというのが第一印象。でもこれ、この簡単そうな印象のまま、実案件で泣いている人が世界中にいそうな気がすけるけど、まあ余計なお世話か。

*注*
筆者及び水玉製作所はPapervision3Dの経験は薄いものの、弊社オリジナルエンジンによるFlashの3D案件は大手ゲームメーカ、イベントホール、研究所ほか複数受注納品しています。視野を広げ、対応力を高めるためにPapervision3Dの勉強をはじめました。

 
とりあえず、弊社立野のエントリーを読みながら入門。
http://www.mztm.jp/wp/2009/05/22/studypapervision3dを使ってみる1/
http://www.mztm.jp/wp/2009/06/01/studypapervision3d-02-360度のパノラマ画像を回してみる/
とりあえずコピペして動かせて第一歩は踏めた。やった!
ありがとう立野君。次は上のエントリーに無駄なことがだいぶあることに気がついてね!(はーと)
まあ、人のこと言えないけどw

さらにGoogle検索して動かしてみる。第二歩目に進んだ。

■Papervision3Dやってみる
http://rainyday.jp/blog/flash/pv3d/75.html

プリミティブを簡単に動かせるのはいいことだ。良くできている。
特に面白いと思ったのは。テクスチャの管理とファイルローダーを一体化させているところ。

var m:BitmapFileMaterial = new BitmapFileMaterial("hoge.jpg");

あとはEvent.ENTER_FRAMEが最初から走っているところ。

override protected function onRenderTick(event:Event=null):void {
	mySphere.rotationX += 0.5;
	super.onRenderTick(event);
}

なるほど。

さらにGoogle検索して動かしてみる。第三歩目。
■WonderflでPapervision3D
http://clockmaker.jp/blog/2009/02/wonderfl_papervision3d/
プリミティブに対してひと味加えて、やってみたい感を増量させている。さすが。

んで、「被写界深度デモ」をフォークして作ってみたのが以下。

▼Wonderfl

先日公開の物欲フローのPV3D版。
とりあえず、動かすことに専念できたのは良かったんだけど、どうしても、かゆいところに手が届かない感がある。

わからないところ
・マウスクリックでどのアイテムがクリックされたかを知る。
・ビットマップにスムージングをかける。

▼ActionScript AS3(FP9)

/**
* Papervision3Dで被写界深度
* 参照: http://clockmaker.jp/blog/2008/07/pv3d_gw_blur/

動き方自体は前に作ったことがあったので、それのPV3D版。

うーん、とりあえずPV3Dが便利なのはわかった。

次の課題
・マウスクリックでどのアイテムがクリックされたかを知る。
・ビットマップにスムージングをかける。

*/
package
{
	import flash.display.*;
	import flash.events.*;
	import flash.filters.*;

	import org.papervision3d.view.*;
	import org.papervision3d.materials.*;
	import org.papervision3d.objects.*;
	import org.papervision3d.objects.primitives.*

	[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]

	public class Test extends BasicView
	{
		// const vars
		static private const OBJ_LENGTH   :int = 20;
		static private const CIRCLE_RANGE :int = 570;
		private var stageWidth:int = stage.stageWidth;
		private var stageHeight:int = stage.stageHeight;
		private var loadFiles_array:Array;
		private var MultiLoader:MultiLoaderClass = new MultiLoaderClass("http://mztm.heteml.jp/crossdomain.xml");
		private var data_xml:XML;
		//private var shadow

		// 3d vars
		private var list :Array = []
		private var wrap :D isplayObject3D;
		/**
		 * Constructor
		 */
		public function Test(){
			loadFiles_array = MultiLoader.setLoad(["http://mztm.heteml.jp/umhr/3d/arss/data.xml"],onXMLComp);

		}
		public function onXMLComp():void
		{
			var i:int;
			var jpg_array:Array = new Array();
			data_xml = XML(loadFiles_array[0].data);
			var _length:int = data_xml.items.item.length();
			for (i = 0; i < _length; i++) {
				if(data_xml.items.item[i].jpg != ""){
					var _array:Array = String(data_xml.items.item[i].jpg).split('/');
					var jpg_url:String = "http://mztm.heteml.jp/umhr/3d/arss/revolution/"+_array.pop();
					jpg_url = jpg_url.replace(/%/g,'');
					jpg_array.push(jpg_url);
				}
			}

			camera.x		 = 0;
			camera.y		 = 200;
			camera.z		 = 1000;
			camera.rotationX = 5;

			// wrap
			wrap = new DisplayObject3D();
			scene.addChild(wrap);

			for (i = 0; i < OBJ_LENGTH; i++)
			{
				var rot:Number = 360 * i / OBJ_LENGTH ;

				var m : BitmapFileMaterial = new BitmapFileMaterial(jpg_array[i+int(Math.random()*120)]);
				//var m:ColorMaterial = new ColorMaterial(0x0066CC*i);
				m.doubleSided = true;

				var o:Plane = new Plane(m, 180, 180,2,2);
				o.x = CIRCLE_RANGE * Math.sin(rot * Math.PI / 180);
				o.z = CIRCLE_RANGE * Math.cos(rot * Math.PI / 180);

				if(i > OBJ_LENGTH/2){
					o.rotationY = rot-90;
				}else{
					o.rotationY = rot+90;
				}
				o.useOwnContainer = true; //ココ重要

				// 配列に追加 & wrapの子供にする
				list.push(wrap.addChild(o));
			}

			addEventListener(Event.ENTER_FRAME, loop);
			startRendering();
			//addEventListener(MouseEvent.MOUSE_DOWN,DOUBLE_CLICK);
			//MouseUnderPoint.isNamed = true;
			//function DOUBLE_CLICK(e:MouseEvent):void{
				//trace(MouseUnderPoint.getObject(stage).name);
			//}
		}

				// loop
		private function loop(event:Event):void
		{
			var mouseX:Number = Math.min(Math.max(stage.mouseX,0),stageWidth)-stageWidth/2;
			var mouseY:Number = Math.min(Math.max(stage.mouseY,0),stageHeight)-stageHeight/2;
			camera.y = mouseY;
			wrap.yaw(mouseX/200);

			// 被写界深度
			for (var i:int = 0; i < list.length; i++)
			{
				var o:DisplayObject3D = list[i] as DisplayObject3D;
				var CIRCLE_RANGE_oSceneZ:Number = (CIRCLE_RANGE - o.sceneZ);

				if(CIRCLE_RANGE_oSceneZ< 30){
					if(o.sceneX < 0){
						o.rotationY =360 * i / OBJ_LENGTH + CIRCLE_RANGE_oSceneZ*3-180;
					}else{
						o.rotationY =360 * i / OBJ_LENGTH - CIRCLE_RANGE_oSceneZ*3-180;
					}
				}else if((CIRCLE_RANGE*2-1) < CIRCLE_RANGE_oSceneZ){
					if(o.sceneX < 0){
						o.rotationY =360 * i / OBJ_LENGTH + 90-180;
					}else{
						o.rotationY =360 * i / OBJ_LENGTH - 90-180;
					}
				}
				var blur:Number = Math.round(CIRCLE_RANGE_oSceneZ / 100);
				o.filters = [new BlurFilter(blur, blur, 2)];
			}
		}
	}
}

class MultiLoaderClass{
	import flash.system.Security;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.display.Loader;
	//import flash.display.LoaderInfo;

	private var onComplete:Function = function():void{};
	private var loadNum:int;
	private var loadCompNum:int;

	public function MultiLoaderClass(_str:String = null){
		if(_str != null){
			Security.loadPolicyFile(_str);
		}
	}

	public function setLoad(__item_array:Array,_onComp:Function = null):Array{
		loadCompNum = loadNum = 0;
		onComplete = _onComp;
		var _array:Array = new Array();
		var _length:int = __item_array.length;
		for (var i:int = 0; i < _length; i++) {
			if(__item_array[i] == null){continue};
			var _extension:String = __item_array[i].substr(-4,4).toLowerCase();//拡張子を取り出す。
			if(_extension == ".xml"){
				loadNum ++;
				_array[i] = fnURLLoader(__item_array[i]);
			}else if(_extension == ".jpg" || _extension == ".png" || _extension == ".gif"){
				loadNum ++;
				_array[i] = fnLoader(__item_array[i]);
			}else{
				//_array[i] = null;
			}
		}
		return _array;
	}
	private function fnURLLoader(__url:String):URLLoader{
		var _loader : URLLoader = new URLLoader();
		_loader.load(new URLRequest(__url));
		_loader.addEventListener (Event.COMPLETE,completeHandler);
		_loader.addEventListener (IOErrorEvent.IO_ERROR, ioErrorHandler);
		return _loader;
	}

	private function fnLoader(__url:String):Loader{
		var _loader:Loader = new Loader();
		_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
		_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		_loader.load(new URLRequest(__url));
		//_loader.name = __url;
		return _loader;
	}

	private function completeHandler(event:Event = null):void {
		loadCompNum ++;
		if(loadCompNum == loadNum){
			onComplete();
		}
		//var loaderInfo:LoaderInfo=event.currentTarget as LoaderInfo;
		//var loader:Loader=loaderInfo.loader;
		//addChild(loader);
	}

	private function ioErrorHandler(event:IOErrorEvent):void {
		//event.text = "Error #2035: URL が見つかりません。 URL: file:///~~~~~";
		//event.text = "Error #2036: 読み込みが未完了です。 URL: http://~~~~~";
		//から、URLのみを取り出す。
		//trace(String(event.text).substr(String(event.text).indexOf(" URL: ")+6),"*****");
		completeHandler();
	}
}

//import flash.geom.Point;
//class MouseUnderPoint {
//	public static var isNamed:Boolean;
//	public static var isPassFn:Function = function(obj:Object):Boolean { return true };
//	public static var target:Object;
//	public static function getObject(argTarget:Object = null):Object {
//		if(!argTarget){
//			if(target){
//				argTarget = target;
//			}else{
//				trace("targetが指定されていません");
//				return null;
//			}
//		}
//		var list:Array = argTarget.getObjectsUnderPoint(argTarget.localToGlobal(new Point(argTarget.mouseX , argTarget.mouseY)));
//		var l:int = list.length;
//		if(l > 0){
//			/* 上から順にnameを確認 */
//			for (var i:int = l-1; i>=0; i--) {
//				var str:String = list[i].name;
//				if (isNamed && str.substr(0, 8) == "instance" && !isNaN(parseInt(str.substr(8)))) {
//					/**
//					 * nameを設定をしてないと、instance123とかの名前になる。
//					 * よって、この関数を使うには「instance123」(数字部は恐らくAVM起動後のinstanceの数)以外の名前にすること。
//					 * nameを付けないオブジェクトに対して動作を指定したい場合はこちらに記入。
//					 */
//				}else if (!isPassFn(list[i])) {
//					/* isPassFnの関数の条件がfalseの時にはここにくる。*/
//				}else{
//					return list[i];
//				}
//			}
//		};
//		return null;
//	}
//}

関連記事:

Comments are closed.