前面我们讨论过了如何横向旋转和移动摄像机希望你已经完全理解本文中内容是紧接着上篇来回想下在前面我们制做动画中摄像机旋转直是围绕着y轴(竖直向上轴)旋转然而现实中我们可以上下旋转摄像机甚至可以把摄像机倾斜定角度这就提醒了我们还需要更深入研究旋转这个课题下面几个动画演示了我们摄像机(简单摄像机轮廓)3种旋转模式从左到右分别是横向旋转纵向旋转倾斜从我们3D空间角度来说分别是沿yx和z轴旋转
横向和纵向旋转摄像机
倾斜摄像机
再介绍些 3角方程
事情变得复杂起来了!不过请你还是保持头脑清醒这篇文章你任务就是学会纵向旋转和倾斜摄像机你也许会想我已经学会了横向旋转摄像机算法中我们使用了个panning变量代表旋转角度那么我再加两个变量然后按顺序先沿x旋转然后再沿y最后z旋转不就好了Well这种想法很接近但却是错(不要把3D数学想那么简单)来看下下面两个图还是以3D空间在2D平面上投影举例我们把线段OB沿着z轴(也就是2D平面上 原点)旋转大约78度可以看到OB长度就是我们旋转半径那么接下来我们把OB沿y轴旋转看下图中旋转半径是多少?不难看出我们旋转半径明显变小了继续如果你沿y旋转后再打算沿x轴旋转你还是会有同样“半径变化”问题
先沿z轴旋转再试图沿y旋转
在上面例子中如果想要保持旋转半径不变那么开始我们就不要沿z旋转不过我们拿着摄像机左转右转如何可能保持角度不变!?因此你要在每次摄像机旋转后计算新旋转半径可是如果每次我们都把旋转半径计算出来那定是很头疼!
于是我们聪明想到了省力思路方法首先让我们再看下2D 3角(又是 3角)我们根据旋转半径和旋转角度可以得到x和y:
x=Math.cos(angle)*radius;
y=Math.sin(angle)*radius;
需要注意点上面方程式旋转点为原点并且的前旋转角度为0如果我们的前就有旋转角度a再旋转b那么我们方程式就成了:
x=Math.cos(a+b)*radius;
y=Math.sin(a+b)*radius;
看起来眼熟但是不知道是什么了?别担心:
cos(a+b)=cos(a)*cos(b)-sin(a)*sin(b);
sin(a+b)=sin(a)*cos(b)+sin(b)*cos(a);
把cos(a+b)和sin(a+b)带入上面x和y求值方程我们就有:
x=radius*cos(a)*cos(b)-radius*sin(a)*sin(b);
y=radius*sin(a)*cos(b)+radius*sin(b)*cos(a);
化简下得到:
x=x_before*cos(b)-y_before*sin(b);
y=x_before*sin(b)+y_before*cos(b);
这样我们使用上面两个方程不用担心你在其他平面(xz或者yz平面)旋转角度了也不用每次旋转后再去计算物体新旋转半径了我们只要关心旋转后x和y并且把它们作为下次旋转x_before和y_before问题就解决了下面我把相应方程式写上:
围绕y轴旋转pan角度:
x=Math.cos(pan)*x_before-Math.sin(pan)*z_before;
z=Math.sin(pan)*x_before+Math.cos(pan)*z_before;
围绕x轴旋转pitch角度:
y=Math.cos(pitch)*y_before-Math.sin(pitch)*z_before;
z=Math.sin(pitch)*y_before+Math.cos(pitch)*z_before;
围绕z轴旋转tilt角度:
x=Math.cos(tilt)*x_before-Math.sin(tilt)*y_before;
y=Math.sin(tilt)*x_before+Math.cos(tilt)*y_before;
那么基本知识已经说完了整理总结下当你在使用这些方程式操作摄像机全方位旋转时候只要取得相应变量然后替换在方程里就可以了是不是看起来有点 难理解?不要担心适应这些东西是需要花点时间(特别是这些对你来说还是新课题话)不过适应以后你应该就觉得很简单了坦白说其实你并不需要知 道到底这些是怎样得来你只要知道如何使用它们从而得到想要得结果就可以了(当然完全理解会对你以后学习有些帮助)这些方程你可以写成个然 后命名它为“给我旋转”方程当你需要摄像机旋转时候只要呼唤“给我旋转”就好了至于“给我旋转”如何做工作你就不需要担心了
全方位旋转摄像机
只说这些理论东西你肯定会觉得乏味那么我举个例子来介绍说明下面这个演示了摄像机全方位旋转运行你会看到你置身在个巨大正方体中这个正方体是由很多我们朋友小P组成不过这回我们用区别颜色小P来代表区别边使用WS键控制纵向旋转AD键控制横向旋转QE控制倾斜角度鼠标点击屏幕禁止或者允许鼠标移动控制纵向和横向旋转
全方位旋转摄像机使用WS纵向旋转AD横向旋转QE倾斜角度鼠标点击禁止或者允许鼠标控制
制作步骤:
1. 首先定义几个常量MAX_OBJ是我们每条边上物体数量CUBE_WIDTH是我们正方体边长
//constants
varMAX_OBJ= 6;
varPI=3.1415926535897932384626433832795;
varCUBE_WIDTH=300;
2. 下面还是设置原点场景焦距等
//sameasusual
varorigin=Object;
origin.x=stage.stageWidth/2;
origin.y=stage.stageHeight/2;
origin.z=0;
varscene=Sprite;
scene.x=origin.x;
scene.y=origin.y;
this.addChild(scene);
varfocal_length= 400;
3. 设置摄像机这回我们摄像机多了几个新属性pitching是纵向旋转角度tilt是倾斜角度
varcamera=Object;
camera.x=0;
camera.y=0;
camera.z=0;
camera.panning=-PI/8; //initpanangleofourcamera,panleft
camera.pitching=-PI/8; //pitchup
camera.tilt=0; //andnotilt
4. 设置些全局变量在我们处理键盘和鼠标事件时会用到
//globalbooleansforourkeyboardcontrol
varpan_left;
varpan_right;
varpitch_up;
varpitch_down;
varmouse_ctl=true;
5. 下面我们步置个正方体你完全不必要明白我是如何布置场景布置场景方式并不唯所以如果你愿意话你可以自己动手布置3D场景当然我也不介意直接拷贝我设置场景代码去用总的这些代码就是化些小P然后把它们摆放在合适位置(围绕着我们摄像机)
//ok,hereyoudon'thavetoknowhowiacutallyupthecube
//causeeverybodyhasadferentwayofdoingthat,youreally
//erestedinhowididit,thenyoumayhavealook
//youcanjustcopymycodeanditwillitupforyou
varlen=CUBE_WIDTH/2;
for(varseg=0;seg<3;seg)
{
varline_h;
varline_v;
varline_z;
switch(seg)
{
0:
line_h=true;
line_v=false;
line_z=false;
;
1:
line_h=false;
line_v=true;
line_z=false;
;
2:
line_h=false;
line_v=false;
line_z=true;
;
}
for(vari=0;i<MAX_OBJ;i)
{
(line_h||(i0||iMAX_OBJ-1))
{
for(varj=0;j<MAX_OBJ;j)
{
(line_v||(j0||jMAX_OBJ-1))
{
for(vark=0;k<MAX_OBJ;k)
{
(line_z||(k0||kMAX_OBJ-1))
{
varball;
(line_h)
{
ball=SphereHorizontal;
((i0||iMAX_OBJ-1))
{
ball=SphereVertex;
}
{
ball=SphereHorizontal;
}
}
(line_v)
{
ball=SphereVertical;
((j0||jMAX_OBJ-1))
{
continue;
}
}
(line_z)
{
ball=SphereStraight;
((k0||kMAX_OBJ-1))
{
continue;
}
}
ball.x_3d=-len+(i)*(CUBE_WIDTH/MAX_OBJ);
ball.y_3d=-len+(j)*(CUBE_WIDTH/MAX_OBJ);
ball.z_3d=-len+(k)*(CUBE_WIDTH/MAX_OBJ);
scene.addChild(ball);
}
}
}
}
}
}
}
6. 下面就是刷新小P位置和大小这也是这篇文章主要讲述内容所以请集中OK首先我们要得出小P(其中个小P)到摄像机xy和z 距离对于横向旋转角度panning我们使用本文前面讲述方程把相应x距离和z距离带入然后我们得出新x距离和z距离使用相同思路方法得出 纵向旋转角度pitching后y和z距离对摄像机倾斜角度tilt我们在次使用上述方程这样我们就得到围绕 3个轴旋转后新xy和z距离继而 便可以使用老办法算出物体缩放和移动最后别忘记加个z_near变量存储小P到摄像机距离以便于我们对所有小P进行z排序
//updateballsizeandposition
//hereiswhatwereallycareabout,soconcentrate
functiondisplay(obj)
{
varx_distance=obj.x_3d-camera.x; //firstwedeterminexdistanceballtocamera
vary_distance=obj.y_3d-camera.y; //y
varz_distance=obj.z_3d-camera.z; //zdistance
vartempx,tempy,tempz; //sometemporaryvariables
//twomoretrigyouneedtoknowabout,supposeaisthepreviousangle
//cos(a+b)=cos(a)*cos(b)-sin(a)*sin(b)
//sin(a+b)=sin(a)*cos(b)+cos(a)*sin(b)
//thuswehavethefollowing
varangle=camera.panning;
tempx=Math.cos(angle)*x_distance-Math.sin(angle)*z_distance;
tempz=Math.sin(angle)*x_distance+Math.cos(angle)*z_distance;
x_distance=tempx;
z_distance=tempz;
angle=camera.pitching; //thesamethingwehaveforpitchangle
tempy=Math.cos(angle)*y_distance-Math.sin(angle)*z_distance;
tempz=Math.sin(angle)*y_distance+Math.cos(angle)*z_distance;
y_distance=tempy;
z_distance=tempz;
angle=camera.tilt; //andtiltangle
tempx=Math.cos(angle)*x_distance-Math.sin(angle)*y_distance;
tempy=Math.sin(angle)*x_distance+Math.cos(angle)*y_distance;
x_distance=tempx;
y_distance=tempy;
(z_distance>0) //theballisinfrontofthecamera
{
(!obj.visible)
obj.visible=true; //maketheballvisibleanyway
varscale=focal_length/(focal_length+z_distance); //calthescaleoftheball
obj.x=x_distance*scale; //calcualtethexpositioninacameraview
obj.y=y_distance*scale; //andyposition
obj.scaleX=obj.scaleY=scale; //scaletheballtoaproperstate
}
{
obj.visible=false;
}
obj.z_near=z_distance; //keeptrackofzdistancetoourcamera
}
7. 写个循环不停第6步刷新所有小P如果你直有看文章话那么这些对你来说应该不难
//looptoupdatethescreen
functionrun(e:Event)
{
for(vari=0;i<scene.numChildren;i) //updatealltheballsonthescreen
{
display(scene.getChildAt(i));
}
swap_depth(scene);
}
//bubblesortalgo
functionswap_depth(container:Sprite)
{
for(vari=0;i<container.numChildren-1;i)
{
for(varj=container.numChildren-1;j>0;j--)
{
(Object(container.getChildAt(j-1)).z_near<Object(container.getChildAt(j)).z_near)
{
container.swapChildren(container.getChildAt(j-1),container.getChildAt(j));
}
}
}
}
8. 最后是设置些键盘和鼠标事件响应完成我们
functionkey_down(e:KeyboardEvent):void
{
(e.keyCode65) //a
pan_left=true;
(e.keyCode68) //d
pan_right=true;
(e.keyCode87) //w
pitch_up=true;
(e.keyCode83) //s
pitch_down=true;
}
functionkey_up(e:KeyboardEvent):void
{
(e.keyCode65)
pan_left=false;
(e.keyCode68)
pan_right=false;
(e.keyCode87)
pitch_up=false;
(e.keyCode83)
pitch_down=false;
}
functionkey_response(e:Event):void
{
(pan_left)
camera.panning-=0.01;
(pan_right)
camera.panning0.01;
(pitch_up)
camera.pitching-=0.01;
(pitch_down)
camera.pitching0.01;
(mouse_ctl) //allowmousecontrolpanandpitch
{
camera.panningscene.mouseX/22000;
camera.pitchingscene.mouseY/22000;
}
//limitthepitchandtilt
(camera.pitching<-1*PI/3)
camera.pitching=-1*PI/3;
(camera.pitching>PI/3)
camera.pitching=PI/3;
}
functionclicked(e:Event) //togglemousecontrol
{
mouse_ctl=!mouse_ctl;
}
//upeventlisteners
this.addEventListener(Event.ENTER_FRAME,run);
this.addEventListener(Event.ENTER_FRAME,key_response);
stage.addEventListener(KeyboardEvent.KEY_DOWN,key_down);
stage.addEventListener(KeyboardEvent.KEY_UP,key_up);
stage.addEventListener(MouseEvent.CLICK,clicked);
整理总结下这篇文章中 3角部分可能有些抽象我们是在3D空间中完成不过还是那句话不要担心你只要知道如何使用这些方程就可以了
注意:物体自身围绕中心3D旋转
有点不知道你有没有注意那就是在本文开头我做了几个摄像机旋转演示在演示里摄像机(物体)都是本身在旋转而并不是我们眼睛(摄像机) 在旋转虽然到目前为止文章里还没有讨论到如何让物体自身旋转不过我们很快就会看到些例子我做这些演示唯想介绍说明就是 3种旋转机制所以不 要着急那些演示是如何做出来会慢慢好起来
其实有关Flash和3D空间基本知识介绍到这里我想应该结束了从下篇文章开始我们就要关注3D物体因此如果你对前面文章中基础知识还是模模糊糊话你完全可以不必担心不过我还是建议你自己多实验些小例子增加自己空间感相信你在不久将来就可以开发自己3D Engine了加油ALL THINGS ARE POSSIBLE
相关文章:
Flash和3D编程探秘( 7)- 3D物体框架
Flash和3D编程探秘( 6)- 全方位旋转摄像机
Flash和3D编程探秘()- Flash和3D空间
Flash和3D编程探秘( 5)- 摄像机旋转和移动
Flash和3D编程探秘( 4)- 摄像机旋转基础知识
Flash和3D编程探秘( 3)- 摄像机(Camera)
作者:YangZhou
出处:http://yangzhou1030.cnblogs.com/
感谢:Yunqing
最新评论