テクスチャ
図1 テクスチャ

先週予告したとおり,今週はポリゴンの見映えをよくしていきます。

見映えをよくするための道具はテクスチャです。

テクスチャは,いうなればシールやデカールのようなものです。絵や写真をポリゴンにペタッと貼りつけることによって,見映えをよくします。

例えば,デコボコ道を3Dで表現するとき,デコボコをポリゴンで表すとしたら膨大な数のポリゴンが必要になります。しかし,ポリゴンをそれほど使用しなくても,そこにデコボコの絵を貼ることで,あたかもデコボコのように見えてしまうから不思議です。

図1は適当に作ったデコボコと,これまたいいかげんに描いた草のパターンであぜ道を作ってみたものです。どう見えますか? それなりに見えますか?

このテクスチャは2Dのイメージですが,1Dや3Dのテクスチャもあります。本解説では最も使用頻度の高い2Dのテクスチャを取り上げます。

注 デカールはプラモデルなどで使われるシールの一種です。

テクスチャを貼る

C言語などでテクスチャを使用する場合,テクスチャに使用するイメージを配列に格納する必要があります。また,イメージのサイズも2のn乗である必要があります。例えば,64×128とか512×512とかのサイズにします。このとき,縦と横が同じでなくてもかまいません。

JavaでもCのように配列を使用してテクスチャを扱えます。しかし,もっと便利な方法があります。

com.sun.opengl.util.textureパッケージにはテクスチャを表すためのTextureクラスや,外部のイメージファイルからテクスチャを作成するTextureIOクラスなどが定義されています。

画像ファイルの読み込みには内部的にImage I/Oが使われるので,Java SE単体でもJPEG,PNG,GIFなどを読み込むことができます。また,イメージのサイズが2のn乗でなくてもテクスチャとして扱うことができます。

さっそくやってみましょう。

サンプルとして先週作成したSimplePolygonクラスを使用します。

サンプルはここからダウンロードできます: TexturePolygon.java

まずはテクスチャを準備するところから。以下のコードはinitメソッドに記述してあります。

    try {
      File imageFile = new File("texture.png");
      Texture texture = TextureIO.newTexture(imageFile, true);
      texture.enable();
      texture.bind();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
テクスチャ座標
図2 テクスチャ座標

Textureオブジェクトの生成にはTextureIO#newTextureメソッドを使用します。newTextureメソッドは引数の違いによりオーバロードされていますが,ここではFileオブジェクトを引数とするものを使用しました。

第2引数は解像度の違うテクスチャを作成するかどうかを指定するものです。これをミップマップと呼びますが,はじめのうちは常にtrueにしてしまってもかまいません。

Textureオブジェクトが生成できたら,テクスチャを使用可能にするために,Texture#enableメソッドとTexture#bindメソッドをコールしておきます。

これで準備は整いました。さっそくポリゴンに貼りたいのですが... さて,どのように貼りましょう。

テクスチャを貼る方法には平行投影,球投影などいくつかの方法があります。これらの手法の中から,今回は使用される頻度の高いUVマッピングを使用します。

UVマッピングはポリゴンの頂点座標と,それに対応するテクスチャの座標を指定していく方法です。

テクスチャは解像度によらず,図2に示すように(0, 0),(1, 0),(1, 1),(0, 1)の領域にあてはめられます。そして,ポリゴンの頂点との対応関係を指定します(図3)。

対応関係を指定するには,GL#glVertex3fメソッドなどの頂点を指定するメソッドの前に,GLクラスのglTexCoord2f,glTexCoord2fvなどのメソッドでテクスチャの座標を指定します。

テクスチャ・マッピング
図3 テクスチャ・マッピング

SimplePolygonクラスは正方形のポリゴンだったので,テクスチャをすべて使うようにしてみましょう。

    gl.glBegin(GL.GL_POLYGON);
 
    // ポリゴンの各頂点を指定する前に
    // テクスチャの座標を指定する
    gl.glTexCoord2f(0.0f, 0.0f);
    gl.glVertex3f(-1.0f, -1.0f,  0.0f);
 
    gl.glTexCoord2f(1.0f, 0.0f);
    gl.glVertex3f(1.0f, -1.0f,  0.0f);
 
    gl.glTexCoord2f(1.0f, 1.0f);
    gl.glVertex3f(1.0f,  1.0f,  0.0f);
 
    gl.glTexCoord2f(0.0f, 1.0f);
    gl.glVertex3f(-1.0f,  1.0f,  0.0f);
 
    gl.glEnd();
実行結果
図4 実行結果
GiftBox用のテクスチャ
図5 GiftBox用のテクスチャ
GiftBoxの実行結果
図6 GiftBoxの実行結果

ポリゴンの(-1, -1, 0)にはテクスチャの(0, 0)を対応させ,(1, -1, 0)には(1, 0)を対応させます。以下,同じようにすべての頂点に対して,テクスチャの座標を対応させます。

これを実行してみましょう。図4はわかりやすいようにポリゴンを回転させてあります。

どうですか。なんとなくデコボコがあるように見えませんか?

もう少し複雑なサンプルを示しましょう。

直方体にテクスチャを貼りつけるサンプルです。

サンプルはここからダウンロードできます: GiftBox.java

1枚のテクスチャを複数のポリゴンで使用することもできます。GiftBoxクラスは,図5に示すテクスチャを使用して,直方体をプレゼント用にラッピングするものです。

上面にリボンの結び目,底面にリボンが交差する部分。その他の面はリボンが真ん中にある部分を使用します。

例えば,上面と下面は次のような対応関係になっています。

モデル座標 テクスチャ
座標
上面 (1.0, 0.5, 1)
(1.0, 0.5, -1)
(-1, 0.5, -1)
(-1, 0.5, 1)
(0, 0)
(1/3, 0)
(1/3, 1)
(0, 1)
下面 (1, -0.5, 1)
(-1, -0.5, 1)
(-1, -0.5, -1)
(1, -0.5, -1)
(1/3, 0)
(2/3, 0)
(2/3, 1)
(1/3, 1)

その他の4面はすべて,テクスチャの同じ部分を共有します。これでも,全く問題なく動作します。図6にGiftBoxの実行結果を示しました。

今週はテクスチャを使用して,見た目をより“らしく”見せる工夫をしてみました。

ここでのテクスチャの使い方は最も基本的なものです。いろいろなパラメータや,テクスチャを貼るアルゴリズムなどがあります。

もっとも,テクスチャ・マッピングは単にテクスチャを貼っただけなので,ディテールはイマイチかもしません。例えば,図6のリボンの結び目はどう見てもペッタンコですね。

より“らしく”見せるためにはバンプ・マッピングやディスプレイスメント・マッピングなどの技法を使用します。

さて,来週からは3Dを2Dのアプリケーションの中で使うことについて考えていきます。

著者紹介 櫻庭祐一

横河電機の研究部門に勤務。同氏のJavaプログラマ向け情報ページ「Java in the Box」はあまりに有名