从这篇文章开始我将开始介绍3D物体及其在空间中运动和交互这里提到物体是指单个实体比如银河系中颗恒星那么空间就是银河系了不过所 有切都是相对当个分子作为我们例子中实体时候那么个细胞也可以作为3D空间来看待(个细胞是由很多分子组成)同理你可以知道细胞相对于个生物(空间)来说也是个物体有些说多了不过我想让你明白我们用模拟只小狗或者个人作为个整体但是我们不可能完全真实模拟它人体由数不清细胞组成每个细胞都是个物体做着自己运动除非我们使用计算机真实模拟着人体每个细胞以及它运动否则我们永远不可能得到个真实模拟人但是使用现代计算机科技我们是不可能模拟组成人体所有细胞那就更不用说组成每个细胞分子
还是言归正传来看个3D物体例子这也是第个绘制个3D物体例子这个里我们要创建个正方体并且让它围绕着正方体对角线交点自转不过这个正方体还是由8个好朋友小P组成每个顶点站个由它们来勾勒这个正方体框架
个小P组成正方体
动画制作步骤
1. 首先在Flash IDE里绘制个物体小P
2. 开始设置还是和以前样原点摄像机焦距等等另外不要忘记创建个旋转角度object存放物体在xy和z轴旋转角度变量
//constants
varPI=3.1415926535897932384626433832795;
//originisthecenteroftheviewpoin3dspace
//everythingscalearoundthispo
//theselinesofcodewillsht3dspaceorigothecenter
varorigin=Object;
origin.x=stage.stageWidth/2;
origin.y=stage.stageHeight/2;
origin.z=0;
//focallengthofviewer'scamera
varfocal_length=300;
//nowcreateasceneobjecttoholdthespinningbox
varscene=Sprite;
scene.x=origin.x;
scene.y=origin.y
this.addChild(scene);
varaxis_rotation=Object;
axis_rotation.x=0;
axis_rotation.y=0;
axis_rotation.z=0;
varcamera=Object;
camera.x=0;
camera.y=0;
camera.z=0;
3. 写个我们用它来创建空间中个点scale_po代表这个点在投射到2D平面上后位置缩放比率
//thisfunctionconstructa3dvertex
functionvertex3d(x,y,z,scale=1):Object
{
varpo3d=Object;
po3d.x=x;
po3d.y=y;
po3d.z=z;
po3d.scale_po=scale;
po3d;
}
4. 下面发挥下你空间想象力使用第3步创建正方体8个顶点并且把它们添加到个里
//wecalculateallthevertex
varlen=50; //halfofthecubewidth
//nowcreatethevertexesforthecube
varpos=[
// x y z
vertex3d(-len, -len, -len), //rearupperleft
vertex3d(len, -len, -len), //rearupperright
vertex3d(len, -len, len), //frontupperright
vertex3d(-len, -len, len), //frontupperleft
vertex3d(-len, len, -len), //rearlowerleft
vertex3d(len, len, -len), //rearlowerright
vertex3d(len, len, len), //frontlowerright
vertex3d(-len, len, len), //frontlowerleft
];
5. 化8个小P并且把它们放在8个顶点(映射到xy轴上点)所在x和y位置
//initballsandputthemonthescreen
for(vari=0;i<pos.length;i)
{
varball=Sphere;
ball.x=pos[i].x;
ball.y=pos[i].y;
ball.z=0;
scene.addChild(ball);
}
6. 这个你在摄像机空间旋转篇文章中应该见过功能是把3D空间点映射到2D平面xy上执行步骤是这样:
a) 提前计算出xy和z旋转角度正余弦值
b) 使用for loop遍历物体所有顶点
c) 使用计算出正余弦和 3角对 3个轴旋转分别进行计算得出旋转后顶点xy和z
d) 然后计算出物体在2D平面上映射后x和y值
e) 并且把这些2D点添加到个新里
f) 最后返回这个
functionproject_pts(pos)
{
varprojected=;
//declaresomevariableforsavingfunctioncall
varsin_x=Math.sin(axis_rotation.x);
varcos_x=Math.cos(axis_rotation.x);
varsin_y=Math.sin(axis_rotation.y);
varcos_y=Math.cos(axis_rotation.y);
varsin_z=Math.sin(axis_rotation.z);
varcos_z=Math.cos(axis_rotation.z);
varx,y,z, //3dx,y,z
xy,xz, //rotateaboutxaxis
yx,yz, //rotateaboutyaxis
zx,zy, //rotateaboutzaxis
scale; //2dscaletransform
for(vari=0;i<pos.length;i)
{
x=pos[i].x;
y=pos[i].y;
z=pos[i].z;
//hereisthetheroy:
//supposeaisthecurrentangle,basedongivencurrent_x,current_yonaplane
//(canbex,yplane,ory,zplaneorz,xplane),rotateangleb
//thenthexwouldberadius*cos(a+b)andywouldbe radius*sin(a+b)
//radius*cos(a+b)=radius*cos(a)*cos(b)-radius*sin(a)*sin(b)
//radius*sin(a+b)=radius*sin(a)*cos(b)+radius*cos(a)*sin(b)
//rotateaboutxaxis
xy=cos_x*y-sin_x*z;
xz=sin_x*y+cos_x*z;
//rotateaboutyaxis
yz=cos_y*xz-sin_y*x;
yx=sin_y*xz+cos_y*x;
//rotateaboutzaxis
zx=cos_z*yx-sin_z*xy;
zy=sin_z*yx+cos_z*xy;
//scaleit
scale=focal_length/(focal_length+yz-camera.z);
x=zx*scale-camera.x; //getxpositionheviewofcamera
y=zy*scale-camera.y; //getxpositionheviewofcamera
projected[i]=vertex3d(x,y,yz,scale);
}
projected;
}
这样我们就得到个包含所有我们需要2D数据并不困难你完全可以把这段代码叫做这个3D引擎它负责了所有点数据在空间里旋转计算和输出
7. 下面是动画执行循环需要注意点在以后文章中我都将使用基于时间运动在这里你只要知道下面公式就可以了:旋转角度=角速度X时间使用上面公式我们递增物体围绕y轴和x轴旋转角度然后使用第6步计算所有3D顶点旋转后位置并且得到映射后2D点剩下你应该能想到 就是把相应小P定位到这些定点上并且对小球进行缩放比率scale_po最后不要忘记对小P进行z排序
functionmove(e:Event):void
{
//wellweuimebasedmovementhistutorial
varcurrent_time=Date.getTime; //sampethecurrenttime
//incrementtherotationaroundyaxis
axis_rotation.y0.0008*(current_time-start_time);
//incrementtherotationaroundxaxis
axis_rotation.x0.0006*(current_time-start_time);
start_time=current_time; //rethestarttime
varprojected=project_pts(pos); //3dpontsto2dtransformation
//nowwehaveallthedataweneedtopositiontheballs
for(vari=0;i<scene.numChildren;i) //loopthroughtthescene
{
//positioningtheball
scene.getChildAt(i).x=projected[i].x;
scene.getChildAt(i).y=projected[i].y;
scene.getChildAt(i).z=projected[i].z;
scene.getChildAt(i).scaleX=scene.getChildAt(i).scaleY=projected[i].scale_po;
}
swap_depth(scene); //sortoutthedepth
}
//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<Object(container.getChildAt(j)).z)
{
container.swapChildren(container.getChildAt(j-1),container.getChildAt(j));
}
}
}
}
//nowaddtheeventlistenerandsphebox
this.addEventListener(Event.ENTER_FRAME,move);
注意
例子中物体沿着x和y轴旋转但是并没有添加z轴旋转你可以自己添加上看看有什么区别
注意
例子中我们使用了两个for loop第次遍历所有顶点把3D点转化为2D点第 2个把相应小P定位到这些2D点位置虽然这样看起来会降低执行速度但是这样会使流程目了然如果你已经非常熟练你可以试着修改这两个提高执行速度
使用Flash绘制API
上面例子看起来不错不过只有顶点有小球我们看起来还不满意那么接下来做个动态绘制正方体这个例子里基本框架并没有什么变化正方体所有边都是用FlashmoveTo和lineTo来绘制那么我就把需要更改代码地方解释下
个正方体框架
制作步骤
1. 基本上代码和前面是样同样我们需要设置场景创建正方体顶点注意不要再在舞台上添加小P
2. 当我们把3D点映射到2D平面上后我们使用黑线把正方体相邻两个点连接起来非常容易理解不过注意我们有很多种办法连接这些点你可以先连接正方体顶面点然后底面点最后连接顶面和底面当然还有很多连接思路方法你总能找到合适你思维方式连接方式
functionmove(e:Event):void
{
//wellweuimebasedmovementhistutorial
varcurrent_time=Date.getTime; //sampethecurrenttime
//incrementtherotationaroundyaxis
axis_rotation.y0.0008*(current_time-start_time);
//incrementtherotationaroundxaxis
axis_rotation.x0.0006*(current_time-start_time);
start_time=current_time; //rethestarttime
varprojected=project_pts(pos); //3dpontsto2dtransformation
//nowwestartdrawingthecube
with(scene.graphics)
{
clear;
lineStyle(0.5,0x0F6F9F,1);
//topface
moveTo(projected[0].x,projected[0].y);
lineTo(projected[1].x,projected[1].y);
lineTo(projected[2].x,projected[2].y);
lineTo(projected[3].x,projected[3].y);
lineTo(projected[0].x,projected[0].y);
//bottomface
moveTo(projected[4].x,projected[4].y);
lineTo(projected[5].x,projected[5].y);
lineTo(projected[6].x,projected[6].y);
lineTo(projected[7].x,projected[7].y);
lineTo(projected[4].x,projected[4].y);
//verticallines
moveTo(projected[0].x,projected[0].y);
lineTo(projected[4].x,projected[4].y);
moveTo(projected[1].x,projected[1].y);
lineTo(projected[5].x,projected[5].y);
moveTo(projected[2].x,projected[2].y);
lineTo(projected[6].x,projected[6].y);
moveTo(projected[3].x,projected[3].y);
lineTo(projected[7].x,projected[7].y);
}
}
3. 还有个地方需要改动我们不再对顶点物体进行缩放所以就必须要传递scale_po这个属性
//thisfunctionconstructa3dvertex
functionvertex3d(x,y,z):Object
{
varpo3d=Object;
po3d.x=x;
po3d.y=y;
po3d.z=z;
po3d;
}
建议
试着把上面两种框架构建方式结合在起制作个旋转物体被线连着试试制作下面这个条螺旋体模型如果你想增加难度话你还可以做个DNA链
个螺旋体
那么到目前为止你已经知道如何使用框架构建个方体不过现实中物体总是有纹理和填充色你也许会想那么我们使用Flash beginFill就可以给物体加上填充色了Hum很接近不过如果我们要给物体上色话还有很多工作要做后面文章中我们将重点开始介绍着色筛选和相关内容
有关Time Based和Frame Based运动
文章第个例子中制作步骤里我们提到有关基于时间运动公式(只要我们知道了物体运动速度那么根据牛顿第运动定律就可以得出物体在某个时间点位移):
位移=时间X速度
回想下我们前面几篇文章里使用都是基于祯运动然而基于祯运动是不稳定它公式是:
位移=执行次数X速度
基于祯运动不管我们执行流逝了多少时间只在function执行时候给物体x或者y加减定值这种运动是不稳定所以我建议大家使用基于时间运动下面两个动画分别用两种运动模式做成点击下动画就会在function执行时执行大量junk运算这时你就会看到两种运动差异而基于时间运动中当速度恒定时物体会处在正确位置;基于祯运动你就会看到物体运动慢下来很多 并不能达到物体在某个时间点应该到达位置如果你电脑CPU不是很快话(不要忘记这个页面里还有另外3个使用大量CPU运算动画)点击这里到另外个文章里查看下面两个动画如果感觉动画还是不够连贯话那么你可以下载这两个动画到本机察看
对比基于时间和基于祯运动
相关文章:
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
最新评论