3D 効果のための三角形の使用

Flash Player 10 以降、Adobe AIR 1.5 以降

ActionScript では、3D モデルは空間内の三角形のコレクションによって表現されるので、Graphics.drawTriangles() メソッドを使用してビットマップ変換を実行します(ただし、Flash Player と AIR では深度バッファーがサポートされないので、表示オブジェクトは依然として平面、つまり 2D の性質を持ちます。これについては、Flash Player および AIR ランタイムでの 3D 表示オブジェクトについてで説明しています)。Graphics.drawTriangles() メソッドは、座標のセットを受け取って三角形のパスを描画するので、Graphics.drawPath() メソッドに似ています。

Graphics.drawPath() の使用方法については、パスの描画を参照してください。

Graphics.drawTriangles() メソッドでは、Vector.<Number> を使用して、三角形パスのポイント位置を指定します。

drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

drawTriangles() の最初のパラメーターは、唯一の必須パラメーターである vertices パラメーターです。このパラメーターは、三角形の描画に使用される座標を定義する数値のベクターです。3 セットの座標(6 つの数値)すべてが三角形パスを表します。各三角形には 3 つの座標のペア(2 つの x/y 値の 3 つのセット)が必要なので、indices パラメーターがないと、ベクターの長さは常に 6 の因数になります。次に、例を示します。

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([ 
        10,10,  100,10,  10,100, 
        110,10, 110,100, 20,100]));

これらの三角形のいずれもポイントを共有していませんが、共有していた場合は、2 つ目の drawTriangles() パラメーターである indices を使用して、複数の三角形の vertices ベクターの値を再利用することができます。

indices パラメーターを使用している場合は、indices 値が、vertices 配列エレメントに直接関係するインデックスではなく、ポイントインデックスであることに注意してください。つまり、vertices ベクター内のインデックス(indices で定義されたもの)は、実際には 2 で除算された現実のインデックスです。例えば、vertices ベクターの 3 つ目のポイントについては、そのポイントの最初の数値が 4 つのベクターインデックスから開始する場合でも、2 の indices 値を使用します。

例えば、indices パラメーターを使用し、2 つの三角形をマージして、対角線のエッジを共有します。

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([10,10, 100,10, 10,100, 100,100]), 
    Vector.<int>([0,1,2, 1,3,2]));

正方形は 2 つの三角形を使用して描画されますが、vertices ベクターでは 4 つのポイントのみ指定されていることに注意してください。indices を使用すると、2 つの三角形で共有されている 2 つのポイントが各三角形に再利用されます。これにより、全体の頂点数が 6(12 個の数値)から 4(8 個の数値)に減ります。

頂点パラメーターを使用して 2 つの三角形で描画された正方形

この技法は、ほとんどのポイントが複数の三角形によって共有される大きな三角形メッシュで役立ちます。

すべての塗りが三角形に適用されます。塗りは、他のシェイプに対する場合と同様に、生成される三角形メッシュに適用されます。

ビットマップの変換

ビットマップ変換は、3 次元オブジェクトの遠近法または「テクスチャ」の効果を提供します。具体的には、イメージが消失点の方向に移動するにつれて縮小するように、消失点に向かってビットマップを歪めることができます。または、2 次元ビットマップを使用して、3 次元オブジェクトのサーフェスを作成し、その 3 次元オブジェクトに対してテクスチャまたは「ラップ」の効果を提供することができます。

消失点を使用した 2 次元サーフェスと、ビットマップにラップされた 3 次元オブジェクト。

UV マッピング

テクスチャの操作を開始した後、drawTriangles() の uvtData パラメーターを使用することができます。このパラメーターにより、ビットマップを塗るために UV マッピングを設定することができます。

UV マッピングは、オブジェクトのテクスチャを作成するためのメソッドです。U 水平(x)値および V 垂直(y)値という 2 つの値に依存します。ピクセル値に基づくのではなく、パーセンテージに基づきます。0 U および 0 V はイメージの左上であり、1 U および 1 V は右下です。

ビットマップイメージ上の UV 0 および 1 の位置

三角形のベクターには、イメージ上のそれぞれの場所に関連付けるために UV 座標を与えることができます。

ビットマップイメージの三角形領域の UV 座標

UV 値は、三角形のポイントとの整合性を保ちます。

三角形の頂点が移動し、ビットマップが歪められて、個別のポイントの UV 値が同じに保たれます。

