本テーマの前回「三角形分割によるテクスチャマッピング − Graphics.drawTriangles()メソッド Part 1」は、Graphics.drawTriangles()メソッドに渡す3つの引数について、基本的な指定の仕方をご説明しました。今回のPart 2では、簡単なサンプルを作成して、Graphics.drawTriangles()メソッドによりテクスチャを動的にマッピングしてみます(図001)。
![]() |
→ | ![]() |
正方形の画像(左図)の角をドラッグして移動すると、その位置に合わせてテクスチャが任意の四角形(右図)に変形される。
まず準備として、ドラッグする4隅のポイントをMovieClipシンボルで作成し、それらをタイムラインに配置します(図002)。4つのインスタンスの位置は、マッピングするテクスチャ(ビットマップ)の大きさに合わせておきます。
![]() |
![]() |
ドラッグするポイントをMovieClipシンボルでつくり、ビットマップ画像の4隅の位置に合わせてタイムラインに配置する。
インスタンスをドラッグするための処理は、MovieClipシンボルにフレームアクションとして記述しておきます(スクリプト001)。マウスイベントの扱いは、本稿のテーマから外れますので、説明を省きます[*1]。ここで確かめておきたいのは、インスタンスをドラッグしている間、DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数xUpdate()が呼出され、その関数本体からはメインタイムラインのxTransform()という関数が実行されるということです[*2]。
// MovieClip: ドラッグするポイント
// 第1フレームアクション
buttonMode = true;
addEventListener(MouseEvent.MOUSE_DOWN, xPress);
function xPress(eventObject:MouseEvent):void {
startDrag();
addEventListener(MouseEvent.MOUSE_UP, xRelease);
stage.addEventListener(MouseEvent.MOUSE_UP, xRelease);
addEventListener(Event.ENTER_FRAME, xUpdate);
}
function xRelease(eventObject:MouseEvent):void {
stopDrag();
removeEventListener(MouseEvent.MOUSE_UP, xRelease);
stage.removeEventListener(MouseEvent.MOUSE_UP, xRelease);
removeEventListener(Event.ENTER_FRAME, xUpdate);
}
function xUpdate(eventObject:Event):void { // ドラッグ中に呼出されるリスナー関数
MovieClip(root).xTransform(); // メインタイムラインの関数xTransform()を呼出す
}
そこで、メインタイムラインに関数xTransform()を定義し、つぎのように確認用のtrace()関数を加えたうえで、[ムービープレビュー]してみます。
function xTransform():void {
trace("called!");
}
ポイントのインスタンスをドラッグすると、メインタイムラインに定義したxTransform()関数が呼出されて、[出力]パネルに確認用の文字列が表示されます(図003)。これで準備はできました。あとは、メインタイムラインのフレームアクションで、関数xTransform()にテクスチャマッピングの処理を定義すればよいでしょう。
![]() |
![]() |
ポイントのインスタンスをドラッグすると、メインタイムラインに定義したxTransform()関数が呼出される。この関数に、テクスチャマッピングの処理を加える。
[*1] マウスイベントの扱いについては、F-siteセミナー「イベントを制する者、ActionScript 3.0を制す」および「マウスイベント」をお読みください。
[*2] メインタイムラインに定義した関数にDisplayObject.rootプロパティを参照してアクセスする場合、プロパティはMovieClipクラスでキャストする必要があります(「rootプロパティでメインタイムラインの関数にアクセスできない」参照)。
ポイントのインスタンスをドラッグしている間、メインタイムラインの関数xTransform()が呼出されます。ですから、そのたびに新たなテクスチャマッピングを行えばよいということです。処理内容を簡単にするため、今回も正方形のビットマップを対角線でふたつに分けます。頂点番号は、Z状に0から3までの整数とします(図004)。

