前回の第46回は、矩形を三角形に分けてビットマップで塗るいわゆる「テクスチャマッピング」について解説した。今回は、いよいよ3次元空間座標を2次元平面に透視投影して、ビットマップの面を貼ってみたい。3次元空間座標の透視投影は、第43回「Vector3Dオブジェクトの座標に遠近法を適用する」で学んだ。このときは、3次元空間で回転する正方形をワイヤーフレームで描いた(第43回図7再掲)。今回は、この正方形にテクスチャマッピングしてみよう。
3次元空間で水平回転する正方形の頂点座標にテクスチャマッピングする
第43回スクリプト1が「3次元空間の頂点座標から2次元平面に透視投影したワイヤーフレームを描く」フレームアクションだ。今回はこのフレームアクションに手を加える。スクリプトの解説やファイルのダウンロードは、第43回2ページをご覧いただきたい。
[ライブラリ]に納めた塗りのビットマップには、クラス「Image」を設定しておく(第45回図1再掲)。[ライブラリ]のビットマップへの[クラス]の設定方法ついて詳しくは、第34回「3次元空間における回転」の「ビットマップのインスタンスを動的に配置する」を参照してほしい。
それでは、第43回スクリプト1をテクスチャマッピングできるように書き替えよう。できあがるフレームアクションは、スクリプト1として後にまとめて掲げた。手を加えるスクリプトは抜き書きして順に示す。まずは、初期設定から考えよう。
加えた内容は大きくふたつある(図1)。第1は、テクスチャとして用いるビッマップのインスタンス(myTexture)をつくることだ。第2に、Graphics.drawTriangles()メソッドに渡すVectorオブジェクトをつくった。第2引数となる分割した3角形の頂点番号の組と、第3引数のuv座標だ。そして、それらのVectorオブジェクトに初期値のエレメントを与えている。なお、第1引数の頂点座標はアニメーションさせるため、後で書直す関数(xGetVertices2D())で計算する。
つぎは、イベントリスナーの設定だ。ここでもふたつ書き替える。第1は、透視投影した頂点座標のデータ型だ。第43回スクリプト1ではVectorオブジェクトのベース型をPointで定めた。しかし、Graphics.drawTriangles()メソッドに渡すには、ベース型をNumberにしなければならない。第2に、描画はワイヤーフレームでなくテクスチャマッピングにするので、関数(xDraw())を新たに定める。
そして、上記の変更にもとづく関数の修正だ。3次元空間の座標を2次元平面に透視投影する関数(xGetVertices2D())は、つぎのように戻り値であるVectorオブジェクトのベース型をPointからNumberに変える。その他の実質的な中身はそのままだ。
最後に、テクスチャマッピングの関数(xDraw())を新たに定める。引数は、2次元平面に透視投影した座標のVectorオブジェクトだ。ワイヤーフレームを描く関数(xDrawLines)はもはや要らない。新たな関数の基本的な処理は、前回のスクリプト3のリスナー関数(xDraw())と変わらない。とくに補足は不要だろう。
でき上がったフレームアクションの全体は、つぎのスクリプト1のとおりだ。さほど大きな手を加えずにできたように見える。
テクスチャがゆがむ謎
前掲スクリプト1のキャプションに「(暫定)」とあるのが気になる。取りあえず、[ムービープレビュー]を確かめよう。マウスポインタの水平位置に応じた向きと速さで、正方形が水平に回り、ビットマップはそのかたちに合わせて塗られる。しかしよく見ると、回るときにテクスチャの真ん中当たりが上下に歪み、ペンギンが2頭身になったり4頭身になったりする(図2上段)。
前掲スクリプト1の関数xDraw()内に、コメントアウトが1行ある。この確認用のGraphics.lineStyle()メソッドを有効にすると、分けた三角形の外枠が描かれ、どのように画像がゆがむのか少し見やすくなる(図2下段)。
とくに画像中程の水平線に注目すると、三角形に分けた対角線のところが、上下にゆがんでいるとわかる。ふたつの三角形の変形に食い違いがあるようだ。ゆがみをさらにはっきりと見るため、使うビットマップを格子状の線が引かれた正方形に変えてみる。
正方形を回してゆがみを確かめると、線のつながりは保たれているものの、正方形のます目が平行四辺形になっている(図3上段)。これはつまり、テクスチャに遠近法が適用されていないことを示す。いわゆるパースペクティブがかかれば、ます目は奥に向かって狭まった台形にならなければいけないはずだ(図3下段)。
前掲スクリプト1は、正方形の頂点座標には遠近法を適用して透視投影した。しかし、テクスチャは単に三角形の頂点に合わせて変形しただけで、遠近法つまり奥行きを考えていない。Graphics.drawTriangles()メソッドの第3引数には、uv座標に奥行きのt軸を加えたuvt座標が渡せる。そうすれば、テクスチャにも遠近法が適用される。次回はこのuvt座標について解説する。
今回解説した次のサンプルファイルがダウンロードできます。