ActionScript 3D 変換が、ビットマップに関連付けられている三角形に適用されると、ビットマップイメージが UV 値に基づいて三角形に適用されます。そのため、マトリックス計算を使用する代わりに、UV 値を設定または調整して 3 次元効果を作成します。

Graphics.drawTriangles() メソッドは、3 次元変換のオプションの情報部分である T 値を受け入れることもあります。uvtData の T 値は 3D 遠近法を表します。より具体的には、関連付けられた頂点の縮尺率を表します。UVT マッピングでは、UV マッピングに遠近法補正が追加されます。例えば、オブジェクトが「原点」の 50 % のサイズで表示されるように視点から離れた 3D 空間に配置される場合、そのオブジェクトの T 値は 0.5 になります。三角形が 3D 空間のオブジェクトを表すように描画される場合、z 軸に沿ったその位置によって T 値が決定されます。T 値を決定する等式は次のとおりです。

T = focalLength/(focalLength + z);
この等式では、focalLength は、ビューに提供される遠近法の量を示す焦点の長さまたは計算された「スクリーン」位置を表します。
焦点の長さと z 値
A.
視点

B.
スクリーン

C.
3D オブジェクト

D.
focalLength 値

E.
z 値

T の値を使用して、基本的なシェイプを拡大/縮小し、遠くにあるように見せます。通常これは、3D ポイントを 2D ポイントに変換するために使用する値です。UVT データの場合は、遠近法で三角形の内部の頂点の間のビットマップを拡大/縮小するためにも使用されます。

UVT 値を定義する場合、T 値は頂点に対して定義されている UV 値に直接従います。T を含める場合、uvtData パラメーターの 3 つの値(U、V および T)がすべて、vertices パラメーターの 2 つの値(x および y)に一致します。UV 値単体では、uvtData.length == vertices.length となります。T 値を含めると、uvtData.length = 1.5*vertices.length となります。

次の例では、UVT データを使用して 3D 空間で回転された平面を表示します。この例では、ocean.jpg というイメージおよび「ヘルパー」クラス ImageLoader を使用して ocean.jpg イメージがロードされるので、BitmapData オブジェクトに割り当てることができます。

次に、ImageLoader クラスソースを示します(このコードは ImageLoader.as という名前のファイルに保存します)。

package { 
    import flash.display.* 
    import flash.events.*; 
    import flash.net.URLRequest; 
    public class ImageLoader extends Sprite { 
        public var url:String; 
        public var bitmap:Bitmap; 
    public function ImageLoader(loc:String = null) { 
        if (loc != null){ 
            url = loc; 
            loadImage(); 
        } 
    } 
    public function loadImage():void{ 
        if (url != null){ 
            var loader:Loader = new Loader(); 
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete); 
            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoError); 
             
                var req:URLRequest = new URLRequest(url); 
                loader.load(req); 
            } 
        } 
         
    private function onComplete(event:Event):void { 
            var loader:Loader = Loader(event.target.loader); 
            var info:LoaderInfo = LoaderInfo(loader.contentLoaderInfo); 
            this.bitmap = info.content as Bitmap; 
            this.dispatchEvent(new Event(Event.COMPLETE)); 
    } 
         
    private function onIoError(event:IOErrorEvent):void { 
            trace("onIoError: " + event); 
    } 
    } 
}

また、トライアングル、UV マッピングおよび T 値を使用して、消失点に向かって縮小し、回転するように見えるイメージを作成する ActionScript を次に示します。このコードを、Spinning3dOcean.as という名前のファイルに保存します。