正方形のビットマップを対角線でふたつに分けて、Z状に頂点番号を振る。uv座標は図のとおり。
このとき、Graphics.drawTriangles()メソッドの第2引数に渡す頂点番号の組と第3引数のuvtデータの座標は、毎回とくに変わることはありません。したがって、各頂点のxy座標だけを、xTransform()関数で指定し直せばよいでしょう。以下のフレームアクション(スクリプト002)の前半は、Part 1でご紹介したスクリプト004と基本的に変わりません。後半に定義した関数xTransform()で、各ポイントのインスタンスからxy座標を調べ、Graphics.drawTriangles()メソッドの第1引数として指定しています。
// タイムライン: メイン
// 第1フレームアクション
var mySprite:Sprite = new Sprite();
var myGraphics:Graphics = mySprite.graphics;
var myTexture:BitmapData = new Pen(0,0);
var indices:Vector.<int> = new Vector.<int>();
var uvtData:Vector.<Number> = new Vector.<Number>();
addChildAt(mySprite, 0);
// 三角形の頂点番号の組合わせ(第2引数)
indices.push(0,1,2);
indices.push(1,3,2);
// テクスチャマッピングのuv座標(第3引数)
uvtData.push(0,0);
uvtData.push(1,0);
uvtData.push(0,1);
uvtData.push(1,1);
xTransform(); // ドラッグ前にテクスチャを初期位置にマッピング
function xTransform():void {
// 三角形の頂点座標(第1引数)
var vertices:Vector.<Number> = new Vector.<Number>();
vertices.push(point0_mc.x, point0_mc.y);
vertices.push(point1_mc.x, point1_mc.y);
vertices.push(point2_mc.x, point2_mc.y);
vertices.push(point3_mc.x, point3_mc.y);
myGraphics.clear(); // 描画を一旦消す
myGraphics.beginBitmapFill(myTexture);
myGraphics.drawTriangles(vertices, indices, uvtData);
}
関数xTransform()の本体で頂点座標(vertices)を取得し、Graphics.drawTriangles()メソッドの第1引数に指定していることがおわかりになれば、あとはPart 1の解説で処理内容は理解できるでしょう。ふたつだけ補足しておきます。
ひとつは、xTransform()関数定義の直前に、フレームアクションから関数を呼出していることです。このステートメントがないと、ポイントのインスタンスをドラッグするまでxTransform()関数が呼出されず、初期位置にテクスチャがマッピングされないからです。
もうひとつは、Grphics.clear()メソッドの呼出しです。これを行わないと、以前の描画は残ったままテクスチャが重ね塗りされてしまいます。ですから、新たにマッピングする前に、毎回このメソッドで描画を消去しておく必要があるのです。(図005)

Grphics.clear()メソッドで毎回描画を消さないと、以前のテクスチャが残ったまま重ね塗りされる。
[ムービープレビュー]で4隅のポイントをドラッグすると、その位置座標に合わせて、動的にテクスチャがマッピングされます(図006)。

4隅のポイントをドラッグすると、その位置座標に合わせてテクスチャが動的にマッピングされる。
ここで、マッピングされるふたつの三角形の重ね順を確かめてみましょう。三角形のマッピングは、Graphics.drawTriangles()メソッドの第2引数(indices)に頂点番号を指定した三角形の順に行われます。ですから、左上半分の三角形が先に描かれ、その手前に右下半分が描画されるということです(図007)。

左上の三角形は、右下のポリゴンの手前には描画されない。
左上と右下のポイントとで、ドラッグした方の三角形を前面に描画するようスクリプトを修正してみましょう。まず、ドラッグされているインスタンスがわからなければなりません。そのため、ドラッグするMovieClipシンボルのフレームアクションを書替え、xTransform()関数の引数に自分自身の参照(this)を渡して呼出すことにします。(図008)

