■ 2004年09月13日 [OpenGL][テクスチャ] 第1回 画像の読み込み
テクスチャマッピングについて
手抜きOpenGL にはテクスチャマッピングについて何も書いていないので,研究室の学生さん向けにこれから何回かに分けて簡単な説明を書いてみます.最初は「画像データの読み込み方」です.これは卒業研究などで結構学生さんが引っかかるところだったりしますが,実は自分でもよく悩むんです.特に気分が落ち込んでいると,物事が決められなくなって困るんですね.
画像ローダ
以前,某君が見付けてきた方法は,AUX ライブラリに含まれる auxRGBImageLoad() や auxDIBImageLoad() を使うという手でした.この方法は Windows なんかだと確かにお手軽ですけど,GLUT 使っているのにここだけ AUX 使うのも何だかなぁと言う気がしないでもありません.その線でいけば,nvsdk に png を読む関数が入っていたような記憶がありますし,ATI のサンプルソースプログラムの中には確か tga を読み込むものがあったような気がしますから,こういうものを流用するという手もあるでしょう.また glpng(ドキュメント)というのも便利そうです.MSDN Library にも OpenGL V: Translating Windows DIBs という記事があります.他にも陳先生の Raslib(うちの学生さんなら演習で使ったはずじゃ)をはじめ,Linux で使われる imlib とか jpegsrc とか,いろんな人が画像ローダを書いているので,探せばいくらでも見付かるように思います(おっとぉ,自分でも昔,PPM や BMP を読み込むプログラム書いた覚えがあるぞ).
ただ,Linux でも Mac OS X でも Windows でも通るプログラムにしようとか色々考え出すと,こういうものの使い方を調べたり自分のプログラムに組み込んだりすること自体がなんだか億劫になってきます.それで思考停止の挙げ句,結局「RAW 画像ですませちゃえ」となってしまうんですね.実際はかえって手間がかかるんですけど…
RAW 画像を使う
Photoshop で保存できるファイルの形式の中に,「汎用フォーマット」というのがあります.RAW 画像形式とはこのことです.これは何のことはない,画像のサイズや形式に関する情報を含まず,データの圧縮も行わない,いわゆる「ベタファイル」のことです.これの嬉しいところは,画像データの読み込みが read() 一発で行えるというあたりにあります.
但し,RAW 画像はサイズや深度(色数)に関する情報も含んでいないので,読み込みプログラム内にそのあたりのことを作り込んでおく必要があります.このため,この方法を採用すると融通の利かないプログラムになってしまいます.でも,png や jpeg を読んで画像の大きさを調べ,それに合わせてメモリを確保して…みたいなことをやることの方が,私を滅入らせてしまうのです.
テクスチャ画像を作る
Photoshop(Elements でも可)や GIMP などを使って,テクスチャに使う画像を作ります.画像のモードは,ここでは「RGB モード」にします.また画像のサイズは,縦横 256×256 とか 512×128 という風に,2n 画素にします.OpenGL のテクスチャマッピングにおけるこの制限は,テクスチャを部分的に置き換える glTexSubImage2D() を使うならあまり気にする必要はありません.また OpenGL 2.0 では,この制限自体が撤廃されています.しかし,ここではこの OpenGL の伝統的なマナーに従うことにします.
画像ができたら,画像を別名で保存します.オリジナルは残しておきましょう.
フォーマット(画像の形式)に「汎用フォーマット」を指定します..
次に現れるダイアログで「インターリーブの順序」を選ぶと,カラーデータ(RGB)が1画素毎に順番に格納されます.そのほかの部分はどうでもいいんですが,「ヘッダ」は 0 にしておいて下さい.
あと,どういうサイズの画像を作ったかは,プログラマが覚えておかないといけません.
画像ファイルの読み込み
こうして保存した画像を読み込むプログラムを考えます.一応,雛形のプログラムを用意してあります.以後,このプログラムをもとにして説明しますので,あらかじめ自分の環境で使用できるものをダウンロードして,実行してみてください.
このプログラムは四角形を1枚だけ表示します.一応,マウスで回転できるようになっています.実行できることが確認できたら,このソースプログラム main.cpp の以下の部分に,太字のところを追加してください.記号定数 TEXWIDTH と TEXHEIGHT には,読み込む画像の横幅と高さの画素数を定義します.
・・・ /* ** 光源 */ static const GLfloat lightpos[] = { 0.0, 0.0, 1.0, 0.0 }; /* 位置 */ static const GLfloat lightcol[] = { 1.0, 1.0, 1.0, 1.0 }; /* 直接光強度 */ static const GLfloat lightamb[] = { 0.1, 0.1, 0.1, 1.0 }; /* 環境光強度 */ /* ** テクスチャ */ #define TEXWIDTH 256 /* テクスチャの幅 */ #define TEXHEIGHT 256 /* テクスチャの高さ */ static const char texture1[] = "tire.raw"; /* テクスチャファイル名 */ /* ** 初期化 */ static void init(void) { /* テクスチャの読み込みに使う配列 */ GLubyte texture[TEXHEIGHT][TEXWIDTH][3]; FILE *fp; /* テクスチャ画像の読み込み */ if ((fp = fopen(texture1, "rb")) != NULL) { fread(texture, sizeof texture, 1, fp); fclose(fp); } else { perror(texture1); } /* 初期設定 */ 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); } ・・・
perror() を使ってエラーメッセージを出してますけど,Windows でコンソールを出さないんだったら,別の方法を採用すべきでしょう(あるいはエラーメッセージを出さないか).また,fread() の戻り値をチェックしてませんので,もしファイルがうまく読めなかったら何が表示されるかはお楽しみ :-)
でも,ここまでだと単にファイルを読み込んでいるだけなので,実行結果は何も変わりありません(わざわざ説明を書かないといけないプログラムじゃないかも).読み込んだ画像をテクスチャとして物体に貼り付ける方法は,次回以降で説明します.
GIMPでテクスチャ画像を作る場合どうすればよいですか?
glut見習いさま、コメント有難うございます。お返事が遅くなり、申し訳ありません。<br><br>GIMP の場合は「ファイル」メニューの「エクスポート」で「ファイル形式の選択」に「Raw画像データ」を選んでください。<br>拡張子は .data になります。また「RGB 保存タイプ」は「標準 (R,G,B)」を選んでください。<br><br>なお、GIMP 2.8.14 で試したところ、RGB 画像であっても4チャンネル分保存されるようです。<br>その場合、テクスチャの format には GL_RGBA を指定する必要があります。<br>internalFormat は GL_RGB のままで問題ありません。<br><br> /* テクスチャの割り当て */<br> glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXWIDTH, TEXHEIGHT, 0,<br> GL_RGBA, GL_UNSIGNED_BYTE, texture);<br> ^^^^^^^<br><br>よろしくお願いします。
先日はご回答ありがとうございました(気づくのが遅くなってすいません。)<br><br>テクスチャとは関係ない質問なのですが、キーボードとマウスの同時操作はどうすれば可能でしょうか。例えばマウスに合わせて図形を移動させながら'j'を押すと上に跳ねる動きをさせてみたいのですが、どうやっても'j'を押すと移動が止まってから跳ねる動きになってしまいます。<br>簡単な方法があれば教えて頂きたいです。