アクセシビリティ
デベロッパーリソース
Fumio Nonaka

野中 文雄氏

Fumio Nonaka

http://www.fumiononaka.com/
作成日:
2009年10月1日
ユーザレベル:
中級
製品:
Adobe Flash

三角形分割によるテクスチャマッピング − Graphics.drawTriangles()メソッド Part 2

INDEX

サンプルファイル

本テーマの前回「三角形分割によるテクスチャマッピング − Graphics.drawTriangles()メソッド Part 1」は、Graphics.drawTriangles()メソッドに渡す3つの引数について、基本的な指定の仕方をご説明しました。今回のPart 2では、簡単なサンプルを作成して、Graphics.drawTriangles()メソッドによりテクスチャを動的にマッピングしてみます(図001)。

図001■テクスチャを動的にマッピング

図001■テクスチャを動的にマッピング(左図) 図001■テクスチャを動的にマッピング(右図)

正方形の画像(左図)の角をドラッグして移動すると、その位置に合わせてテクスチャが任意の四角形(右図)に変形される。


01 準備 - ドラッグする4隅のインスタンス

まず準備として、ドラッグする4隅のポイントをMovieClipシンボルで作成し、それらをタイムラインに配置します(図002)。4つのインスタンスの位置は、マッピングするテクスチャ(ビットマップ)の大きさに合わせておきます。

図002■ポイント用のMovieClipインスタンス4つをタイムラインに配置

図002■ポイント用のMovieClipインスタンス4つをタイムラインに配置(ステージ) 図002■ポイント用のMovieClipインスタンス4つをタイムラインに配置([ライブラリ])

ドラッグするポイントをMovieClipシンボルでつくり、ビットマップ画像の4隅の位置に合わせてタイムラインに配置する。

インスタンスをドラッグするための処理は、MovieClipシンボルにフレームアクションとして記述しておきます(スクリプト001)。マウスイベントの扱いは、本稿のテーマから外れますので、説明を省きます[*1]。ここで確かめておきたいのは、インスタンスをドラッグしている間、DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数xUpdate()が呼出され、その関数本体からはメインタイムラインのxTransform()という関数が実行されるということです[*2]

スクリプト001■ドラッグするポイントのMovieClipシンボルに記述したフレームアクション

// 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()にテクスチャマッピングの処理を定義すればよいでしょう。

図003■ポイントをドラッグするとメインタイムラインの関数が呼出される

図003■ポイントをドラッグするとメインタイムラインの関数が呼出される(スクリプトと[出力]) 図003■ポイントをドラッグするとメインタイムラインの関数が呼出される(インスタンスのドラッグ)

ポイントのインスタンスをドラッグすると、メインタイムラインに定義したxTransform()関数が呼出される。この関数に、テクスチャマッピングの処理を加える。

[*1] マウスイベントの扱いについては、F-siteセミナー「イベントを制する者、ActionScript 3.0を制す」および「マウスイベント」をお読みください。

[*2] メインタイムラインに定義した関数にDisplayObject.rootプロパティを参照してアクセスする場合、プロパティはMovieClipクラスでキャストする必要があります(「rootプロパティでメインタイムラインの関数にアクセスできない」参照)。


02 任意の座標にテクスチャをマッピングする

ポイントのインスタンスをドラッグしている間、メインタイムラインの関数xTransform()が呼出されます。ですから、そのたびに新たなテクスチャマッピングを行えばよいということです。処理内容を簡単にするため、今回も正方形のビットマップを対角線でふたつに分けます。頂点番号は、Z状に0から3までの整数とします(図004)。

図004■テクスチャの頂点番号とuv座標

図004■テクスチャの頂点番号とuv座標

正方形のビットマップを対角線でふたつに分けて、Z状に頂点番号を振る。uv座標は図のとおり。

このとき、Graphics.drawTriangles()メソッドの第2引数に渡す頂点番号の組と第3引数のuvtデータの座標は、毎回とくに変わることはありません。したがって、各頂点のxy座標だけを、xTransform()関数で指定し直せばよいでしょう。以下のフレームアクション(スクリプト002)の前半は、Part 1でご紹介したスクリプト004と基本的に変わりません。後半に定義した関数xTransform()で、各ポイントのインスタンスからxy座標を調べ、Graphics.drawTriangles()メソッドの第1引数として指定しています。

スクリプト002■ドラッグしたポイントの座標に合わせてテクスチャをマッピングする

// タイムライン: メイン
// 第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)

図005■Grphics.clear()メソッドを呼出さないと以前の描画が消えない

図005■Grphics.clear()メソッドを呼出さないと以前の描画が消えない

Grphics.clear()メソッドで毎回描画を消さないと、以前のテクスチャが残ったまま重ね塗りされる。

[ムービープレビュー]で4隅のポイントをドラッグすると、その位置座標に合わせて、動的にテクスチャがマッピングされます(図006)。

図006■ドラッグした4隅のポイントに合わせてテクスチャマッピング

図006■ドラッグした4隅のポイントに合わせてテクスチャマッピング

4隅のポイントをドラッグすると、その位置座標に合わせてテクスチャが動的にマッピングされる。


03 三角形の重ね順を制御する

ここで、マッピングされるふたつの三角形の重ね順を確かめてみましょう。三角形のマッピングは、Graphics.drawTriangles()メソッドの第2引数(indices)に頂点番号を指定した三角形の順に行われます。ですから、左上半分の三角形が先に描かれ、その手前に右下半分が描画されるということです(図007)。

図007■左上より右下の三角形が手前に描画される

図007■左上より右下の三角形が手前に描画される

左上の三角形は、右下のポリゴンの手前には描画されない。

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

図008■xTransform()関数の呼出しに自身の参照を引数として渡す

図008■xTransform()関数の呼出しに自身の参照を引数として渡す

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)。

スクリプト003■左上と右下のポイントでドラッグした方の三角形を手前にする

// タイムライン: メイン
// 第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);
}

図009■左上のポイントをドラッグすると左上半分の三角形が手前に描画される

図009■左上のポイントをドラッグすると左上半分の三角形が手前に描画される

ドラッグしたポイントのインスタンス名により、Graphics.drawTriangles()メソッドに指定する第2引数の頂点番号を切替えている。

[*3] テクスチャは対角線でふたつに分けられているだけですので、左上半分と右下半分の三角形のどちらを前面にするかが問題です。つまり、重ね順が問われるのは左上と右下のポイントです。右上と左下のポイントは2分割した対角線になるため、一方を他方の手前に描画することはできません。

著者について

野中 文雄 Fumio Nonaka
ソフトウェアトレーナー、テクニカルライター、オーサリングエンジニア
上智大学法学部卒、慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。 独立系パソコン販売会社で、総務・人事、企画、外資系企業担当営業などに携わる。その後、マルチメディアコンテンツ制作会社に転職。
ソフトウェアトレーニング、コンテンツ制作などの業務を担当する。2001年11月に独立。
Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。
近著は『ActionScript 3.0プロフェッショナルガイド』(株式会社毎日コミュニケーションズ)。