simple 3D 06 (PV3D version.)
http://wonderfl.net/c/tpsjをPV3Dで書き直してみました。
PV3Dをはじめ、各種3Dライブラリの凄さを再確認。
/**
* Copyright sakef ( http://wonderfl.net/user/sakef )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/20Y9
*/
/*
http://wonderfl.net/c/tpsjをPV3Dで書き直してみました。
PV3Dをはじめ、各種3Dライブラリの凄さを再確認。
*/
package
{
import com.bit101.components.Label;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.Security;
import net.hires.debug.Stats;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.view.BasicView;
[SWF(width="465", height="465", backgroundColor="0xffffff")]
public class simple3d_06_pv3d extends BasicView
{
// サイズ・中心等
private static const SIZE:Number=90;
private static const RADIUS:int = 300;
private static const CAMERA_RADIUS:int=600;
private static const CENTER_X:int=465 >> 1;
private static const CENTER_Y:int=465 >> 1;
// 画像検索に使うキーワード
private static const KEYWORD:String = "sea";
// カメラ用
private var isMouseDown:Boolean;
private var oldX:Number;
private var oldY:Number;
private var targetRot:Number;
private var targetPitch:Number;
private var rot:Number;
private var pitch:Number;
// コンテナとPlaneの数
private var container:Array;
private var n_planes:int;
// 画像用
private var count:int;
private var label:Label;
public function simple3d_06_pv3d()
{
super(0,0,true,true);
// ステージ設定・マウス関係停止
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
stage.quality=StageQuality.HIGH;
stage.frameRate=30;
mouseChildren=false;
mouseEnabled=false;
// Stats追加
addChild(new Stats());
// 変数の初期化
container = [];
oldX=oldY=rot=pitch=n_planes=count=0;
targetPitch=90;
targetRot=180;
isMouseDown=false;
// カメラの初期化
camera.x = 0;
camera.y = 0;
camera.z = CAMERA_RADIUS;
// Planeを球体に並べる
var radian:Number = Math.PI/180;
var H:int=(RADIUS * Math.PI) / SIZE;
var theta1:Number=90;
for(var i:int=0; i < H; i++)
{
var theta2:Number=0;
var pn:int=Math.floor((2 * RADIUS * Math.PI * Math.cos(theta1 * radian)) / SIZE);
for(var j:int=0; j < pn; j++)
{
var plane:Plane = new Plane(null, SIZE, SIZE);
plane.rotationX=-theta1;
plane.rotationY=theta2;
plane.x=RADIUS * Math.cos(theta1 * radian) * Math.sin(theta2 * radian);
plane.y=RADIUS * Math.sin(theta1 * radian);
plane.z=RADIUS * Math.cos(theta1 * radian) * Math.cos(theta2 * radian);
theta2+=360 / pn;
container[n_planes] = plane;
scene.addChild(plane);
n_planes ++;
}
theta1-=180 / H;
}
// ロード状況用ラベルの初期化
label = new Label(this, CENTER_X-80, CENTER_Y-50);
label.scaleX = label.scaleY = 2;
label.text="Loading images from flickr.\n" + count.toString() + "\t/ " + n_planes.toString();
// ポリシーファイルの読み込み
Security.loadPolicyFile("http://api.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");
// Flickrから画像のロード
var api_loader:URLLoader=new URLLoader;
api_loader.addEventListener(Event.COMPLETE, onCompleteAccessAPI);
api_loader.load(new URLRequest("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=25c5f4bc0087edf4d6efdc567daf0a64&tags="+KEYWORD + "&per_page=" + n_planes));
}
// FlickrAPIへのアクセスが成功したら実行する関数
private function onCompleteAccessAPI(e:Event):void
{
var api_loader:URLLoader=e.target as URLLoader;
api_loader.removeEventListener(Event.COMPLETE, onCompleteAccessAPI);
// XMLのパースと画像のURLの作成・ロード
var xml:XML=XML(api_loader.data);
if (xml.@stat == "ok")
{
for each(var photo:XML in xml.photos.photo)
{
var url:String="http://farm" + photo.@farm + ".static.flickr.com/" + photo.@server + "/" + photo.@id + "_" + photo.@secret + ".jpg";
var img_loader:Loader=new Loader();
img_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompletePhotoLoad);
img_loader.load(new URLRequest(url), new LoaderContext(true));
}
}
}
// 画像のロードが終わったら実行する関数
private function onCompletePhotoLoad(e:Event):void
{
var img_loader:Loader=(e.target as LoaderInfo).loader;
img_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompletePhotoLoad);
// ロードした画像をPlaneに反映
var plane:Plane = container[count] as Plane;
var mat:BitmapMaterial = new BitmapMaterial((img_loader.content as Bitmap).bitmapData, true);
mat.doubleSided = true;
plane.material = mat;
count ++;
label.text="Loading images from flickr.\n" + count.toString() + "\t/ " + n_planes.toString();
// 画像が全部ロードし終わったらレンダリング開始
if(count == n_planes)
{
label.visible = false;
addEventListener(Event.ENTER_FRAME, onFrame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
// 計算更新用関数
private function onFrame(e:Event):void
{
// カメラの移動
if (isMouseDown)
{
targetRot+=(mouseX - oldX) * 0.2;
targetPitch+=(mouseY - oldY) * 0.2;
targetPitch=(targetPitch > -90) ? (targetPitch) : (-90);
targetPitch=(targetPitch < 90) ? (targetPitch) : (90);
oldX=mouseX;
oldY=mouseY;
}
rot+=(targetRot - rot) * 0.1;
pitch+=(targetPitch - pitch) * 0.1;
pitch=(pitch > -90) ? (pitch) : (-90);
pitch=(pitch < 90) ? (pitch) : (90);
camera.x=CAMERA_RADIUS * Math.sin(rot * Math.PI / 180);
camera.y=CAMERA_RADIUS * Math.sin(pitch * Math.PI / 180);
camera.z=CAMERA_RADIUS * Math.cos(rot * Math.PI / 180);
// レンダリング
singleRender();
}
// マウスダウン時の関数
private function onMouseDown(e:MouseEvent):void
{
isMouseDown=true;
oldX=mouseX;
oldY=mouseY;
}
// マウスアップ時の関数
private function onMouseUp(e:MouseEvent):void
{
isMouseDown=false;
}
}
}