テクスチャを割り当てる
今回は配列に読み込んだ画像をポリゴンに貼り付けます。画像を読み込んだ配列は、コンピュータのメインメモリ上にあります。テクスチャマッピングを行うには、これを OpenGL が管理するテクスチャメモリ(グラフィックスカード上のメモリあるいはグラフィックスカードのドライバ確保したメモリ)に転送して、グラフィックスコントローラから参照できるようにします。
2次元画像をテクスチャとして使う場合、これには glTexImage2D() という関数を使います。他に1次元テクスチャを扱う glTexImage1D() や3次元テクスチャを扱う glTexImage3D() というのもあります。ここでは、ごく普通に2次元画像をテクスチャとして用いますから、glTexImage2D() を使います。
/*
** 初期化
*/
static void init()
{
/* テクスチャの読み込みに使う配列 */
GLubyte texture[TEXHEIGHT][TEXWIDTH][3];
/* テクスチャ画像の読み込み */
FILE* fp = fopen(texture_file, "rb");
if (fp != NULL) {
fread(texture, sizeof texture, 1, fp);
fclose(fp);
}
else {
perror(texture_file);
}
/* テクスチャの割り当て */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXWIDTH, TEXHEIGHT, 0,
GL_RGB, GL_UNSIGNED_BYTE, texture);
/* テクスチャを拡大・縮小する方法の指定 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
/* 初期設定 */
glClearColor(0.3, 0.3, 1.0, 0.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
/* 光源の初期設定 */
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightcol);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightcol);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightamb);
}
- void glTexParameteri(GLenum target, GLenum pname, GLint param)
glTexParameteri()はテクスチャマッピングを行う際の種々のパラメータの設定を行います。2次元のテクスチャを扱うときは、引数targetにGL_TEXTURE_2Dを指定します。引数pnameにGL_TEXTURE_MAG_FILTERあるいはGL_TEXTURE_MIN_FILTERを指定したときは、paramにテクスチャマッピングの際の画像の補間方法を指定します。画像をオブジェクト(物体)にテクスチャマッピングすると、その画像はオブジェクトの見かけの大きさにあわせて拡大あるいは縮小されます。GL_TEXTURE_MAG_FILTERはテクスチャが拡大されるときの補間方法の指定を行い、paramにはGL_NEAREST(最近傍法)あるいはGL_LINEAR(双線形補間)が指定できます。またGL_TEXTURE_MIN_FILTERはテクスチャが縮小されるときの補間方法を指定を行い、paramにはGL_NEAREST,GL_LINEAR, およびGL_NEAREST_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_NEAREST,GL_LINEAR_MIPMAP_LINEARが指定できます。MIPMAP は画像の縮小サンプリングを行う際のエリアシングの発生を抑える手法ですが、ここでは説明を割愛します。詳しくは CG の本なりマニュアルなりを読んでください。- void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
- メモリ上の2次元画像をテクスチャに割り当てます。引数
targetはGL_TEXTURE_2Dでないといけません。levelには MIPMAP を行う場合のテクスチャの解像度レベルを指定します。MIPMAP を行わない場合は 0 にしておいてください。internalFormatは、テクスチャの OpenGL 内部でどのように保持するかを指定します。GL_RGBは RGB 形式で保持します。このほかにGL_RGBA,GL_ALPHA,GL_LUMINANCE,GL_LUMINANCE_ALPHA,GL_INTENSITYなど、全部で 38 種類のものが指定できます。widthとheightは、それぞれテクスチャの幅と高さです。borderは境界線の太さです。0 を指定すれば、テクスチャに境界線は付きません。formatは引数 pixels に指定したメモリ上の画像の形式です。GL_RGBのほか、GL_RGBA,GL_COLOR_INDEX,GL_RED,GL_GREEN,GL_BLUE,GL_ALPHA,GL_LUMINANCE,GL_LUMINANCE_ALPHAが指定できます。typeには引数pixelの要素のデータ型を指定します。GL_UNSIGNED_BYTEは*pixelsがGLubyte(unsigned charと等価)であることを示します。他にGL_BYTE,GL_SHORT,GL_UNSIGNED_SHORT,GL_INT,GL_UNSIGNED_INT,GL_FLOAT,GL_BITMAPが指定できます。pixelsにはテクスチャの画像を格納したメモリ(配列)のポインタを指定します。
ふぅ〜、こうなるからテクスチャマッピングに関係する関数の説明ってヤなんだけど、これらの関数の全部の機能を押さえるのは後回しにして、とりあえず上のサンプルプログラムの太字の部分が何をしているのかだけを理解?しておいてください。
これは 2004 年の記事です。OpenGL (3.1以降 Core Profile) および OpenGL ES 2.0/3.0 以降では、
GL_ALPHA、GL_LUMINANCE、GL_LUMINANCE_ALPHA、GL_INTENSITY、GL_COLOR_INDEX、GL_BITMAPは廃止されました。またborderも意味を持たなくなりましたので、常に 0 を指定してください。詳しくは OpenGL 4.0 以降の glTexImage2D() のマニュアルを読んでください。
テクスチャ座標と頂点の対応付け
読み込んだ画像は、サイズ(すなわち glTeXImage2D() の引数 width と height に指定した値)に関係なく、テクスチャ空間 (s, t) 上の 2 点 (0, 0), (1, 1) を対角線とする正方形上に配置されます(これは初期設定であり、画像を配置するテクスチャ空間上の領域は自由に設定できます)。テクスチャマッピングを行うには、ポリゴンの頂点に対して、このテクスチャ空間中の対応する位置を指定します。

