![]() ![]() 前几天参考了ox的贴子,总算弄出来了,用了好多ox的东西。。。呵呵 http://bbs.flashempire.net/showthread.php?t=183141&page=2 上面这个就是ox在闪帝的长篇大补贴,讨论3D贴图的 很早就看过“小小”做的3D烟盒,很想自己也做个,于是开始学习3D方面的东西, 但是进展很慢,而且断断续续的,在参考了很多源代码之后,终于弄出了个 3D球棍模型http://www.5dblog.com/user2/jh7086/index.asp?id=19656 空间点的基本变换和简单消隐算是搞懂些了,但是还是没弄出贴图来,想到“小小” 的贴图是将图片分割成三角形的,于是我以为,只要能将一个三角形的图片进行 任意的变换UploadFile/2004-11/20041125201957997.swf 就可以贴图了,但是“小小”为什么把每个面分割成4个三角形,而不是2个呢, 直到那天看了ox的帖子才明白:贴图并不是简单的顶点坐标映射,要做真正的 透视贴图,必须按像素级别切割图片,这在Flash里是不现实的,“小小”的每个面 是用4个三角形平行透视后拼成的(不知道为什么会想到要这样做) 楼下的代码中最关键的就是将正方形的MC贴到任意平行四边形那一段,我是直接 //------------------------------------------------------------------------- // 平行透视引擎 // vol 0.03 // 初步完成映射贴图 // 上下左右、PageUp、PageDown旋转画面 //-------------------------------------------------------------- // 初始化 //坐标:垂直屏幕的方向为z坐标 //顶点表 dot=[]; //平行四边形表,需要三个顶点(第四个顶点由其他3个计算出来)和一个贴图信息,顶点 va\vb\vc绕向顺时针为正 Rectlist=[]; CameraCenterX=275; //镜头中心x/y CameraCenterY=200; NotRanderPosX=-100000; //把所有不渲染的贴图_x移到这个位置 //开始画一个方形盒子,他有8个顶点,6个面 dot[0]={x:-100,y:50,z:-100};//左下前 dot[1]={x:100,y:50,z:-100};//右下前 dot[2]={x:100,y:-50,z:-100};//右上前 dot[3]={x:-100,y:-50,z:-100};//左上前 dot[4]={x:-100,y:50,z:100};//左下后 dot[5]={x:100,y:50,z:100};//右下后 dot[6]={x:100,y:-50,z:100};//右上后 dot[7]={x:-100,y:-50,z:100};//左上后 Rectlist[0]={va:dot[0],vb:dot[1],vc:dot[2],vd:dot[3],pp_name:"pp_021"}; //前面 Rectlist[1]={va:dot[5],vb:dot[4],vc:dot[7],vd:dot[6],pp_name:"pp_022"}; //后面 Rectlist[2]={va:dot[3],vb:dot[2],vc:dot[6],vd:dot[7],pp_name:"pp_023"}; //上面 Rectlist[3]={va:dot[0],vb:dot[4],vc:dot[5],vd:dot[1],pp_name:"pp_024"}; //下面 Rectlist[4]={va:dot[4],vb:dot[0],vc:dot[3],vd:dot[7],pp_name:"pp_025"}; //左面 Rectlist[5]={va:dot[1],vb:dot[5],vc:dot[6],vd:dot[2],pp_name:"pp_026"}; //右面 //初始化贴图 //所有贴图都必须是100*100的正方形,所有贴图放在"TextureLayer"里面 this.createEmptyMovieClip("TextureLayer",2); for(var i in Rectlist){ //贴图绑定 Rectlist[i].actable=true; //并且通过检测这个变量,做到尽量不执行AS var Texturenow=Texturelayer.createEmptyMovieClip("套子"+i,i); //.............................................................. Rectlist[i].texture2=[]; //"texture2[]"用于指向这个面的4个三角形 for(var j=0;j<4;j++){ //将每个面分割为4个三角形(上-右-下-左) var Texturenow2=Texturenow.createEmptyMovieClip("三角图"+i+"_"+j,(i+1)*(j+1)); //Texturenow2.j=j;//j为0-1-2-3,分别对应于四个三角形:0上-1右-2下-3左 var pic=Texturenow2.createEmptyMovieClip("pic",0); //----------建立三角形遮罩------- var maskMC=pic.createEmptyMovieClip("遮罩",1); maskMC.lineStyle(0,0); maskMC.beginFill(0); maskMC.moveTo(2,2); maskMC.lineTo(-100,0); maskMC.lineTo(0,-100); maskMC.lineTo(1,1); maskMC.endFill(); var maskedMC=pic.attachMovie(Rectlist[i].pp_name,"pic00",0);//贴上原始图片 maskedMC._rotation=-45-90*j;//原始图片旋转到指定角度 maskedMC.setMask(maskMC); //------------end--------------- Texturenow2._visible=0; Rectlist[i].texture2[j]=Texturenow2; } //............................................................. //Texturenow._visible=0; //移出屏幕 //Texturenow._alpha=50; Rectlist[i].texture=Texturenow;//"texture"用于指向这个面的整个图形 } //--------------------------------------------------------------------------- // 渲染函数 // ====================将正方形的MC贴到任意平行四边形======================= function renderTriTexture(va, vb, vc, textureMC){ var Rander=false; //a、c相对b的坐标(a,b) (c,d) var a=va.vx-vb.vx var b=va.vy-vb.vy var c=vc.vx-vb.vx var d=vc.vy-vb.vy //检验表面方向,如果顶点A、B、C旋向为逆时针则为正面 if (a<0&&d>=c*b/a) Rander=true; else if (a>0&&d<=c*b/a) Rander=true; else if (a==0){ if (b>0&&c>=0) Rander=true; if (b<=0&&c<0) Rander=true; } //第三步把图形逆时针转动角Angle3 = 0.5 * arctg( 2(ab+cd) / bb+dd-aa-cc ) if(Rander){ var Angle3=0.5*Math.atan(2*(a*b+c*d)/(b*b+d*d-a*a-c*c)); if (!isFinite(Angle3)) Angle3=1.5707963267949 var cosAngle3=Math.cos(Angle3); var sinAngle3=Math.sin(Angle3); //第二步的结果设为(Xa,Ya) ,(0,0) , (Xc,Yc),就是将最终显示顺时针转动Angle3 var Xa=a*cosAngle3-b*sinAngle3; var Ya=a*sinAngle3+b*cosAngle3; var Xc=c*cosAngle3-d*sinAngle3; var Yc=c*sinAngle3+d*cosAngle3; //要注意某数为0的错误 if(Xa==0&&Xc==0||Ya==0&&Yc==0){ rander=false; }else if (Yc!=0&&Ya!=0){ var scale=Xa/Yc; //横纵相对缩放率 var reallength=Math.sqrt(Xc*Xc+Yc*Yc*scale*scale)//正方形整体拉伸之后边长 var xscale=reallength/100; //第二步要设置的贴图的_xscale var yscale=reallength/100*Yc/Xa //和_yscale //第一步图形顺时针旋转Angle1 var Angleco=180/Math.PI; //弧度->角度转换系数 if ((Ya/scale)<=0) var Angle1=90-Math.atan(Xa/Ya/scale)*Angleco else if ((Ya/scale)>0) var Angle1=270-Math.atan(Xa/Ya/scale)*Angleco }else if(Ya==0){ var xscale=Xa/100; var yscale=Yc/100; Angle1=180 }else if(Yc==0){ var xscale=Xc/100; var yscale=Ya/-100; Angle1=90; } } //开始贴图 //------------------------------------- if(Rander){ textureMC._visible=1; textureMC._x=CameraCenterX+vb.vx; textureMC._y=CameraCenterY+vb.vy; textureMC._xscale=100*xscale; textureMC._yscale=100*yscale; textureMC.pic._rotation=Angle1; textureMC._rotation=-1*Angle3*Angleco }else{ textureMC._visible=0; } } //===========================end======================== // //=========================透视贴图映射==================== function FillTexture(){ for(var i in Rectlist){ var Rectnow=Rectlist[i]; if (Rectnow.actable){ //如果这个面允许渲染 //计算这个面的几何中心的屏幕坐标 var vo={},va={},vb={},vc={}; vo.x=(Rectnow.va.x+Rectnow.vc.x)/2; vo.y=(Rectnow.va.y+Rectnow.vc.y)/2; vo.z=(Rectnow.va.z+Rectnow.vc.z)/2; vb=getOne_toxy(V_d,vo); for(var j=0;j<4;j++){ var textureMC=Rectnow.texture2[j]; switch (j) { //0上--1左--2下--3右 case 0 : va=Rectnow.va; vc=Rectnow.vb; break; case 1 : va=Rectnow.vb; vc=Rectnow.vc; break; case 2 : va=Rectnow.vc; vc=Rectnow.vd; break; case 3 : va=Rectnow.vd; vc=Rectnow.va; break; } renderTriTexture(va, vb, vc, textureMC); } } } } //===========================end============================= // // 面排序 function SortPolygon(){ for(var i in Rectlist){ var Rectnow=Rectlist[i]; Rectnow.texture.swapDepths(i-10*(Rectnow.va.z+Rectnow.vc.z)); } } // 线框渲染 function RanderByLine(){ createEmptyMovieClip("linelayer",100); linelayer._x=CameraCenterX; linelayer._y=CameraCenterY; linelayer.lineStyle(1,0x504040); for(var i in Rectlist){ if (!Rectlist[i].actable) continue; var Rectnow=Rectlist[i] linelayer.moveTo(Rectnow.va.vx,Rectnow.va.vy); linelayer.lineTo(Rectnow.vb.vx,Rectnow.vb.vy); linelayer.lineTo(Rectnow.vc.vx,Rectnow.vc.vy); linelayer.lineTo(Rectnow.vd.vx,Rectnow.vd.vy); linelayer.lineTo(Rectnow.va.vx,Rectnow.va.vy); } } //----------------------以上部分为ox老大所作----------------------------- //----------------------以下部分是自己抄来的------------------------------- //3d变换部分的函数 // // 单个空间点旋转变换,xa,ya,za均为角度值,dotArray为存储点集的数组名,num为需要操作的空间 点的编号 function dot_rotate(xa, ya, za, dotArray,num) { var rad = Math.PI/180; xa *= rad; ya *= rad; za *= rad; var sin_xa = Math.sin(xa); var cos_xa = Math.cos(xa); var sin_ya = Math.sin(ya); var cos_ya = Math.cos(ya); var sin_za = Math.sin(za); var cos_za = Math.cos(za); var px, py, pz, tempx, tempy, tempz; px = dotArray[num].x; py = dotArray[num].y; pz = dotArray[num].z; tempx = (pz*cos_xa)-(py*sin_xa); tempy = (px*cos_ya)-(pz*sin_ya); tempz = (py*cos_za)-(px*sin_za); // // dotArray[num].x = (py*sin_za)+(px*cos_za); dotArray[num].x = (py*sin_za)+(tempy*cos_za); dotArray[num].y = (pz*sin_xa)+(tempz*cos_xa); // dotArray[num].z = (pz*cos_xa)-(tempz*sin_xa); dotArray[num].z = (px*sin_ya)+(tempx*cos_ya); // // } //整个点集的旋转变换:xa,ya,za均为角度值,dotArray为存储点集的数组名 function dot_rotateAll(xa, ya, za, dotArray) { for(var i in dotArray){ dot_rotate(xa, ya, za, dotArray,i); } } //将单个空间点透视投影到xy平面,d为视点到投影面的距离,dot为需要作透视投影的点 function getOne_toxy(d,dot) { var k = 1-dot.z/d; dot.vx = dot.x/k; dot.vy = -dot.y/k; return dot; } // 将空间点集透视投影到xy平面,d为视点到投影面的距离,dotArray为存储点集的数组名 function getAll_toxy(d,dotArray) { for (var i in dotArray) { var k = 1-dotArray[i].z/d; dotArray[i].vx = dotArray[i].x/k; dotArray[i].vy = -dotArray[i].y/k; } } // //----------------------主程序段-------------------------------------------------------- V_d=500; dot_rotateAll(0,30,0,dot); // 按键响应和渲染 onEnterFrame=function(){ if(Key.isDown(Key.LEFT)) dot_rotateAll(0,1,0,dot); else if(Key.isDown(Key.RIGHT)) dot_rotateAll(0,-1,0,dot); else if(Key.isDown(Key.UP)) dot_rotateAll(1,0,0,dot); else if(Key.isDown(Key.DOWN)) dot_rotateAll(-1,0,0,dot); else if(Key.isDown(Key.PGUP)) dot_rotateAll(0,0,1,dot); else if(Key.isDown(Key.PGDN)) dot_rotateAll(0,0,-1,dot); getAll_toxy(V_d,dot);//顶点的透视投影 //RanderByLine();//线框渲染 SortPolygon();//面排序 FillTexture();//贴图 } //-----------------------主程序完------------------------------------------------------- |
回复Comments
作者:
{commentrecontent}