今回から、定められた領域をビットマップで塗りつぶすお題に取りかかる。目指すは、3次元空間から2次元平面に透視投影された面に、素材となるビットマップを貼りつけることだ。素材を「テクスチャ」と呼び、貼りつけは「マッピング」という。この「テクスチャマッピング」を学ぼう。
ビットマップで塗る
まず、3次元空間は今回置いておく。ビットマップで、決まった領域を塗ってみたい。使うのは、Graphicsクラスのメソッドだ。第33回「遠近法の投影」の「ステージにランダムなシェイプを配置する」で、Shapeインスタンスに塗りの円を描いた。このとき塗り色を定めたのは、Graphics.beginFill()メソッドだった。このメソッドをGraphics.beginBitmapFill()と書替えれば、塗りにビットマップが使える。必須の第1引数には、塗りに用いるBitmapDataオブジェクトを渡す[1]。
塗りのビットマップは[ライブラリ]に置いて、インスタンスは動的につくろう。そのためには、そのビットマップに[クラス]を設定しておかねばならない(詳しい手順については、第34回「3次元空間における回転」の「ビットマップのインスタンスを動的に配置する」参照)。クラス名は「Image」としておく(図1)。
タイムラインには予め何も置かなくてよい。つぎのスクリプト1をフレームアクションとして書くだけだ。
タイムラインに動的にShapeインスタンス(myShape)を置いて、そのShape.graphicsプロパティから得たGraphicsオブジェクト(myGraphics)にGraphics.drawCircle()メソッドで円を描いた(前掲第33回「遠近法の投影」参照)。そのとき、塗りはGraphics.beginBitmapFill()メソッドで、[ライブラリ]のビットマップのインスタンス(myTexture)を指定している[2]。すると、円の内側はビットマップでタイル状に塗られる(図2)。
三角形に分けて描く - Graphics.drawTriangles()メソッド
描画領域をいくつもの三角形に分けて描くのが、Graphics.drawTriangles()メソッドだ。三次元空間の曲面も、複数の細かな三角形に分ければ、平面の三角形の集まりで表現できる。某ビールメーカーの特徴的な酎ハイの缶を思い浮かべてもらうとよい(図3)。必須の第1引数はNumberベース型のVectorオブジェクトで、3角形の頂点座標をxyの順に交互に3つずつ加えていく。
Graphics.drawTriangles()メソッドにより、ふたつの三角形をビットマップで塗ってみよう。ふたつの三角形それぞれの3頂点、都合6つの座標は下図4のように定める。
描くのが仮に三角形1ひとつだけだったら、引数となるNumberベース型のVectorオブジェクトをつぎのようにつくって、Graphics.drawTriangles()メソッドに渡しても構わないかもしれない。
しかし、Graphics.drawTriangles()メソッドをテクスチャマッピングに用いると、面を数多くの三角形に分けて塗ることが少なくない。上記のように座標をただ書連ねると、三角形がいくつあるのか、どれがx座標でどれがy座標なのか訳がわからなくなる。筆者としては、VectorオブジェクトにVector.push()メソッドを用いて、頂点ひとつずつ、つまりxy座標ひと組ごとに加えることをお勧めしたい。
Graphics.drawTriangles()メソッドでふたつの三角形を描き、ビットマップで塗ったのが、つぎのスクリプト2だ。
[ムービープレビュー]を確かめると、ふたつの三角形が描かれて、その内側はビットマップでタイル状に塗られる(図5上図)。Graphics.beginBitmapFill()メソッドは、デフォルトでは対象となるShapeオブジェクトの基準点、つまりスクリプト2ではステージ左上隅からビットマップを塗り始める[3]。そのため、三角形に塗ったビットマップの左上が少し切れてしまった(図5下図)。
ビットマップを三角形の頂点に対応させる
Graphics.drawTriangles()メソッドが優れているのは、三角形ひとつひとつについてビットマップのどの部分で塗るかが細かく決められることだ。塗りのビットマップも、やはり三角形の頂点座標で領域を定める。Graphics.drawTriangles()メソッドには、その指定を第1引数と同じように、Numberベース型のVectorオブジェクトで渡す。ただし、注意すべきことがふたつある。
第1に、このVectorオブジェクトはGraphics.drawTriangles()メソッドの第3引数になる。第2引数を省く訳にはいかないので、とくに指定がないときはデフォルト値のnullを渡す。第2は、ビットマップの位置を決める座標の単位がピクセルではないことだ。ビットマップの左上は(0, 0)、右下が(1, 1)となる比率で示す。この水平軸をu、垂直軸をvで表すので、uv座標と呼ばれる(図6)。
この第3引数として渡すVectorオブジェクトの数値(Numberベース型)エレメントは、第1引数のVectorオブジェクトのxy座標値(Numberベース型)のエレメントにそれぞれ対応させる。つまり、ふたつのオブジェクトのエレメント数(Vector.lengthプロパティ値)は、等しくなければならない。第1引数のxy座標に対して、第3引数のuv座標は下表1のように決めよう。
表1 第1引数の頂点座標とそれに対応する第3引数のuv座標
第1引数/頂点座標 | 第3引数/uv座標 |
(20, 20) | (0, 0) |
(120, 20) | (1, 0) |
(20, 120) | (0, 1) |
(140, 40) | (1, 0) |
(140, 140 | (1, 1) |
(40, 140) | (0, 1) |
前掲スクリプト2のGraphics.drawTriangles()メソッド呼出しに、第3引数のuv座標(uvData)を加えたのがつぎのスクリプト3だ。メソッドに渡す第2引数のnullを忘れないでほしい。
[ムービープレビュー]を確かめると、ビットマップは第3引数に指定したとおりふたつの三角形を塗る。結果として、四角いビットマップが対角線でふたつに切られたように描かれる(図7)。
ふたつの引数となるVectorオブジェクト(Numberベース型)の座標は、好きなように決められる。たとえば、前掲スクリプト3でGraphics.drawTriangles()メソッドに渡した第1引数(vertices)の座標値を書替えれば、ビットマップが変形できる(図8)。
Graphics.drawTriangles()メソッドで面を三角形に分けて、ビットマップのuv座標をうまく定めれば、ビットマップをあたかも伸縮自在のラッピングペーパーのように使ってマッピングできる。次回は、メソッドの第2引数の説明に加えて、テクスチャマッピングの練習をしてみたい。
今回解説した次のサンプルファイルがダウンロードできます。