Flash/Flex学习笔记(49):3D基础 里已经介绍了3D透视的基本原理,不过如果每次都要利用象该文中那样写一堆代码,估计很多人不喜欢,事实上AS3的DisplayObject类已经内置了z坐标、rotationX、rotationY、rotationZ属性,再加上PerspectiveProjection类用于处理透视转换,基本上可以满足大多数的3D要求。
import flash.events.Event; import flash.display.Sprite; import flash.text.TextField; import flash.events.MouseEvent; import flash.text.TextFieldAutoSize; var isAngleChangeing = false; var txtX:TextField,txtY:TextField,txtZ:TextField,txtPosZ:TextField,txtFieldOfView:TextField,txtInfo:TextField,txtCenter:TextField,txtFocusLength:TextField; txtX = new TextField(); txtX.text = "rotationX:"; txtY = new TextField(); txtY.text = "rotationY:"; txtZ = new TextField(); txtZ.text = "rotationZ:"; txtPosZ = new TextField(); txtPosZ.text = "Z:"; txtFieldOfView = new TextField(); txtFieldOfView.text = "视角:"; txtCenter = new TextField(); txtCenter.text = "消失点:" txtFocusLength = new TextField(); txtFocusLength.text = "焦距:"; txtX.y = txtY.y = txtZ.y = 5; txtX.x = txtPosZ.x = 10; txtPosZ.y = txtX.y + 26; txtPosZ.x += 40; txtY.x = txtX.x + 180; txtZ.x = txtY.x + 180; txtFieldOfView.x = txtPosZ.x + 160; txtFieldOfView.y = txtPosZ.y; txtCenter.x = txtFieldOfView.x + 170; txtCenter.y = txtPosZ.y; txtInfo = new TextField(); txtInfo.text=""; txtFocusLength.x = txtX.x + 25; txtFocusLength.y = txtPosZ.y + 25; var imgBD:BitmapData = new ImgSample(); var img:Bitmap = new Bitmap(imgBD); trace("img.width=",img.width,",img.height=",img.height); var imgSprite:Sprite = new Sprite(); img.x = - img.width / 2; img.y = - img.height / 2; imgSprite.addChild(img); trace("imgSprite.width=",imgSprite.width,",imgSprite.height=",imgSprite.height); var containerSprite:Sprite = new Sprite(); containerSprite.addChild(imgSprite); imgSprite.x = img.width / 2; imgSprite.y = img.height / 2; addChild(containerSprite); trace("containerSprite.width=",containerSprite.width,",containerSprite.height=",containerSprite.height); containerSprite.x = stage.stageWidth / 2 - containerSprite.width / 2; containerSprite.y = stage.stageHeight / 2 - containerSprite.height / 2; containerSprite.z = 50; var silderX:SimpleSlider = new SimpleSlider(0,360,0); silderX.x = txtX.x + 160; silderX.y = txtX.y + 7; silderX.rotation = 90; var silderY:SimpleSlider = new SimpleSlider(0,360,0); silderY.x = txtY.x + 160; silderY.y = silderX.y; silderY.rotation = 90; var silderZ:SimpleSlider = new SimpleSlider(0,360,0); silderZ.x = txtZ.x + 160; silderZ.y = silderX.y; silderZ.rotation = 90; var silderPosZ:SimpleSlider = new SimpleSlider(-200,200,50); silderPosZ.x = txtX.x + 160; silderPosZ.y = silderX.y + 25; silderPosZ.rotation = 90; var silderFieldOfView:SimpleSlider = new SimpleSlider(0.1,179.9,90); silderFieldOfView.x = silderPosZ.x + 180; silderFieldOfView.y = silderPosZ.y; silderFieldOfView.rotation = 90; var silderCenterPos:SimpleSlider = new SimpleSlider(150,400,275); silderCenterPos.x = silderFieldOfView.x + 180; silderCenterPos.y = silderPosZ.y; silderCenterPos.rotation = 90; var silderFocusLength:SimpleSlider = new SimpleSlider(100,500,300); silderFocusLength.x = silderPosZ.x ; silderFocusLength.y = silderPosZ.y + 25; silderFocusLength.rotation = 90; addChild(txtX); addChild(txtY); addChild(txtZ); addChild(txtPosZ); addChild(txtFieldOfView); addChild(txtInfo); addChild(txtCenter); addChild(txtFocusLength); addChild(silderX); addChild(silderY); addChild(silderZ); addChild(silderPosZ); addChild(silderFieldOfView); addChild(silderCenterPos); addChild(silderFocusLength); silderX.addEventListener(Event.CHANGE,silderXChangeHandler); silderY.addEventListener(Event.CHANGE,silderYChangeHandler); silderZ.addEventListener(Event.CHANGE,silderZChangeHandler); silderPosZ.addEventListener(Event.CHANGE,silderPosZChangeHandler); silderFieldOfView.addEventListener(Event.CHANGE,silderFieldOfViewChangeHandler); silderFieldOfView.addEventListener(MouseEvent.MOUSE_UP,function(){isAngleChangeing = false}); silderCenterPos.addEventListener(Event.CHANGE,silderCenterPosChangeHandler); silderFocusLength.addEventListener(Event.CHANGE,silderFocusLengthChangeHandler); function showTxtInfo(s:SimpleSlider){ txtInfo.text = s.value.toString().substr(0,5); txtInfo.x = mouseX + 20; txtInfo.y = s.y + 5; } function silderXChangeHandler(e:Event):void { imgSprite.rotationX = silderX.value; showTxtInfo(silderX); } function silderYChangeHandler(e:Event):void { imgSprite.rotationY = silderY.value; showTxtInfo(silderY); } function silderZChangeHandler(e:Event):void { imgSprite.rotationZ = silderZ.value; showTxtInfo(silderZ); } function silderPosZChangeHandler(e:Event):void { containerSprite.z = silderPosZ.value; showTxtInfo(silderPosZ); } function silderFieldOfViewChangeHandler(e:Event):void { doPerspectiveProjection(); showTxtInfo(silderFieldOfView); isAngleChangeing = true; } function silderCenterPosChangeHandler(e:Event):void { doPerspectiveProjection(); showTxtInfo(silderCenterPos); } function silderFocusLengthChangeHandler(e:Event):void { doPerspectiveProjection(); showTxtInfo(silderFocusLength); } function doPerspectiveProjection():void{ var pp:PerspectiveProjection=new PerspectiveProjection(); pp.fieldOfView = silderFieldOfView.value; if (!isAngleChangeing){ pp.focalLength = silderFocusLength.value; } //trace(pp.focalLength); pp.projectionCenter = new Point(silderCenterPos.value,silderCenterPos.value); containerSprite.transform.perspectiveProjection = pp; } doPerspectiveProjection(); var txtAuthor:TextField = new TextField(); txtAuthor.htmlText ="<a href='http://yjmyzz.cnblogs.com/' target='_blank'>by 菩提树下的杨过</a>"; addChild(txtAuthor); txtAuthor.y = txtFocusLength.y; txtAuthor.x = 425; 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.如何用代码从库里取出一张图片?
如上图,关键在于导入图片时要指定“类”名,这样在代码中就可以用
var imgBD:BitmapData = new ImgSample();//从库中取出一张图片 var img:Bitmap = new Bitmap(imgBD);
得到一个图片的Bigmap实例