MovieClipシンボルのフレームアクションを書替えて、xTransform()関数の呼出しに自身の参照(this)を引数として渡す。
関数xTransform()を定義するメインタイムラインのフレームアクションでは、4つのポイントごとに頂点番号のVectorインスタンスを用意しておき、各ポイントのインスタンス名からそのうちのひとつを取出す仕組みにしましょう。そのために新たにindicesをObject型の変数として宣言し、各インスタンス名のプロパティにそれぞれのVectorインスタンスを設定します。フレームアクションには、つぎのような関数xGetIndices()の定義を加えます[*3]。
var indices:Object = xGetIndices();
function xGetIndices() {
var oIndices:Object = new Object();
// point1_mc〜point3_mcまでの頂点番号をプロパティとして設定
var myIndices:Vector.<int> = new Vector.<int>();
myIndices.push(0,1,2); // 左上の三角形
myIndices.push(1,3,2); // 右下の三角形
oIndices.point1_mc = oIndices.point2_mc = oIndices.point3_mc = myIndices;
// point0_mcの頂点番号をプロパティとして設定
myIndices = new Vector.<int>();
myIndices.push(1,3,2); // 右下の三角形
myIndices.push(0,1,2); // 左上の三角形
oIndices.point0_mc = myIndices;
return oIndices;
}
関数xGetIndices()の返すObjectインスタンスには、4つのポイントのインスタンス名をプロパティ名とする頂点番号のVectorインスタンスが納められています。したがって、ポイントのインスタンスが変数my_mcに入っているなら、そのポイントに対応した頂点番号のVectorインスタンスをつぎのようにして取出すことができます。
indices[my_mc.name]
以上の修正を加えたメインタイムラインのフレームアクションは、以下のスクリプト003のとおりです。ポイントのインスタンスから呼出されるxTransform()関数にインスタンスの参照が渡されますので、そのインスタンス名によりGraphics.drawTriangles()メソッドに指定する第2引数のVectorインスタンスを取出しています。これで、左上のポイントのインスタンスをドラッグすれば、左上半分の三角形が手前に描画されるようになりました(図009)。
// タイムライン: メイン
// 第1フレームアクション
var mySprite:Sprite = new Sprite();
var myGraphics:Graphics = mySprite.graphics;
var myTexture:BitmapData = new Pen(0,0);
var indices:Object = xGetIndices();
var uvtData:Vector.<Number> = new Vector.<Number>();
addChildAt(mySprite, 0);
uvtData.push(0,0);
uvtData.push(1,0);
uvtData.push(0,1);
uvtData.push(1,1);
xTransform(point0_mc);
function xGetIndices() {
var oIndices:Object = new Object();
var myIndices:Vector.<int> = new Vector.<int>();
myIndices.push(0,1,2);
myIndices.push(1,3,2);
oIndices.point1_mc = oIndices.point2_mc = oIndices.point3_mc = myIndices;
myIndices = new Vector.<int>();
myIndices.push(1,3,2);
myIndices.push(0,1,2);
oIndices.point0_mc = myIndices;
return oIndices;
}
function xTransform(my_mc:MovieClip):void {
var vertices:Vector.<Number> = new Vector.<Number>();
vertices.push(point0_mc.x, point0_mc.y);
vertices.push(point1_mc.x, point1_mc.y);
vertices.push(point2_mc.x, point2_mc.y);
vertices.push(point3_mc.x, point3_mc.y);
myGraphics.clear();
myGraphics.beginBitmapFill(myTexture);
myGraphics.drawTriangles(vertices, indices[my_mc.name], uvtData);
}

ドラッグしたポイントのインスタンス名により、Graphics.drawTriangles()メソッドに指定する第2引数の頂点番号を切替えている。
[*3] テクスチャは対角線でふたつに分けられているだけですので、左上半分と右下半分の三角形のどちらを前面にするかが問題です。つまり、重ね順が問われるのは左上と右下のポイントです。右上と左下のポイントは2分割した対角線になるため、一方を他方の手前に描画することはできません。