forked from: Alternativa3D Cover Flow
勝手に何でもAlternativa3Dで作っちゃおうのコーナー
今回は、りんごが好きな人は、なんとなく見た事ある、サファリな、あれですw
仕事で少し前にPv3Dで作ったものを、alternativa3Dに移植してみました。
サンプルでは、MovieClipMaterialを使用し、各loadingをTexture内で個別に行いましたが、
正直、パフォーマンスが悪いです。
素直にloadingのprogress処理をまとめて、すべてloadingし終わってから、textureMaterialで作成する方が、パフォーマンスはあがると思います。
さらに
textureを操作したい場合、実は・・・
alternativa3DDocには書かれていませんが、TextureMaterialには、
alternativa3d function draw (camera:Camera3D, skin:Skin, vertexCount:uint, vertices:Array):void
alternativa3d function clear (skin:Skin):void
なんてのが、あります。
参照: http://docs.alternativaplatform.com/display/TDEN/Creating+materials
TextureMaterialを継承して、直接drawの中でSkinをいじればさらに、高速化します。
が、ちょっとあまりにDeep。w
そのうち、気が向いたらTipsアップします(たぶん、フラットシェーディングとかの改良版として)。
@narutohyper
Alternativa3D を簡単に扱うためのベーシックテンプレート
@author Yasu (clockmaker)
/**
* Copyright hellolight ( http://wonderfl.net/user/hellolight )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wUxs
*/
// forked from narutohyper's Alternativa3D Cover Flow
// forked from clockmaker's [Alternativa3D] Basic Template
package {
import alternativ5.engine3d.materials.WireMaterial;
import alternativ5.engine3d.primitives.Box;
import alternativ5.engine3d.events.MouseEvent3D
import alternativ5.types.Point3D;
import alternativ5.utils.*
import flash.display.Sprite;
import flash.utils.Dictionary;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.TextField
import flash.text.TextFieldAutoSize
import flash.text.TextFormat
import caurina.transitions.Tweener;
[SWF(width = 800, height = 600, frameRate = 30, backgroundColor="0xFFFFFF")]
/*
勝手に何でもAlternativa3Dで作っちゃおうのコーナー
今回は、りんごが好きな人は、なんとなく見た事ある、サファリな、あれですw
仕事で少し前にPv3Dで作ったものを、alternativa3Dに移植してみました。
サンプルでは、MovieClipMaterialを使用し、各loadingをTexture内で個別に行いましたが、
正直、パフォーマンスが悪いです。
素直にloadingのprogress処理をまとめて、すべてloadingし終わってから、textureMaterialで作成する方が、パフォーマンスはあがると思います。
さらに
textureを操作したい場合、実は・・・
alternativa3DDocには書かれていませんが、TextureMaterialには、
alternativa3d function draw (camera:Camera3D, skin:Skin, vertexCount:uint, vertices:Array):void
alternativa3d function clear (skin:Skin):void
なんてのが、あります。
参照: http://docs.alternativaplatform.com/display/TDEN/Creating+materials
TextureMaterialを継承して、直接drawの中でSkinをいじればさらに、高速化します。
が、ちょっとあまりにDeep。w
そのうち、気が向いたらTipsアップします(たぶん、フラットシェーディングとかの改良版として)。
@narutohyper
*/
/**
* Alternativa3D を簡単に扱うためのベーシックテンプレート
* @author Yasu (clockmaker)
*/
public class SimpleDemo extends Sprite {
private var dataXml:XML =
<menu>
<imgurl>1.png</imgurl>
<imgurl>2.png</imgurl>
<imgurl>3.png</imgurl>
<imgurl>4.png</imgurl>
<imgurl>5.png</imgurl>
<imgurl>6.png</imgurl>
</menu>;
private var plateArray:Array;
private var maxPage:uint=0;
private var nextPage:int=0;
private var nowPage:int=-1;
private var defWidth:Number=580
private var defHeight:Number=320;
private var startPage:uint=3;
private var title:TextField
public function SimpleDemo():void {
//FPS.init(stage);
// テンプレートを作成します
var template:BasicTemplate = new BasicTemplate();
addChild(template);
template.camera.x = 0;
template.camera.y = -600;
template.camera.z = 150;
template.camera.zoom = 100;
template.camera.rotationX = MathUtils.toRadian(-90);//-1.6;
template.camera.rotationZ = 0;
template.camera.fov = MathUtils.toRadian(90)
//取り込んだXMLデータの中の画像URLで画像を読み込む
plateArray = new Array();
for each (var item:String in dataXml.imgurl) {
plateArray.push(new mirrorPlane(new LoadTextureMaterial(item,defWidth),defWidth,defHeight))
}
maxPage=plateArray.length
// 3Dシーンのルートに追加します
for (var i:uint=0;i<maxPage;i++) {
template.scene.root.addChild(plateArray[i]);
plateArray[i].id=i
plateArray[i].rotationX=MathUtils.toRadian(-90)
plateArray[i].coords=new Point3D((i-maxPage/2)*240,0,0)
plateArray[i].addEventListener(mirrorPlane.CLICK,onPlateClick);
}
changePage(startPage,1)
//プリミティブのロールオーバー、クリックを有効にする為
template.view.buttonMode = true;
template.view.interactive = true;
//送りButtonと戻りButtonの作成
//makeInterface()
// Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
// レンダリング前に実行したい処理を記述します。
template.onPreRender = function():void {
//template.cameraContoller.lookAt(new Point3D());
}
}
private function makeInterface():void {
var trans:String="linear";
var action:Boolean= true;
//送りButtonと戻りButtonの作成
//長いけど△書いてるだけ------------------------------
var goBt:Sprite=new Sprite()
var backBt:Sprite=new Sprite()
var goArrow:Sprite=new Sprite()
var backArrow:Sprite=new Sprite()
goArrow.graphics.beginFill(0x666666,1)
goArrow.graphics.moveTo(-10,-10)
goArrow.graphics.lineTo(10,0)
goArrow.graphics.lineTo(-10,10)
goArrow.graphics.endFill()
backArrow.graphics.beginFill(0x666666,1)
backArrow.graphics.moveTo(10,-10)
backArrow.graphics.lineTo(-10,0)
backArrow.graphics.lineTo(10,10)
backArrow.graphics.endFill()
goBt.addChild(goArrow)
goArrow.x=25
goArrow.y=25
backBt.addChild(backArrow)
backArrow.x=25
backArrow.y=25
goBt.buttonMode=true
backBt.buttonMode=true
goBt.mouseChildren=false
backBt.mouseChildren=false
goBt.graphics.beginFill(0xFFFFFF,1)
goBt.graphics.drawRect(0,0,50,50)
this.addChild(goBt)
goBt.x=this.stage.stageWidth-50;
goBt.y=this.stage.stageHeight-70;
backBt.graphics.beginFill(0xFFFFFF,1)
backBt.graphics.drawRect(0,0,50,50)
backBt.y=this.stage.stageHeight-70;
this.addChild(backBt)
//---------------------------------------------------
goBt.addEventListener(MouseEvent.CLICK, onGoClick);
goBt.addEventListener(MouseEvent.MOUSE_OVER, onGoMouseOver);
goBt.addEventListener(MouseEvent.MOUSE_OUT, onGoMouseOut);
backBt.addEventListener(MouseEvent.CLICK, onBackClick);
backBt.addEventListener(MouseEvent.MOUSE_OVER, onBackMouseOver);
backBt.addEventListener(MouseEvent.MOUSE_OUT, onBackMouseOut);
stage.addEventListener(Event.RESIZE, onResize);
var nextR:Number=MathUtils.toRadian(45)
function onGoClick(e:MouseEvent):void {
nextPage++
if (nextPage==maxPage) {
nextPage=maxPage-1;
}
goPage(nextPage)
}
function actionEnd():void {
action=true
}
function onGoMouseOver(e:MouseEvent):void {
Tweener.addTween(goArrow, {x:30,time:0.5,transition:trans});
}
function onGoMouseOut(e:MouseEvent):void {
goArrow.x=25
}
function onBackClick(e:MouseEvent):void {
nextPage--
if (nextPage==-1) {
nextPage=0;
}
goPage(nextPage)
}
function onBackMouseOver(e:MouseEvent):void {
Tweener.addTween(backArrow, {x:20,time:0.2,transition:trans});
}
function onBackMouseOut(e:MouseEvent):void {
backArrow.x=25
}
function onResize(e:Event):void {
goBt.x=stage.stageWidth-50;
goBt.y=stage.stageHeight-70;
backBt.y=stage.stageHeight-70;
}
}
private function onPlateClick(e:MouseEvent):void {
changePage(e.currentTarget.id,0)
}
public function goPage(n:uint):void {
//現在のページから順に、ページをnページに送っていく
movePage(n,0)
}
public function changePage(n:Number,mode:uint=0,linkFlag:Boolean=true):void {
nextPage=n
movePage(n,mode,linkFlag)
}
public function movePage(n:uint,mode:uint=0,linkFlag:Boolean=true):void {
if (nowPage!=n) {
var tempX:Number=0;
var tempY:Number=0;
var tempR:Number=0;
for (var i:uint=0;i<maxPage;i++) {
//plateArray[i].visible=true
tempX=(80*i)-(80*n)
if (i<n) {
tempX-=defWidth*0.6
tempY=defWidth*0.7+((n-i)*30)
tempR=MathUtils.toRadian(80)
} else if (i>n) {
tempX+=defWidth*0.6
tempY=defWidth*0.7+((i-n)*30)
tempR=MathUtils.toRadian(-80)
} else {
tempR=MathUtils.toRadian(0)
tempY=0
}
if (mode==0) {
moveParts(i,tempX,tempY,tempR)
} else {
plateArray[i].x=tempX
plateArray[i].y=tempY
plateArray[i].rotationZ=tempR
}
}
if (mode==0) {
nowPage=-1
} else {
nowPage=nextPage
}
}
}
public function moveParts(i:uint,tempX:Number,tempY:Number,tempR:Number):void {
Tweener.addTween(plateArray[i], {rotationZ:tempR,time:0.7, transition:"easeoutexpo"});
Tweener.addTween(plateArray[i], {x:tempX,y:tempY,time:1.4, transition:"easeoutexpo", onComplete:moveComplete});
function moveComplete():void {
nowPage=nextPage
}
}
}
}
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.primitives.Plane;
import alternativ5.engine3d.materials.MovieClipMaterial;
import alternativ5.engine3d.materials.SurfaceMaterial;
import alternativ5.engine3d.materials.FillMaterial;
import alternativ5.engine3d.materials.Material;
import alternativ5.engine3d.events.MouseEvent3D
import alternativ5.utils.*
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Loader;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.LineScaleMode;
import flash.display.GradientType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.events.IOErrorEvent;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.system.Security;
//------------------------------------------------------
//鏡面を持ったPlane
//------------------------------------------------------
class mirrorPlane extends Object3D {
public static const CLICK:String = 'click';
private var width:Number;
private var height:Number;
private var main:Plane;
private var mirror:Plane;
private var _id:uint;
function mirrorPlane(material:LoadTextureMaterial,_w:Number=240,_h:Number=320,sw:Number=4,sh:Number=4) {
super();
width=_w;
height=_h;
//メイン画像の作成
main=new Plane(width,height,sw,sh);
this.addChild(main)
main.y=-160
main.cloneMaterialToAllSurfaces(material);
main.addEventListener(MouseEvent3D.CLICK, onPlateClick);
//反転する裏面を反転(MovieClipMaterialは、matrixを持ってるので、そいつで、反転)
var mt:MovieClipMaterial=MovieClipMaterial(main.getSurfaceById('front').material);
var mtx:Matrix=new Matrix()
mtx.rotate(MathUtils.toRadian(-180));
mtx.translate(width,width);
mt.matrix=mtx
//鏡面部分の作成
mirror=new Plane(width,height,sw,sh);
this.addChild(mirror)
mirror.y=160
var mirrorMaterial:SurfaceMaterial=SurfaceMaterial(material.mirrorMaterial())
Security.loadPolicyFile('http://marubayashi.net/crossdomain.xml');
//半透明にしたかったのだけど、某サイトのは、透けてないので、上からマスクする事にする
var shadow:Sprite = new Sprite();
var colors:Array=new Array(0xFFFFFF,0xFFFFFF)
var alphas:Array=new Array(1,0.4)
var ratios:Array=new Array(50,255)
var matrix:Matrix=new Matrix()
matrix.createGradientBox(width,height,Math.PI/2,0,0)
shadow.graphics.beginGradientFill(GradientType.LINEAR,colors, alphas, ratios, matrix)
shadow.graphics.drawRect(0,0,width,height)
MovieClipMaterial(mirrorMaterial).movieClip.addChild(shadow)
mirror.cloneMaterialToAllSurfaces(mirrorMaterial);
var mt1:MovieClipMaterial=MovieClipMaterial(mirror.getSurfaceById('front').material);
var mt2:MovieClipMaterial=MovieClipMaterial(mirror.getSurfaceById('back').material);
mtx=new Matrix()
mtx.rotate(MathUtils.toRadian(-180));
mtx.scale(1,-1);
mtx.translate(width,0);
mt1.matrix=mtx
mtx=new Matrix()
mtx.scale(1,-1);
mtx.translate(0,width);
mt2.matrix=mtx
}
//----------------------------------------------------------
//中心点の変更
//----------------------------------------------------------
public function changeCenter(align:String='CENTER'):void {
if (align=='CENTER') {
main.x=0
mirror.x=0
} else if (align=='LEFT') {
main.x=width/2
mirror.x=-width/2
} else if (align=='RIGHT') {
main.x=-width/2
mirror.x=width/2
}
}
public function set id(value:uint):void {
_id=value;
}
public function get id():uint {
return _id;
}
private function onPlateClick(e:MouseEvent3D):void {
dispatchEvent(new MouseEvent(CLICK))
}
}
//------------------------------------------------------
//Loaderと一体になったマテリアル。
//Loadが終わると、勝手に反映します。
//------------------------------------------------------
class LoadTextureMaterial extends MovieClipMaterial {
private var mc:MovieClip;
private var mirror:MovieClip;
private var width:Number
public function LoadTextureMaterial(url:String,_w:Number=240) {
width=_w
mc = new MovieClip();
mc.graphics.beginFill(0xCCCCCC,1)
mc.graphics.drawRect(0,0,width,width)
//長方形の場合、UVマッピングの値を変えないといけなくなる(もしくはmatrixで調整)ので、正方形にしてしまう
super(mc,width,width,null,null,true)
//clone用のMovieClip
mirror = new MovieClip();
mirror.graphics.beginFill(0xCCCCCC,1)
mirror.graphics.drawRect(0,0,width,width)
var mirrorBmd:BitmapData=new BitmapData(width,width,true,0xCCCCCCC);
if (url) {
var loader:Loader= new Loader()
var context:LoaderContext = new LoaderContext(true);
loader.load(new URLRequest(url), context);
loader.contentLoaderInfo.addEventListener(Event.OPEN,open);
loader.contentLoaderInfo.addEventListener(Event.INIT,init);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,progressHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, error);
//ProgressBar 色々ライブラリはあるけれど、とりあえず、自作w------------
var progress:Sprite = new Sprite();
progress.graphics.beginFill(0x666666,1)
progress.graphics.drawRect(0,0,100,10)
var bar:Shape = new Shape();
bar.graphics.beginFill(0xCCCCFF,1)
bar.graphics.drawRect(0,0,100,10)
var line:Shape = new Shape();
line.graphics.lineStyle(0,0x666666,1,false,LineScaleMode.NONE)
line.graphics.drawRect(0,0,100,10)
progress.addChild(bar)
progress.addChild(line)
mc.addChild(progress);
progress.x=(width-100)/2
progress.y=(width-20)/2
//ProgressBar END -----------------------------------------------------
function open(e:Event):void {
mc.addChild(progress)
}
function progressHandler(e:ProgressEvent):void {
var bytesLoaded:Number = e.bytesLoaded
var bytesTotal:Number = e.bytesTotal
bar.width=Math.round(bytesLoaded / bytesTotal)
}
function loaded(e:Event):void {
}
function error(e:IOErrorEvent):void {
loader.contentLoaderInfo.removeEventListener(Event.OPEN,open);
loader.contentLoaderInfo.removeEventListener(Event.INIT,init);
loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS,progressHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, error);
}
function init(e:Event):void {
loader.contentLoaderInfo.removeEventListener(Event.OPEN,open);
loader.contentLoaderInfo.removeEventListener(Event.INIT,init);
loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS,progressHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, error);
//mc.removeChild(progress)
//長方形の場合、UVマッピングの値を変えないといけなくなるので、正方形にしてしまう
loader.content.height=loader.content.width
mc.addChild(loader.content)
mirrorBmd.draw(loader.content)
mirror.addChildAt(new Bitmap(mirrorBmd),0);
trace(loader.content.width,loader.content.height)
}
}
}
public function mirrorMaterial():Material {
var result:MovieClipMaterial=new MovieClipMaterial(mirror,width,width,null,null,true)
return result;
}
}
import alternativ5.engine3d.controllers.CameraController;
import alternativ5.engine3d.core.Camera3D;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Scene3D;
import alternativ5.engine3d.display.View;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
/**
* BasicTemplate for Alternativa3D
* Alternativa3Dを扱いやすくするためのテンプレートです
* @author Yasu
*/
class BasicTemplate extends Sprite{
/**
* シーンインスタンスです。
*/
public var scene:Scene3D;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraContoller:CameraController;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
/**
* 新しい BasicTemplate インスタンスを作成します。
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function BasicTemplate(viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true) {
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
// Creating scene
scene = new Scene3D();
scene.splitAnalysis = false; // not analysis for performance
scene.root = new Object3D();
// Adding camera
camera = new Camera3D();
camera.z = -1000;
scene.root.addChild(camera);
// camera contoller
cameraContoller = new CameraController(this);
cameraContoller.camera = camera;
// set view
view = new View();
view.camera = camera;
addChild(view);
// stage
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理を記述します。
*/
private var _onInit:Function = function():void { };
public function get onInit():Function { return _onInit; }
public function set onInit(value:Function):void {
_onInit = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理を記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void {
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
protected var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void {
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void {
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void {
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void {
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
// resize
stage.addEventListener(Event.RESIZE, onResize);
onResize(null);
// render
startRendering();
atInit();
_onInit();
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void {
atPostRender();
_onPostRender();
scene.calculate();
atPreRender();
_onPreRender();
}
/**
* @private
*/
private function onResize(event:Event = null):void {
if (_scaleToStage) {
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}else {
view.width = _viewWidth;
view.height = _viewHeight;
}
}
}