見出し画像

テクスチャマッピング

サイズが1024×1024の画像をOpenGLで画面に表示するために、

  1. 画像を読み込む。

  2. 画像をOpenGL向けの形式に変換する。

  3. OpenGLで描画するコントロール(ウィンドウ)を用意する。

  4. 1024×1024の長方形の平板を作る。

  5. テクスチャを作ってそこに画像データを流し込み、平板に貼り付ける(テクスチャマッピング)。

  6. 視点を平板の中央真上に、視線の向きを平板の法線に固定する(モデルビュー行列の設定)。

  7. 平板がコントロール(ウィンドウ)に収まるように表示する範囲を決める(プロジェクション行列の設定)。

をする。

1~3はリンク先の記事に記載しているのでこの記事では触れない。

この記事では4と5、特に5のテクスチャマッピングに焦点を当てる。


1. テクスチャを作る

1つあれば事足りるが、美術館のように絵をいくつも並べてみたいので
4つ作ってみる。

const int N_TEX = 4 ;
unsigned int* textureNames = new unsigned int[N_TEX];
memset( textureNames, 0x00, sizeof( unsigned int ) * N_TEX );
glGenTextures( N_TEX, textureNames );

// glReadPixels()
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );


2. テクスチャに画像を流し込む

作成したテクスチャに、サイズ width × height の画像データ imageData を流し込む。

imageData は画像の各ピクセルのRGB値の配列で、R、G、Bに1バイトずつ使用しているので、glTexImge2Dの7番目、8番目の引数に GL_RGB、GL_UNSIGNED_BYTE を指定している。

void SetImageToTexture( unsigned int textureName,
                      int width, int height, const void* imageData )
{
  glBindTexture( GL_TEXTURE_2D, textureName );

  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, 
                                GL_RGB, GL_UNSIGNED_BYTE, data );

  glBindTexture( GL_TEXTURE_2D, 0 );
}


3. 平板を作る

XY平面上にサイズ width × height の長方形(平板)を作る。
長方形の左下隅を原点にする。
画像をテクスチャとして貼り付けるので、長方形の各頂点にUV座標を設定しておく。
画像の大きさと平板の大きさをそろえているので、単純に四隅のUV値を( 0, 0 ), ( 1, 0 ), ( 1, 1 ), ( 0, 1 ) にすれば平板全体に画像が表示されアスペクト比も維持される。

void CreateBoard( int width, int height, float zValue = 0 )
{
  glBegin( GL_QUADS );
    glNormal3f( 0, 0, 1 );

    glTexCoord2f( 0, 0 );
    glVertex3f( 0, 0, zValue );

    glTexCoord2f( 1, 0 );
    glVertex3f( width, 0, zValue );

    glTexCoord2f( 1, 1 );
    glVertex3f( width, height, zValue );

    glTexCoord2f( 0, 1 );
    glVertex3f( 0, height, zValue );
  glEnd();
}


4. 平板にテクスチャを貼り付ける

上で作った関数を利用して、テクスチャを貼り付けた平板を作る。

一度平板を作ったらその形や大きさ、貼り付けたテクスチャを変えることはないので、ディスプレイリストにしておく。

unsigned int CreateImageBoardByUsingDisplayList( 
               unsigned int textureName, int width, int height )
{
  unsigned int displayList = glGenLists( 1 );
  glNewList( displayList, GL_COMPILE );
    glBindTexture( GL_TEXTURE_2D, textureName );
    CreateBoard( width, height );
  glEndList();

  return displayList;
}


まとめ

以上の1~4の処理をまとめると以下のようなコードになる。

1と2の間の glPixelStorei は適切に設定すれば、glTexImage2D で OpenGL に画像データを渡す時の処理効率を上げる効果がある。画像データは1ピクセルRGBの3バイトなので「3」を指定できればおそらく効率最高になるが、1、2、4、8 しか指定できない。3の約数は1だけなので、今回は1を指定せざるを得ない。

// 1. テクスチャを作る
const int N_TEX = 4 ;
unsigned int* textureNames = new unsigned int[N_TEX];
memset( textureNames, 0x00, sizeof( unsigned int ) * N_TEX );
glGenTextures( N_TEX, textureNames );

// OpenGLに、画像データがメモリ上にどう格納されているか教える
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );

// 2. テクスチャに画像を流し込む
SetImageToTexture( textureNames[0], width, height, imageData );

// 3. 平板を作ってテクスチャを貼り付ける
unsigned int displayList 
  = CreateImateBordByUsingDisplayList( textureNames[0], width, height );

// 4. 描画する
glCallList( displayList );




いいなと思ったら応援しよう!