Flash 3D 基础
1、设置消失点
在3D中,消失点是所有物体远离时的聚集点。
在 Flash 10 里,每个显示元素可以有一个 perspectiveProjection 去指定控制怎么去渲染 3D。它指定的是 transform 的 perspectiveProjection 属性。所以,假如有一个名叫 s的 sprite,你可以这样去访问:
s.transform.perspectiveProjection
PerspectiveProjection 类有一个 projectionCenter属性是 Point 类的实例。这就是通常所说的消失点。因此,去设置显示元素的中心就可以像下面这样:
s.transform.perspectiveProjection.projectionCenter=new Point(stage.stageWidth / 2,
stage.stageHeight / 2);
这样只能设置一个 object 的消失点。当然这样就可以为这个元件的所有子元素设置消失点。
如果你想为影片中的所有元素设置消失点,可以在 root 上设置,像这样:
root.transform.perspectiveProjection.projectionCenter=new Point(stage.stageWidth / 2, stage.stageHeight / 2);
2、景深排序
在同一个容器中任何用 addChild 方法添加到显示列表中的对象会显示在以前的对象的前面。唯一能够改变这种情况的途径是一些操作显示列表的方法,比如addChild,addChildAt,swapChildren,removeChild 等等。因为显示容器里没有排序方法,所以所有的景深排序工作都需要手动完成。
3、3D 容器
显示对象的容器会在他们被改变的时候改变他们的子对象。换句话说,当你往一个 sprite
里添加一些显示对象并且移动它的容器的时候,它并不是简单地把窗口展平然后作为一个独立的对
象在 3D 空间里移动。它实际上改变每个子对象以使它们看起来是在 3D 空间里独立运动。
1 package 2 { 3 import flash.display.Sprite; 4 import flash.display.StageAlign; 5 import flash.display.StageScaleMode; 6 import flash.events.Event; 7 import flash.text.TextField; 8 import flash.text.TextFormat; 9 10 public class Container3D extends Sprite 11 { 12 private var _sprite:Sprite; 13 private var _n:Number = 0; 14 15 public function Container3D() 16 { 17 stage.align = StageAlign.TOP_LEFT; 18 stage.scaleMode = StageScaleMode.NO_SCALE; 19 20 _sprite = new Sprite(); 21 _sprite.y = stage.stageHeight / 2; 22 23 for( var i:int = 0; i < 100; i++ ) 24 { 25 var tf:TextField = new TextField(); 26 tf.defaultTextFormat = new TextFormat( "Arial", 40 ); 27 tf.text = String.fromCharCode( 65 + Math.floor( Math.random()* 25 ) ); 28 tf.selectable = false; 29 30 tf.x = Math.random() * 300 -150; 31 tf.y = Math.random() * 300 -150; 32 tf.z = Math.random() * 1000; 33 34 _sprite.addChild( tf ); 35 } 36 37 addChild( _sprite ); 38 addEventListener( Event.ENTER_FRAME, onEnterFrame ); 39 } 40 41 protected function onEnterFrame(event:Event):void 42 { 43 _sprite.x = stage.stageWidth / 2 + Math.cos(_n) * 200; 44 _n += .05; 45 } 46 } 47 }
4、3D旋转
在3D空间中,可以绕X、Y、 Z坐标轴旋转任何对象。
可以通过 deltaTransformVector()方法来转换对象的坐标系,使在不同坐标系里的对象处于同一坐标系。
如:
var posA:Vector3D = objA.transform.matrix3D.position;
posA = container.transform.matrix3D.deltaTransformVector( posA );
在转换坐标系时,一定要确保容器 container 对象有3D属性,可以通过container.z = 0, container.rotationX等来设置。
不然的话,container.transform.matrix3D 返回的将是 null。
1 package 2 { 3 import flash.display.Shape; 4 import flash.display.Sprite; 5 import flash.display.StageAlign; 6 import flash.display.StageScaleMode; 7 import flash.events.Event; 8 import flash.geom.Vector3D; 9 10 [SWF(width="600", height="600")] 11 public class RotateAndPosition extends Sprite 12 { 13 private var _holder:Sprite; 14 private var _shapes:Array = []; 15 16 public function RotateAndPosition() 17 { 18 stage.align = StageAlign.TOP_LEFT; 19 stage.scaleMode = StageScaleMode.NO_SCALE; 20 21 _holder = new Sprite(); 22 _holder.x = stage.stageWidth / 2; 23 _holder.y = stage.stageHeight /2; 24 _holder.z = 0; 25 addChild( _holder ); 26 27 var shape1:Shape = makeShape(); 28 //shape1.x = 200; 29 shape1.z = 200; 30 _holder.addChild( shape1 ); 31 _shapes.push( shape1 ); 32 33 var shape2:Shape = makeShape(); 34 //shape2.x = 200; 35 shape2.z = -200; 36 _holder.addChild( shape2 ); 37 _shapes.push( shape2 ); 38 39 var shape3:Shape = makeShape(); 40 shape3.x = 200; 41 //shape3.z = -200; 42 shape3.rotationY = 90; 43 _holder.addChild( shape3 ); 44 _shapes.push( shape3 ); 45 46 var shape4:Shape = makeShape(); 47 shape4.x = -200; 48 //shape4.z = -200; 49 shape4.rotationY = -90; 50 _holder.addChild( shape4 ); 51 _shapes.push( shape4 ); 52 53 var shape5:Shape = makeShape(); 54 //shape2.x = 200; 55 //shape5.z = -200; 56 shape5.y = 200; 57 shape5.rotationX = 90;; 58 _holder.addChild( shape5 ); 59 _shapes.push( shape5 ); 60 61 var shape6:Shape = makeShape(); 62 //shape2.x = 200; 63 //shape6.z = -200; 64 shape6.y = -200; 65 shape6.rotationX = -90; 66 _holder.addChild( shape6 ); 67 _shapes.push( shape6 ); 68 69 sortShape(); 70 71 addEventListener( Event.ENTER_FRAME, onEnterFrame ); 72 73 } 74 75 private function sortShape():void 76 { 77 _shapes.sort( depthSort ); 78 for( var i:int = 0; i < _shapes.length; i++ ) 79 { 80 _holder.addChildAt( _shapes[i] as Shape, i ); 81 } 82 } 83 84 /** 85 * 将局部坐标系转换为世界坐标系 86 * @param objA 87 * @param objB 88 * @return 89 * 90 */ 91 private function depthSort(objA:Object, objB:Object):int 92 { 93 var posA:Vector3D = objA.transform.matrix3D.position; 94 posA = _holder.transform.matrix3D.deltaTransformVector( posA ); 95 var posB:Vector3D = objB.transform.matrix3D.position; 96 posB = _holder.transform.matrix3D.deltaTransformVector( posB ); 97 return posB.z - posA.z; 98 } 99 100 /** 101 * 创建Shape 102 * @return 103 * 104 */ 105 private function makeShape():Shape 106 { 107 var shape:Shape = new Shape(); 108 shape.graphics.beginFill( 0xffffff * Math.random() ); 109 shape.graphics.drawRect( -100, -100, 200, 200 ); 110 shape.graphics.endFill(); 111 return shape; 112 } 113 114 protected function onEnterFrame(event:Event):void 115 { 116 _holder.rotationY += 2; 117 _holder.rotationX += 1.5; 118 119 sortShape(); 120 } 121 } 122 }
1 package 2 { 3 import flash.display.DisplayObject; 4 import flash.display.Sprite; 5 import flash.display.StageAlign; 6 import flash.display.StageScaleMode; 7 import flash.events.Event; 8 import flash.geom.Vector3D; 9 10 [SWF(width="800", height="800", backgroundColor="0xffffff")] 11 public class Carousel extends Sprite 12 { 13 private var _holder:Sprite; 14 private var _itemsNum:int = 5; 15 private var _items:Array = []; 16 private var radius:Number = 200; 17 18 19 public function Carousel() 20 { 21 stage.align = StageAlign.TOP_LEFT; 22 stage.scaleMode = StageScaleMode.NO_SCALE; 23 24 _holder = new Sprite(); 25 _holder.x = stage.stageWidth / 2; 26 _holder.y = stage.stageHeight /2; 27 _holder.z = 0; 28 addChild( _holder ); 29 30 for( var i:int = 0; i < _itemsNum; i++ ) 31 { 32 var angel:Number = 2 * Math.PI / _itemsNum * i; 33 var item:Sprite = makeItem(); 34 item.x = Math.cos( angel ) * radius; 35 item.z = Math.sin( angel ) * radius; 36 item.rotationY = -360 / _itemsNum * i + 90; 37 //_holder.addChild( item ); 38 _items.push( item ); 39 } 40 41 sortItem(); 42 43 addEventListener( Event.ENTER_FRAME, onEnterFrame ); 44 } 45 46 protected function onEnterFrame(event:Event):void 47 { 48 var speedX:Number = ( stage.stageWidth / 2 - mouseX ) * 0.05; 49 //_holder.rotationY += ( stage.stageWidth / 2 - mouseX ) * 0.1; 50 if( speedX > 5 ) 51 { 52 _holder.rotationY += 5; 53 } 54 else if( speedX < -5 ) 55 { 56 _holder.rotationY += -5; 57 } 58 else 59 { 60 _holder.rotationY += speedX; 61 } 62 63 64 _holder.y += ( mouseY - _holder.y ) * 0.1; 65 sortItem(); 66 } 67 68 private function sortItem():void 69 { 70 _items.sort( depthSort ); 71 72 for( var i:int = 0; i < _items.length; i++ ) 73 { 74 _holder.addChildAt( _items[i] as Sprite, i ); 75 } 76 } 77 78 private function depthSort(objA:DisplayObject, objB:DisplayObject):int 79 { 80 var posA:Vector3D = objA.transform.matrix3D.position; 81 posA = _holder.transform.matrix3D.deltaTransformVector( posA ); 82 var posB:Vector3D = objB.transform.matrix3D.position; 83 posB = _holder.transform.matrix3D.deltaTransformVector( posB ); 84 85 return posB.z - posA.z; 86 } 87 88 /** 89 * 创建图形 90 * @return 91 * 92 */ 93 private function makeItem():Sprite 94 { 95 var item:Sprite = new Sprite(); 96 item.graphics.beginFill( 0xffffff * Math.random() ); 97 item.graphics.drawRect( -100, -100, 200, 200 ); 98 item.graphics.endFill(); 99 return item; 100 } 101 } 102 }
5、视野与焦距
焦距和视野联系很紧密并且都决定着物体看起来应该缩放和扭曲多少。
在Flash 3D中,你可以通过设置焦距或视野来控制扭曲。实际上,设置了一个另外一个会跟着改变。但你要选择一个你感觉最舒服的去用。这个工作需要设置显示对象的
transform 属性的perspectiveProjection 属性:focalLength 和 fieldOfView。通常地,最好在你的 movie 的根目录设置这些属性,除非你的容器有一
特殊的要求或者对象有特殊的属性(比如在不同的窗口中看对象)。
视野需要用度数进行度量,并且需要大于 0 小于 180,否则将出现错误。
如:
视野: root.transform.perspectiveProjection.fieldOfView = 100;
焦距: root.transform.perspectiveProjection.focalLength = 1000;
6、屏幕坐标系和 3D 坐标系
local3DtoGlobal:一个 3D 空间中的点转换为相对应的屏幕坐标。从 flash.geom.Vector3D 转 换 成 一 个 2Dflash.geom.Point 对象。
globalToLocal3D: 屏幕上的坐标转换为指定3D空间中的点。
1 package 2 { 3 import flash.display.Sprite; 4 import flash.display.StageAlign; 5 import flash.display.StageScaleMode; 6 import flash.events.Event; 7 import flash.geom.Point; 8 import flash.geom.Vector3D; 9 10 [SWF(width="800", height="800")] 11 public class localGlobal extends Sprite 12 { 13 private var _sprite:Sprite; 14 private var _tracker:Sprite; 15 private var _angle:Number = 0; 16 17 public function localGlobal() 18 { 19 if( stage ) 20 { 21 init(); 22 } 23 else 24 { 25 addEventListener( Event.ADDED_TO_STAGE, init ); 26 } 27 } 28 29 private function init():void 30 { 31 if( hasEventListener( Event.ADDED_TO_STAGE ) ) 32 { 33 removeEventListener( Event.ADDED_TO_STAGE, init ); 34 } 35 36 stage.align = StageAlign.TOP_LEFT; 37 stage.scaleMode = StageScaleMode.NO_SCALE; 38 39 _sprite = new Sprite(); 40 _sprite.graphics.lineStyle( 10 ); 41 _sprite.graphics.lineTo( 200, 0 ); 42 _sprite.graphics.drawCircle( 200, 0, 10 ); 43 _sprite.graphics.endFill(); 44 _sprite.x = 400; 45 _sprite.y = 400; 46 addChild( _sprite ); 47 48 _tracker = new Sprite(); 49 _tracker.graphics.lineStyle( 2, 0xff0000 ); 50 _tracker.graphics.drawCircle( 0, 0, 20 ); 51 _tracker.graphics.endFill(); 52 addChild( _tracker ); 53 54 addEventListener( Event.ENTER_FRAME, onEnterFrame ); 55 56 57 } 58 59 protected function onEnterFrame(event:Event):void 60 { 61 _sprite.rotationX = 0.1; 62 _sprite.rotationY += 1.2; 63 _sprite.rotationZ += 0.5; 64 //_sprite.x = 400 + Math.cos( _angle ) * 100; 65 //_sprite.y = 400 + Math.sin( _angle ) * 100; 66 //_sprite.z = 200 + Math.cos( _angle * 0.8 ) * 400; 67 _angle += 0.5; 68 69 // 把_sprite里3D空间的点转换为2D的坐标 70 var p:Point = _sprite.local3DToGlobal( new Vector3D( 200, 0, 0 ) ); 71 _tracker.x = p.x; 72 _tracker.y = p.y; 73 } 74 } 75 }
1 package 2 { 3 import flash.display.Sprite; 4 import flash.display.StageAlign; 5 import flash.display.StageScaleMode; 6 import flash.events.Event; 7 import flash.geom.Point; 8 import flash.geom.Vector3D; 9 10 [SWF(width="800", height="800")] 11 public class GlobalLocal extends Sprite 12 { 13 private var _sprite:Sprite; 14 private var _tracker:Sprite; 15 16 public function GlobalLocal() 17 { 18 stage.align = StageAlign.TOP_LEFT; 19 stage.scaleMode = StageScaleMode.NO_SCALE; 20 21 _sprite = new Sprite(); 22 _sprite.graphics.lineStyle( 10 ); 23 _sprite.graphics.drawRect( -200, -200, 400, 400 ); 24 _sprite.graphics.endFill(); 25 _sprite.x = 400; 26 _sprite.y = 400; 27 addChild( _sprite ); 28 29 _tracker = new Sprite(); 30 _tracker.graphics.lineStyle( 2, 0xff0000 ); 31 _tracker.graphics.drawCircle( 0, 0, 20 ); 32 _tracker.graphics.endFill(); 33 _sprite.addChild( _tracker ); 34 35 addEventListener( Event.ENTER_FRAME, onEnterFrame ); 36 } 37 38 protected function onEnterFrame(event:Event):void 39 { 40 _sprite.rotationX = 0.1; 41 _sprite.rotationY += 1.2; 42 //_sprite.rotationZ += 0.5; 43 //_sprite.x = 400 + Math.cos( _angle ) * 100; 44 //_sprite.y = 400 + Math.sin( _angle ) * 100; 45 //_sprite.z = 200 + Math.cos( _angle * 0.8 ) * 400; 46 //_angle += 0.5; 47 48 // 把_sprite里3D空间的点转换为2D的坐标 49 //var p:Point = _sprite.local3DToGlobal( new Vector3D( 200, 0, 0 ) ); 50 51 /*var p:Vector3D = _sprite.globalToLocal3D( new Point( mouseX, mouseY ) ); 52 _tracker.x = p.x; 53 _tracker.y = p.y;*/ 54 _tracker.x = _sprite.mouseX; 55 _tracker.y = _sprite.mouseY; 56 } 57 58 } 59 }
如果要存取一个在3D空间里改变的对象的mouseX和mouseY参数时,世界坐标到局部坐标的3D转换会自动进行。
要注意的是,这只是在转鼠标坐标时才有用。如果想要转换一个在舞台上的对象到3D坐标系,那么仍然需要使用转换函数。
/*var p:Vector3D = _sprite.globalToLocal3D( new Point( mouseX, mouseY ) );
_tracker.x = p.x;
_tracker.y = p.y;*/
_tracker.x = _sprite.mouseX;
_tracker.y = _sprite.mouseY;
7、指向某物
pointAt 方法接收一个 Vector3D 对象作为指向的目标。如果这个函数是被显示对象的 transform 属性的 Matrix3D 对象调用,
它会在 3D 空间中旋转那个显示对象使它指向一个特殊的区域。
1 package 2 { 3 import flash.display.Sprite; 4 import flash.events.Event; 5 import flash.geom.Vector3D; 6 7 [SWF(width="800", height="800")] 8 public class FollowMouse3D extends Sprite 9 { 10 private var _sprite:Sprite; 11 private var _angleX:Number = 0; 12 private var _angleY:Number = 0; 13 private var _angleZ:Number = 0; 14 15 public function FollowMouse3D() 16 { 17 _sprite = new Sprite(); 18 _sprite.x = 400; 19 _sprite.y = 400; 20 _sprite.z = 200; 21 _sprite.graphics.beginFill( 0xff0000 ); 22 _sprite.graphics.moveTo( 0, 50 ); 23 _sprite.graphics.lineTo( -25, 25 ); 24 _sprite.graphics.lineTo( -10, 25 ); 25 _sprite.graphics.lineTo( -10, -50 ); 26 _sprite.graphics.lineTo( 10, -50 ); 27 _sprite.graphics.lineTo( 10, 25 ); 28 _sprite.graphics.lineTo( 25, 25 ); 29 _sprite.graphics.lineTo( 0, 50 ); 30 _sprite.graphics.endFill(); 31 addChild( _sprite ); 32 addEventListener(Event.ENTER_FRAME, onEnterFrame); 33 } 34 35 protected function onEnterFrame(event:Event):void 36 { 37 //_sprite.x = 400 + Math.sin( _angleX += 0.11 ) * 200; 38 //_sprite.y = 400 + Math.sin( _angleY += 0.7 ) * 200; 39 //_sprite.z = Math.sin( _angleZ += 0.09 ) * 200; 40 _sprite.transform.matrix3D.pointAt( new Vector3D( mouseX, mouseY ) ); 41 } 42 } 43 }