Flash/Flex学习笔记(51):3维旋转与透视变换(PerspectiveProjection)
Flash/Flex学习笔记(49):3D基础 里已经介绍了3D透视的基本原理,不过如果每次都要利用象该文中那样写一堆代码,估计很多人不喜欢,事实上AS3的DisplayObject类已经内置了z坐标、rotationX、rotationY、rotationZ属性,再加上PerspectiveProjection类用于处理透视转换,基本上可以满足大多数的3D要求。
001 import flash.events.Event;
002 import flash.display.Sprite;
003 import flash.text.TextField;
004 import flash.events.MouseEvent;
005 import flash.text.TextFieldAutoSize;
006
007 var isAngleChangeing = false;
008
009 var txtX:TextField,txtY:TextField,txtZ:TextField,txtPosZ:TextField,txtFieldOfView:TextField,txtInfo:TextField,txtCenter:TextField,txtFocusLength:TextField;
010 txtX = new TextField();
011 txtX.text = "rotationX:";
012 txtY = new TextField();
013 txtY.text = "rotationY:";
014 txtZ = new TextField();
015 txtZ.text = "rotationZ:";
016 txtPosZ = new TextField();
017 txtPosZ.text = "Z:";
018 txtFieldOfView = new TextField();
019 txtFieldOfView.text = "视角:";
020 txtCenter = new TextField();
021 txtCenter.text = "消失点:"
022 txtFocusLength = new TextField();
023 txtFocusLength.text = "焦距:";
024 txtX.y = txtY.y = txtZ.y = 5;
025 txtX.x = txtPosZ.x = 10;
026 txtPosZ.y = txtX.y + 26;
027 txtPosZ.x += 40;
028 txtY.x = txtX.x + 180;
029 txtZ.x = txtY.x + 180;
030 txtFieldOfView.x = txtPosZ.x + 160;
031 txtFieldOfView.y = txtPosZ.y;
032 txtCenter.x = txtFieldOfView.x + 170;
033 txtCenter.y = txtPosZ.y;
034 txtInfo = new TextField();
035 txtInfo.text="";
036 txtFocusLength.x = txtX.x + 25;
037 txtFocusLength.y = txtPosZ.y + 25;
038
039 var imgBD:BitmapData = new ImgSample();
040 var img:Bitmap = new Bitmap(imgBD);
041 trace("img.width=",img.width,",img.height=",img.height);
042
043 var imgSprite:Sprite = new Sprite();
044 img.x = - img.width / 2;
045 img.y = - img.height / 2;
046 imgSprite.addChild(img);
047 trace("imgSprite.width=",imgSprite.width,",imgSprite.height=",imgSprite.height);
048
049 var containerSprite:Sprite = new Sprite();
050 containerSprite.addChild(imgSprite);
051 imgSprite.x = img.width / 2;
052 imgSprite.y = img.height / 2;
053
054 addChild(containerSprite);
055 trace("containerSprite.width=",containerSprite.width,",containerSprite.height=",containerSprite.height);
056
057 containerSprite.x = stage.stageWidth / 2 - containerSprite.width / 2;
058 containerSprite.y = stage.stageHeight / 2 - containerSprite.height / 2;
059 containerSprite.z = 50;
060
061 var silderX:SimpleSlider = new SimpleSlider(0,360,0);
062 silderX.x = txtX.x + 160;
063 silderX.y = txtX.y + 7;
064 silderX.rotation = 90;
065
066 var silderY:SimpleSlider = new SimpleSlider(0,360,0);
067 silderY.x = txtY.x + 160;
068 silderY.y = silderX.y;
069 silderY.rotation = 90;
070
071 var silderZ:SimpleSlider = new SimpleSlider(0,360,0);
072 silderZ.x = txtZ.x + 160;
073 silderZ.y = silderX.y;
074 silderZ.rotation = 90;
075
076 var silderPosZ:SimpleSlider = new SimpleSlider(-200,200,50);
077 silderPosZ.x = txtX.x + 160;
078 silderPosZ.y = silderX.y + 25;
079 silderPosZ.rotation = 90;
080
081 var silderFieldOfView:SimpleSlider = new SimpleSlider(0.1,179.9,90);
082 silderFieldOfView.x = silderPosZ.x + 180;
083 silderFieldOfView.y = silderPosZ.y;
084 silderFieldOfView.rotation = 90;
085
086 var silderCenterPos:SimpleSlider = new SimpleSlider(150,400,275);
087 silderCenterPos.x = silderFieldOfView.x + 180;
088 silderCenterPos.y = silderPosZ.y;
089 silderCenterPos.rotation = 90;
090
091 var silderFocusLength:SimpleSlider = new SimpleSlider(100,500,300);
092 silderFocusLength.x = silderPosZ.x ;
093 silderFocusLength.y = silderPosZ.y + 25;
094 silderFocusLength.rotation = 90;
095
096 addChild(txtX);
097 addChild(txtY);
098 addChild(txtZ);
099 addChild(txtPosZ);
100 addChild(txtFieldOfView);
101 addChild(txtInfo);
102 addChild(txtCenter);
103 addChild(txtFocusLength);
104 addChild(silderX);
105 addChild(silderY);
106 addChild(silderZ);
107 addChild(silderPosZ);
108 addChild(silderFieldOfView);
109 addChild(silderCenterPos);
110 addChild(silderFocusLength);
111
112 silderX.addEventListener(Event.CHANGE,silderXChangeHandler);
113 silderY.addEventListener(Event.CHANGE,silderYChangeHandler);
114 silderZ.addEventListener(Event.CHANGE,silderZChangeHandler);
115 silderPosZ.addEventListener(Event.CHANGE,silderPosZChangeHandler);
116 silderFieldOfView.addEventListener(Event.CHANGE,silderFieldOfViewChangeHandler);
117 silderFieldOfView.addEventListener(MouseEvent.MOUSE_UP,function(){isAngleChangeing = false});
118 silderCenterPos.addEventListener(Event.CHANGE,silderCenterPosChangeHandler);
119 silderFocusLength.addEventListener(Event.CHANGE,silderFocusLengthChangeHandler);
120
121
122 function showTxtInfo(s:SimpleSlider){
123 txtInfo.text = s.value.toString().substr(0,5);
124 txtInfo.x = mouseX + 20;
125 txtInfo.y = s.y + 5;
126 }
127
128 function silderXChangeHandler(e:Event):void {
129 imgSprite.rotationX = silderX.value;
130 showTxtInfo(silderX);
131 }
132
133 function silderYChangeHandler(e:Event):void {
134 imgSprite.rotationY = silderY.value;
135 showTxtInfo(silderY);
136 }
137
138 function silderZChangeHandler(e:Event):void {
139 imgSprite.rotationZ = silderZ.value;
140 showTxtInfo(silderZ);
141 }
142
143 function silderPosZChangeHandler(e:Event):void {
144 containerSprite.z = silderPosZ.value;
145 showTxtInfo(silderPosZ);
146 }
147
148
149 function silderFieldOfViewChangeHandler(e:Event):void {
150 doPerspectiveProjection();
151 showTxtInfo(silderFieldOfView);
152 isAngleChangeing = true;
153 }
154
155 function silderCenterPosChangeHandler(e:Event):void {
156 doPerspectiveProjection();
157 showTxtInfo(silderCenterPos);
158 }
159
160 function silderFocusLengthChangeHandler(e:Event):void {
161 doPerspectiveProjection();
162 showTxtInfo(silderFocusLength);
163 }
164
165 function doPerspectiveProjection():void{
166 var pp:PerspectiveProjection=new PerspectiveProjection();
167 pp.fieldOfView = silderFieldOfView.value;
168 if (!isAngleChangeing){
169 pp.focalLength = silderFocusLength.value;
170 }
171 //trace(pp.focalLength);
172 pp.projectionCenter = new Point(silderCenterPos.value,silderCenterPos.value);
173 containerSprite.transform.perspectiveProjection = pp;
174
175 }
176
177 doPerspectiveProjection();
178
179 var txtAuthor:TextField = new TextField();
180 txtAuthor.htmlText ="<a href='http://yjmyzz.cnblogs.com/' target='_blank'>by 菩提树下的杨过</a>";
181 addChild(txtAuthor);
182 txtAuthor.y = txtFocusLength.y;
183 txtAuthor.x = 425;
184 txtAuthor.autoSize = TextFieldAutoSize.LEFT;
稍加解释:
z坐标:即对象在z轴上的坐标,flash默认采用的是右手三维坐标,也就是说z值越大,物体越小
rotaionX,rotationY,rotationZ:即对象绕着x,y,z轴旋转的角度
PerspectiveProjection对象的三个属性:
1.focalLength 即焦距,使用效果上貌似焦距越大,物体也越大(?跟常规理解的不同),而且据官方帮助上讲:在透视转换过程中,将使用视野的角度和舞台的高宽比(舞台宽度除以舞台高度)来自动计算 focalLength
2.fieldOfView 即观察点的三维"视角"(0到180之间的值),怎么理解我还没想好,不过在使用效果上,如果当物体的z轴坐标不为0时,该值越大,物体的扭曲和形变越夸张,而且动态调整该值时focalLength值也会自动重新计算。(所以如果用代码写死了focalLength,不管如何调整fieldOfView都是看不到效果的)
3.projectionCenter:即3D透视中的消失点,当z轴坐标趋近于无限大时,物体越趋向于该点(消失)。
最后:上面的代码中暗藏了二个小技巧
1.为啥要先把图片放到imgSprite中,然后再将imgSprite又放到containerSprite中?
因为旋转时有一个旋转的中心点,而Flash默认这个中心就是对象的左顶点,即(0,0)位置,用二个sprite嵌套后,再配合坐标的设定,巧妙的将中心点正好移动到了图片中心,如下图:

2.如何用代码从库里取出一张图片?

如上图,关键在于导入图片时要指定“类”名,这样在代码中就可以用
1 var imgBD:BitmapData = new ImgSample();//从库中取出一张图片
2 var img:Bitmap = new Bitmap(imgBD);
得到一个图片的Bigmap实例
浙公网安备 33010602011771号