ただし、画像の原点(画像ファイルの最初の画素)の位置は通常画像の左上隅ですが、テクスチャ空間上では原点はテクスチャの左下にあるので、このプログラムの方法で画像を読み込んだ場合、画像は上下反転した形で読み込まれています。ポリゴンの頂点にテクスチャ座標を割り当てるときは、このことを考慮に入れる必要があります。たとえば、上図のように四角形ポリゴンの全面にテクスチャを貼り付けようとしたとき、ポリゴンの左下の頂点 (-1, -1, 0) に対応するテクスチャ座標は、テクスチャの左上 (0, 1) になります。
ポリゴンの頂点にテクスチャ座標を割り当てるには、glVertex3d() などで頂点の位置を指定する前に、その頂点のテクスチャ座標を glTexCoord2d() を使って指定します。またテクスチャを使う前に glEnable(GL_TEXTURE_2D) を呼び出して、テクスチャマッピングを有効にしておきます。
/*
** シーンの描画
*/
static void scene()
{
static const GLfloat color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; /* 材質 (色) */
/* 材質の設定 */
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
/* テクスチャマッピング開始 */
glEnable(GL_TEXTURE_2D);
/* 1枚の4角形を描く */
glNormal3d(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glTexCoord2d(0.0, 1.0);
glVertex3d(-1.0, -1.0, 0.0);
glTexCoord2d(1.0, 1.0);
glVertex3d( 1.0, -1.0, 0.0);
glTexCoord2d(1.0, 0.0);
glVertex3d( 1.0, 1.0, 0.0);
glTexCoord2d(0.0, 0.0);
glVertex3d(-1.0, 1.0, 0.0);
glEnd();
/* テクスチャマッピング終了 */
glDisable(GL_TEXTURE_2D);
}
これでプログラムをコンパイルして実行すれば、テクスチャを貼ったポリゴンが表示されるはずです。

MIPMAP について
ちなみに MIPMAP が使いたければ、次のようにテクスチャの拡大フィルタ (GL_TEXTURE_MAG_FILTER) や縮小フィルタ (GL_TEXTURE_MIN_FILTER) に線形補間 (GL_LINEAR や GL_LINEAR_MIPMAP_LINEAR など) を使ってみてください。マッピングされたテクスチャのギザギザが、多少滑らかになります。
/* テクスチャの割り当て */
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, TEXWIDTH, TEXHEIGHT,
GL_RGB, GL_UNSIGNED_BYTE, texture);
/* テクスチャを拡大・縮小する方法の指定 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
こんな具合です。

なお、gluBuild2DMipmaps() を使う場合は、画像のサイズを 2n にあわせる必要はありません。gluBuild2DMipmaps() が自動的に調節してくれます。