執行複雜的 3D 變形

Flash Player 10 以及更新的版本,Adobe AIR 1.5 以及更新的版本

Matrix3D 類別可讓您在座標空間中對 3D 座標點執行變形,或者將 3D 座標點從某一座標空間對應至另一座標空間。

即使不懂矩陣數學,您也一樣可以使用 Matrix3D 類別。使用這個類別的各個方法,即可處理大部分常見的變形作業。您不需要擔心要明確設定或計算矩陣中每個元素的值。

將顯示物件的 z 屬性設定為數值之後,即可使用顯示物件之 Transform 物件的 Matrix3D 屬性,擷取顯示物件的變形矩陣。

var leafMatrix:Matrix3D = this.transform.matrix3D;

您可以使用 Matrix3D 物件的各個方法,對顯示物件執行轉移、旋轉、縮放和透視投影。

使用 Vector3D 類別搭配其 x y z 屬性,即可管理 3D 座標點。這個類別也可以表示物理學上的空間向量,也就是具有方向和量值的向量。Vector3D 類別的各個方法都能讓您搭配空間向量執行常見的計算工作,例如加法、內積和外積計算。

備註: Vector3D 類別與 ActionScript 的 Vector 類別無關。Vector3D 類別包含可用於定義和操作 3D 座標點的屬性與方法,而 Vector 類別則支援具有類型之物件的陣列。

建立 Matrix3D 物件

建立或擷取 Matrix3D 物件的主要方式有三種:

  • 使用 Matrix3D() 建構函式方法,實體化新的矩陣。 Matrix3D() 建構函式會採用 Vector 物件 (包含 16 個數值),並且將每個值放在矩陣的儲存格中。例如:

    var rotateMatrix:Matrix3D = new Matrix3D(1,0,0,1, 0,1,0,1, 0,0,1,1, 0,0,0,1);
  • 設定顯示物件的 z 屬性值,再從該物件的 transform.matrix3D 屬性擷取變形矩陣。

  • 透過在根顯示物件上呼叫 perspectiveProjection.toMatrix3D() 方法,擷取控制 3D 物件在舞台上顯示方式的 Matrix3D 物件。

套用多種 3D 變形

您可以使用 Matrix3D 物件,一次套用許多 3D 變形。例如,如果您要對某一立方體依序執行旋轉、縮放和移動,可以將這三種各自分開的變形套用至立方體的每一個點。不過,另一種方式更有效率,就是在一個 Matrix3D 物件中預先計算多種變形,然後再對每一個點執行一種矩陣變形。

備註: 矩陣變形的套用順序很重要,因為矩陣計算並不具有互換性。例如,對於旋轉和轉移作業,套用的順序如果相反,所得到的結果也會不同。

在下列範例中,會示範兩個執行多種 3D 變形的方式。

package { 
    import flash.display.Sprite;     
    import flash.display.Shape; 
    import flash.display.Graphics; 
    import flash.geom.*; 
 
public class Matrix3DTransformsExample extends Sprite 
    { 
        private var rect1:Shape; 
        private var rect2:Shape; 
         
public function Matrix3DTransformsExample():void 
        { 
            var pp:PerspectiveProjection = this.transform.perspectiveProjection; 
            pp.projectionCenter = new Point(275,200); 
            this.transform.perspectiveProjection = pp; 
             
            rect1 = new Shape(); 
            rect1.x = -70; 
            rect1.y = -40; 
            rect1.z = 0; 
            rect1.graphics.beginFill(0xFF8800); 
            rect1.graphics.drawRect(0,0,50,80); 
            rect1.graphics.endFill(); 
            addChild(rect1); 
 
            rect2 = new Shape(); 
            rect2.x = 20; 
            rect2.y = -40; 
            rect2.z = 0; 
            rect2.graphics.beginFill(0xFF0088); 
            rect2.graphics.drawRect(0,0,50,80); 
            rect2.graphics.endFill(); 
            addChild(rect2); 
             
            doTransforms(); 
        } 
 
        private function doTransforms():void 
        { 
            rect1.rotationX = 15; 
            rect1.scaleX = 1.2; 
            rect1.x += 100; 
            rect1.y += 50; 
            rect1.rotationZ = 10; 
 
            var matrix:Matrix3D = rect2.transform.matrix3D; 
            matrix.appendRotation(15, Vector3D.X_AXIS); 
            matrix.appendScale(1.2, 1, 1); 
            matrix.appendTranslation(100, 50, 0); 
            matrix.appendRotation(10, Vector3D.Z_AXIS); 
            rect2.transform.matrix3D = matrix; 
        } 
    } 
}

doTransforms() 方法中,第一個程式碼區塊會使用 DisplayObject 的屬性,變更矩形形狀的旋轉、縮放、和位置設定。第二個程式碼區塊則會使用 Matrix3D 類別,執行相同的變形。

使用 Matrix3D 方法的主要優點在於,所有的計算作業都是先在矩陣中執行。然後,當顯示物件的 transform.matrix3D 屬性已設定完成時,再將計算的結果套用至顯示物件 (僅套用一次)。設定 DisplayObject 的屬性可以讓原始碼更容易讓人閱讀。不過,每次設定旋轉或縮放屬性時,這麼做就必須執行多個計算作業,並且變更多個顯示物件屬性。

如果程式碼將對多個顯示物件套用多次相同的複雜變形,請將 Matrix3D 物件儲存為變數,然後再重複執行套用的動作。

使用 Matrix3D 物件以重新排列顯示物件

如之前所提及,顯示清單中顯示物件的圖層順序會決定顯示的圖層順序,而與顯示物件的相對 z 軸無關。如果您的動畫將顯示物件的屬性改變為與顯示清單順序不同的順序,則檢視者看到的顯示物件圖層順序可能不會對應至 x 軸圖層的順序。如此一來,看起來應該遠離檢視者的物件可能會出現在較靠近檢視者的物件前方。

若要確保 3D 顯示物件的圖層順序能對應至這些物件的相對深度,請使用如下所示的方法:

  1. 使用 Transform 物件的 getRelativeMatrix3D() 方法,取得子系 3D 顯示物件的相對 z 軸。

  2. 使用 removeChild() 方法,從顯示清單移除這些物件。

  3. 根據這些顯示物件的 z 軸值加以排列。

  4. 使用 addChild() 方法,依照相反的順序,將這些子系重新加入至顯示清單中。

上述重新排列順序的步驟,可以確保這些物件都能依照其相對 z 軸順序顯示。

下列程式碼會強制修正某一 3D 方塊的六個顯示表面。在對方塊套用旋轉之後,程式碼會重新排列方塊的表面:

public var faces:Array; . . . 
 
public function ReorderChildren() 
{     
    for(var ind:uint = 0; ind < 6; ind++) 
    { 
        faces[ind].z = faces[ind].child.transform.getRelativeMatrix3D(root).position.z; 
        this.removeChild(faces[ind].child); 
    } 
    faces.sortOn("z", Array.NUMERIC | Array.DESCENDING); 
    for (ind = 0; ind < 6; ind++) 
    { 
        this.addChild(faces[ind].child); 
    } 
}

若要取得此樣本的應用程式檔案,請參閱 www.adobe.com/go/learn_programmingAS3samples_flash_tw 。您可以在 Samples/ReorderByZ 資料夾中找到這些應用程式檔案。