package { 
    import flash.display.* 
    import flash.events.*; 
    import flash.utils.getTimer; 
     
    public class Spinning3dOcean extends Sprite { 
        // plane vertex coordinates (and t values) 
        var x1:Number = -100,    y1:Number = -100,    z1:Number = 0,    t1:Number = 0; 
        var x2:Number = 100,    y2:Number = -100,    z2:Number = 0,    t2:Number = 0; 
        var x3:Number = 100,    y3:Number = 100,    z3:Number = 0,    t3:Number = 0; 
        var x4:Number = -100,    y4:Number = 100,    z4:Number = 0,    t4:Number = 0; 
        var focalLength:Number = 200;      
        // 2 triangles for 1 plane, indices will always be the same 
        var indices:Vector.<int>; 
         
        var container:Sprite; 
         
        var bitmapData:BitmapData; // texture 
        var imageLoader:ImageLoader; 
        public function Spinning3dOcean():void { 
            indices =  new Vector.<int>(); 
            indices.push(0,1,3, 1,2,3); 
             
            container = new Sprite(); // container to draw triangles in 
            container.x = 200; 
            container.y = 200; 
            addChild(container); 
             
            imageLoader = new ImageLoader("ocean.jpg"); 
            imageLoader.addEventListener(Event.COMPLETE, onImageLoaded); 
        } 
        function onImageLoaded(event:Event):void { 
            bitmapData = imageLoader.bitmap.bitmapData; 
            // animate every frame 
            addEventListener(Event.ENTER_FRAME, rotatePlane); 
        } 
        function rotatePlane(event:Event):void { 
            // rotate vertices over time 
            var ticker = getTimer()/400; 
            z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker)); 
            x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker)); 
             
            // calculate t values 
            t1 = focalLength/(focalLength + z1); 
            t2 = focalLength/(focalLength + z2); 
            t3 = focalLength/(focalLength + z3); 
            t4 = focalLength/(focalLength + z4); 
             
            // determine triangle vertices based on t values 
            var vertices:Vector.<Number> = new Vector.<Number>(); 
            vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4); 
            // set T values allowing perspective to change 
            // as each vertex moves around in z space 
            var uvtData:Vector.<Number> = new Vector.<Number>(); 
            uvtData.push(0,0,t1, 1,0,t2, 1,1,t3, 0,1,t4); 
             
            // draw 
            container.graphics.clear(); 
            container.graphics.beginBitmapFill(bitmapData); 
            container.graphics.drawTriangles(vertices, indices, uvtData); 
        } 
    } 
}

この例をテストするには、この 2 つのクラスファイルを「ocean.jpg」という名前のイメージと同じディレクトリに保存します。元のビットマップがどのように変換されて、3D 空間内で遠くに消失し、回転するように見えるかを参照することができます。

カリング

カリングは、現在の視点から隠れているのでレンダラーでレンダリングする必要のない 3 次元オブジェクトのサーフェスを決定するプロセスです。3D 空間では、3 次元オブジェクトの「背面」にあるサーフェスは、視点から隠されます。
3D オブジェクトの背面は、視点から隠されます。
A.
視点

B.
3D オブジェクト

C.
3 次元オブジェクトの背面

本質的に、すべての三角形は、サイズ、シェイプまたは位置にかかわらず常にレンダリングされます。カリングによって、Flash Player または AIR によって確実に 3D オブジェクトが正しくレンダリングされます。また、レンダリングサイクルを短縮するために、一部の三角形がレンダリングでスキップされるようにする場合があります。空間内で回転する立方体について考えます。特定の時点で、ビューにない面は立方体の他の面の他の方向に面しているので、その立方体の 3 つの面以外は見えません。これらの面は表示されないので、レンダラーは描画しない必要があります。カリングを使用しないと、Flash Player または AIR では、前面と背面の両方がレンダリングされます。

立方体には、現在の視点からは見えない面があります。

したがって、Graphics.drawTriangles() メソッドには、カリング値を設定するための第 4 のパラメーターがあります。

public function drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

カリングパラメーターは、TriangleCulling 列挙クラスの値である TriangleCulling.NONETriangleCulling.POSITIVE および TriangleCulling.NEGATIVE です。これらの値は、オブジェクトのサーフェスを定義する三角形パスの方向に依存します。カリングを決定する ActionScript API では、3D シェイプのすべての外向き三角形が同じパス方向に描画されると想定されます。三角形の表面が裏返ると、パス方向も変更されます。そのポイントで、三角形をカリング(レンダリングから削除)することができます。

したがって、POSITIVETriangleCulling 値によって、三角形が正のパス方向(時計回り)に削除されます。NEGATIVETriangleCulling 値では、三角形が負(反時計回り)のパス方向に削除されます。立方体の場合、前面を向いているサーフェスは正のパス方向を持ち、背面を向いているサーフェスは負のパス方向を持ちます。

立方体は「ラップ解除」されて、パス方向が表示されます。「ラップ」されている場合は、背面のパス方向が逆転します。

カリングの動作を参照するには、前の UV マッピングの例から開始し、drawTriangles()メソッドのカリングパラメーターを TriangleCulling.NEGATIVE に設定します。

container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE);

イメージの「背面」は、オブジェクトが回転したときにレンダリングされないことに注意してください。