«第4回 アルファテスト 最新 第6回 投影マッピング»

床井研究室

現在,このサイトに和歌山大学外から連続してアクセスると,2回目以降にアクセスできなくなる現象が発生しています.その場合は申し訳ありませんが,ブラウザのキャッシュのクリアをお試しください.


■ 2004年09月17日 [OpenGL][テクスチャ] 第5回 テクスチャ座標

2005年06月18日 11:13更新

テクスチャ座標の取り方

テクスチャに使う画像はテクスチャ空間中の2点 (0, 0), (1, 1) を対角線とする正方形の領域に配置されていても,ポリゴンの頂点に対応付けるテクスチャ座標が必ずこの領域内にある必要はありません.試しに,テクスチャ座標にこの領域外の座標値を設定してみましょう.

テクスチャ座標に画像の領域外の値を指定する

アルファテストが有効になっていると,ポリゴン全体が見えないので,ここでは一旦オフにしておきます.

・・・
  
/*
** シーンの描画
*/
static void scene(void)
{
  static const GLfloat color[] = { 1.0, 1.0, 1.0, 1.0 };  /* 材質 (色) */
  
  /* 材質の設定 */
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
  
  /* アルファテスト無効 */
  glDisable(GL_ALPHA_TEST);
  
  /* テクスチャマッピング開始 */
  glEnable(GL_TEXTURE_2D);
  
  /* 1枚の4角形を描く */
  glNormal3d(0.0, 0.0, 1.0);
  glBegin(GL_QUADS);
  glTexCoord2d(0.0, 2.0);
  glVertex3d(-1.0, -1.0,  0.0);
  glTexCoord2d(2.0, 2.0);
  glVertex3d( 1.0, -1.0,  0.0);
  glTexCoord2d(2.0, 0.0);
  glVertex3d( 1.0,  1.0,  0.0);
  glTexCoord2d(0.0, 0.0);
  glVertex3d(-1.0,  1.0,  0.0);
  glEnd();
  
・・・

すると,画像の領域外には,同じ画像が繰り返しマッピングされます.

画像の領域外のテクスチャ

この繰り返しを行わないようにするには,glTexParameteri() を使って GL_TEXTURE_WRAP_S と GL_TEXTURE_WRAP_T に GL_CLAMP を指定します.

・・・
  
/*
** 初期化
*/
static void init(void)
{
  ・・・
  
  /* テクスチャの割り当て */
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXWIDTH, TEXHEIGHT, 0,
    GL_RGBA, GL_UNSIGNED_BYTE, texture);
  
  /* テクスチャを拡大・縮小する方法の指定 */
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  
  /* テクスチャの繰り返しの指定 */
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  
・・・

GL_TEXTURE_WRAP_S はテクスチャ空間 (s, t) の s 軸方向の繰り返し,GL_TEXTURE_WRAP_S は t 軸方向の繰り返しを指定します.GL_CLAMP を指定すると,テクスチャは繰り返されずに,画像の最外周の色が拡張されます.GL_REPEAT を指定すると,テクスチャは繰り返しマッピングされます.初期値は GL_REPEAT になっています.

テクスチャを繰り返さずにマッピング

テクスチャ変換行列

実は,OpenGL ではテクスチャ空間も,物体の空間 (x, y, z, w) と同じように4次元 (s, t, r, q) になっています.そして,ここでは物体の空間と同じ座標変換を行うことができます.テクスチャ空間の座標変換を行う変換行列を,テクスチャ変換行列(テクスチャマトリックス)と呼びます.

それでは,タイヤのテクスチャがポリゴンの中央に来るように,テクスチャ変換行列を設定してみましょう.透視変換やモデルビュー変換と同様に glMatrixMode() を使って変換行列を切り替えるので,後でプログラムを見たときにそのことを把握しやすいよう,これまでと違うところに手を加えます.

・・・
  
/****************************
** GLUT のコールバック関数 **
****************************/
  
/* トラックボール処理用関数の宣言 */
#include "trackball.h"
  
static void display(void)
{
  /* テクスチャ変換行列の設定 */
  glMatrixMode(GL_TEXTURE);
  glLoadIdentity();
  glTranslated(-0.5, -0.5, 0.0);
  
  /* モデルビュー変換行列の設定 */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
・・・

glMatrixMode(GL_TEXTURE) で設定する変換行列をテクスチャ変換行列に切り替えます.glLoadIdentity() で初期化するのは,モデルビュー変換行列や透視変換行列と同じです.そのあと,glTranslated() を使って,テクスチャ空間上で平行移動を行っています.

テクスチャの平行移動

んで,ちょいとややこしいのは,この変換においてテクスチャ空間がスクリーン空間に相当しているところにあります.つまり,ポリゴンの頂点に割り当てられたテクスチャ座標に対してテクスチャ変換を行って,テクスチャ空間上の座標値を得ます.そして,この座標値のところの画像の色を拾って,テクスチャマッピングを行っています.

これは,テクスチャ画像はテクスチャ空間中で静止しており,ポリゴンの頂点に対応付けたテクスチャ座標値がこの変換によって変更される,と考えれば理解しやすいのではないかと思います.

テクスチャ座標の平行移動

タイヤは回るもの

平行移動ができるなら回転だってできます.ということで,このタイヤを回してみましょう.雛形のプログラム自体はもとからアニメーション対応になっています.あとは,フレーム数をカウントするなり ftime()(Windows なら _ftime())なりを使って実時間を計るなどして,フレームごとの経過時間を求めます.ここでは(マシンスピードに依存してしまいますが)フレーム数をカウントすることにします.

・・・
  
/****************************
** GLUT のコールバック関数 **
****************************/
  
/* トラックボール処理用関数の宣言 */
#include "trackball.h"
  
/* アニメーションのサイクル */
#define FRAMES 360
  
static void display(void)
{
  /* フレーム数をカウントして時間として使う */
  static int frame = 0;                      /* フレーム数        */
  double t = (double)frame / (double)FRAMES; /* 時間とともに 0→1 に変化 */
  
  if (++frame >= FRAMES) frame = 0;
  

この t を使って,テクスチャ座標を回転します.まず,中央に原点が来るようにテクスチャ座標を (-1, -1) に平行移動します.そしてこのテクスチャ座標を原点を中心に回転します.最後にこの原点がテクスチャの中心と一致するよう (0.5, 0.5) に平行移動します.なお,このプログラムのコーディング上の順序は,頂点の座標値の変換と同様に,これと逆順になることに注意してください.

  /* テクスチャ行列の設定 */
  glMatrixMode(GL_TEXTURE);
  glLoadIdentity();
  glTranslated(0.5, 0.5, 0.0);         /* 原点をテクスチャの中心に移動   */
  glRotated(t * 360.0, 0.0, 0.0, 1.0); /* 回転               */
  glTranslated(-1.0, -1.0, 0.0);       /* テクスチャ座標の中央を原点に移動 */
  
  /* モデルビュー変換行列の設定 */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
・・・

回りました?これは図形(ポリゴン)の方をまったく操作しておらず,ポリゴン自体は回っていません.でも,アルファテストを有効にしてみると…

・・・
  
/*
** シーンの描画
*/
static void scene(void)
{
  ・・・
  
  /* アルファテスト開始 */
  glEnable(GL_ALPHA_TEST);
  
  /* テクスチャマッピング開始 */
  glEnable(GL_TEXTURE_2D);
  
  ・・・

デモプログラム

ここまでの内容でデモプログラムを作ってあります.ただし,1枚のポリゴンでは面白くないので,箱にしてあります.

今後の予定

今後は以下の内容について書くつもりですが,10月末までにどうしてもやってしまいたい(しまわなければならない)ことがありますので,しばらくそちらに集中します.

  • テクスチャ座標の自動生成
    • スフィアマッピング
    • キューブマッピング
    • プロジェクションマッピング
  • 複数のテクスチャを使う
    • テクスチャの部分的変更
    • テクスチャオブジェクト
    • マルチテクスチャ
    • レンダリング結果をテクスチャに使う
  • プログラマブルシェーダ(GLSL - できるかな?)

編集 «第4回 アルファテスト 最新 第6回 投影マッピング»