AS3 2D轉3D【算法】

FLASH只是有二維的座標.怎麼把三維座標轉換成二維座標:
(一).公式
    給定點:(x,y,z)
    繞x軸旋轉後的點(x1,y1,z1)
    繞y軸旋轉後的點(x2,y2,z2)
    繞z軸旋轉後的點(x3,y3,z3)
 1.x旋轉(x不變):
 x1=x
 y1=y*cosb+z*sinb
 z1=z*cosb-y*sinb
    2.y旋轉(y不變):
 x2=x*cosb-z*sinb
 y2=y
 z2=z*cosb+x*sinb
    3.z旋轉(z不變)
    x3=x*cosb-y*sinb
 y3=y*cosb+x*sinb
 z3=z
 
(二).原理分析
1.三角形定理:
如上圖,已知一個點(x,y,z),利用三角形相似的原理,可以得出下列結論:
  d/(d+z)=y1/y,推出:y1=d*y/(d+z),可在二維平面上來表現空間上的點的位置。進一步把它簡化。提出因子d/(d+z),用ratio(比率)表示,這個公式就變爲
  ratio=d/(d+z);
  y1=ratio*y;同理可推出
  x1=ratio*x;
 
2.flash模擬3D座標:
如上圖,z軸表示一個物體離屏幕的遠近,當物體的z軸位置增加時,物體朝遠離屏幕的方向運動,當物體的z值減小時,物體朝接近屏幕的方向運動。在三維座標中,當z值增大,也就是遠離屏幕時,物體應越小,反之越大。我們可以用上面的ratio,當z增加時,ratio減少,因爲在ratio中,z是作爲分母的。反之,當z減少時,ratio增加。所以可用ratio來控制mc的大小。z值最大,物體應在最底層,最小,在最上層。
 
3.公式推導:
旋轉有三種,x旋轉:座標x不變,y旋轉:y不變,z旋轉:z不變,我們先來推導z旋轉。如上圖:從點(x,y,0)轉到(x1.y1.0),求點(x1.y1.0)
利用數學中的正弦、餘弦公式得出
  x1=r*cos(a+b),而cos(a+b)=sina*cosb+cosa*sinb
  推出:x1=r(cosa*cosb-sina*sinb)
  又因爲x=r*cosa,y=r*sina
  所以x1=x*cosb-y*sinb
  同樣推出:y1=y*cosb+x*sinb
  這就是z旋轉的公式。用同樣的方法可推出x旋轉,y旋轉的公式。總結如下:
給定點:(x,y,z)
繞x軸旋轉後的點(x1,y1,z1)
繞y軸旋轉後的點(x2,y2,z2)
繞z軸旋轉後的點(x3,y3,z3)
 x旋轉(x不變)
 x1=x
 y1=y*cosb-z*sinb
 z1=z*cosb+y*sinb
注:是先加後減,因爲FLASH裏的Y軸是反的,箭頭向下的。 即:
 y1=y*cosb+z*sinb
 z1=z*cosb-y*sinb
 
同理推出:
 y旋轉(y不變)
 x2=x*cosb-z*sinb
 y2=y
 z2=z*cosb+x*sinb

 z旋轉(z不變)
 x3=x*cosb-y*sinb
 y3=y*cosb+x*sinb
 z3=z
  從以上公式可看出,在flash要實現旋轉,先要求x軸的旋轉點,再求y軸的旋轉點,最後再求出z軸的旋轉點。
 
(三).實例應用
最後我們來一個y旋轉的AS3應用(複製代碼到時間軸即可)
// 全局變量
var mcNums:Number=3;
var mcArr:Array = new Array();
var rocArr_x:Array=new Array(100,-100,0);
var rocArr_y:Array=new Array(0,10,0);
var rocArr_z:Array=new Array(-100,0,0);
var hutu:Number=0.001;// 控制旋轉的速度
var jiaodu:Number=hutu*180/Math.PI;
var distance:int=1000;

initConfig();

//初始化
function initConfig():void {
  for (var i=1; i<=mcNums; i++) {
    var t:MovieClip=doDrawRoundRect(); 
    //t.angle = i * ((Math.PI*2)/mcNums);
    this.addChild(t);
    mcArr.push( t );
  }
  addEventListener(Event.ENTER_FRAME, EnterFrame);
}

//刷頻
function EnterFrame(e:Event) {
  for (var i = 0; i<mcNums; i++) {
    // 按公式計算
    var x1=rocArr_x[i]*Math.cos(jiaodu)-rocArr_z[i]*Math.sin(jiaodu);
    var y1=rocArr_y[i];
    var z1=rocArr_z[i]*Math.cos(jiaodu)+rocArr_x[i]*Math.sin(jiaodu);
    //賦值
    rocArr_x[i]=x1;
    rocArr_y[i]=y1;
    rocArr_z[i]=z1;
    // 更新數組元素
    var ratio:Number = distance/(distance+z1);
    var perspective_x=x1*ratio;
    var perspective_y=y1*ratio;
    var perspective_z=z1*ratio;
    // 賦值X Y座標 
    mcArr[i].x=stage.stageWidth/2+perspective_x;
    mcArr[i].y=stage.stageHeight/2-perspective_y;
    // mc的大小
    mcArr[i].scaleX=mcArr[i].scaleY=80*ratio/100;
    mcArr[i].alpha=50*ratio
    // mc的層次
    this.setChildIndex(mcArr[i],ratio);
  }
}

//產生隨機顏色的矩形影片
function doDrawRoundRect():MovieClip {
  var size:uint=80;
  var bgColor:uint=Math.random()*0xffffff;
  var borderColor:uint=0x666666;
  var borderSize:uint=0;
  var cornerRadius:uint=9;
  var gutter:uint=5;
  var child:MovieClip = new MovieClip();
  child.graphics.beginFill(bgColor);
  child.graphics.lineStyle(borderSize, borderColor);
  child.graphics.drawRoundRect(0, 0, size, size, cornerRadius);
  child.graphics.endFill();
  return child;
}

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章