// forked from yd_niku's 3D演習その3 +Camera3Dの回転 // forked from yd_niku's forked from: 3D演習その1 // forked from yd_niku's 3D演習その1 package { // ActionScript3.0Animation読みながら、とりあえず3D投影してみる。 // Z軸で動かしてみる // Camera を導入してみる // Camera を回転させてみた // Zsortをつけてみた // Camera.rotationY がおかしいのを直した。 import flash.display.Sprite; import flash.display.DisplayObject; import flash.events.Event; import caurina.transitions.Tweener; public class FlashTest extends Sprite { private var _scene:Scene3D; private var _camera:Camera3D; private var screenX:Number; private var screenY:Number; public function FlashTest() { stage.frameRate = 60; setup(); putThemFar(); } private function setup():void { DisplayObject3D.screenX = stage.stageWidth/2; DisplayObject3D.screenY = stage.stageHeight/2; _camera = new Camera3D(); _scene = new Scene3D( this, _camera ); var xNum:uint = 8, yNum:uint = 8, zNum:uint = 10; var xInterval:uint = 50, yInterval:uint = 50, zInterval:uint = 50; for( var i:int=0; i<xNum; ++i ) { for( var j:int=0; j<yNum; ++j ) { for( var k:int=0; k<zNum; ++k ) { createBall( (i-xNum*0.5)*xInterval, (j-yNum*0.5)*yInterval, (k-zNum*0.2)*zInterval ); } } } } private function createBall( sx:Number, sy:Number, sz:Number ):void { var obj3D:DisplayObject3D = new DisplayObject3D(new Ball()); obj3D.x = sx; obj3D.y = sy; obj3D.z = sz; _scene.addChild( obj3D ); } private function putThemFar():void { var l:uint = _scene.renderList.length; for( var i:uint=0; i<l; ++i ) { var obj:DisplayObject3D = _scene.renderList[i]; var tz:Number= obj.z; obj.z = 0; Tweener.addTween( obj, { z: tz, time:2, transition:"easeInOutQuart" } ); } Tweener.addTween( _camera, { rotationX:360, rotationY:360, rotationZ:180, time:15, transition:"easeInOutQuart" } ); } } } import flash.display.*; import flash.events.*; class DisplayObject3D { public static var screenX:Number = 0; public static var screenY:Number = 0; public var view:DisplayObject; public var x:Number = 0; public var y:Number = 0; public var z:Number = 0; public function DisplayObject3D( view:DisplayObject ) { this.view = view; } public function render( tx:Number, ty:Number, persepective:Number ):void { view.x = tx + screenX; view.y = ty + screenY; view.scaleX = view.scaleY = persepective; view.alpha = Math.min( 1, persepective); } public function set visible( value:Boolean ) :void { view.visible = value; } public function get visible() :Boolean { return view.visible; } } class Scene3D { private var _stage:DisplayObjectContainer; private var _camera :Camera3D; private var _renderList:Array = []; private var _ZsortList:Array = []; public function Scene3D( stage:DisplayObjectContainer, camera:Camera3D ){ _stage = stage; _camera = camera; _stage.addEventListener( Event.ENTER_FRAME, enterfameHandler ); } private function enterfameHandler(e:Event):void { render(); } public function addChild( obj3D :DisplayObject3D ) :DisplayObject3D { _renderList.push( obj3D ); _stage.addChild( obj3D.view ); return obj3D; } private const PI:Number = Math.PI; public function render():void { _ZsortList = []; var camXCos:Number = Math.cos( PI*_camera.rotationX/180); var camXSin:Number = Math.sin( PI*_camera.rotationX/180); var camYCos:Number = Math.cos( PI*_camera.rotationY/180); var camYSin:Number = Math.sin( PI*_camera.rotationY/180); var camZCos:Number = Math.cos( PI*_camera.rotationZ/180); var camZSin:Number = Math.sin( PI*_camera.rotationZ/180); var l:uint = _renderList.length; for( var i:uint=0; i<l; ++i ) { var obj:DisplayObject3D= _renderList[i]; var tmpX:Number = obj.x - _camera.x; var tmpY:Number = obj.y - _camera.y; var tmpZ:Number = obj.z - _camera.z; // TODO:Matrix3Dにまかせる // Z Axis var ZAxisX :Number = ( tmpX*camZCos - tmpY*camZSin ); var ZAxisY :Number = ( tmpX*camZSin + tmpY*camZCos ); var ZAxisZ :Number = tmpZ; // X Axis var XAxisY :Number = ( ZAxisY*camXCos - ZAxisZ*camXSin ); var XAxisZ :Number = ( ZAxisY*camXSin + ZAxisZ*camXCos ); var XAxisX :Number = ZAxisX; // Y Axis var YAxisZ :Number = ( XAxisZ*camYCos - XAxisX*camYSin ); var YAxisX :Number = ( XAxisZ*camYSin + XAxisX*camYCos ); var YAxisY :Number = XAxisY; if( _camera.isInFocus( YAxisY ) ) { var persepective:Number= _camera.getPersepective( YAxisZ ); var tx:Number = YAxisX*persepective; var ty:Number = YAxisY*persepective; obj.render( tx, ty, persepective); obj.visible = true; _ZsortList.push( { z:YAxisZ, view:obj.view } ); } else { obj.visible = false; } } // Zsort _ZsortList.sortOn( "z", Array.DESCENDING|Array.NUMERIC ); l = _ZsortList.length; for( i=0; i<l; ++i ) { var zobj:Object = _ZsortList[i] as Object; _stage.setChildIndex( zobj.view, i ); } } public function get renderList():Array{ return _renderList; } } class Camera3D{ public var focus:Number = 500; public var x:Number = 0; public var y:Number = 0; public var z:Number = 0; public function getPersepective( tz :Number ):Number { return focus/( focus+tz ); } public function isInFocus( tz:Number ):Boolean { var bool:Boolean = tz > -focus; return bool; } public var rotationX:Number = 0; public var rotationY:Number = 0; public var rotationZ:Number = 0; } class Ball extends Sprite { public function Ball() { graphics.lineStyle(0,0xffffff); graphics.beginFill(0xcc6600); graphics.drawCircle( 0, 0, 10 ); graphics.endFill(); } } 3D演習その3 +Camera3Dの回転