ゲームフレームワーク的なものを作る。(10)〜OpenGLでテクスチャを使う〜
まずはOpenGLでテクスチャを使用する際の基本から。
R8G8B8A8の32bitテクスチャを作る
GLuint texture;
Size size( w, h );
DWORD pixel[] = { ... }; //適当なピクセルデータを設定しておく
- glGenTextures()で指定枚数のテクスチャを作成。とりあえず1でよい。
- glBindTexture()で作成したテクスチャをバインドしてから、フィルタなどのパラメータを設定
- フィルタの設定は必須。
- glTexture2D()でピクセルデータをコピー。
- バインド解除
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); glGenTextures( 1, &texture ); glBindTexture( GL_TEXTURE_2D, texture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel ); glBindTexture( GL_TEXTURE_2D, 0 ); //バインド解除
- 使い終わったらglDeleteTextures()で削除
glDeleteTextures( 1, &texture );
テクスチャの生成は以上で終了です。
スクリーンの設定
OpenGLではデフォルトで画面の中心を原点とした上に向かってY軸の正(-1.0〜1.0)、右に向かってX軸の正(-1.0〜1.0)となるような座標系になっているので、
画面の左上を原点、ウィンドウサイズに合わせた座標系に変更します。
//ビューポート行列の設定 glViewport( 0, 0, client_size.width, client_size.height ); //プロジェクション行列の設定 glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluOrtho2D( 0.0, static_cast< GLdouble >( client_size.width ), //left, right static_cast< GLdouble >( client_size.height ), 0.0 //bottom, top ); //ビュー行列の設定 glMatrixMode( GL_MODELVIEW ); glLoadIdentity();
ポリゴンにテクスチャを貼る
- glEnable()でテクスチャマップを有効化
- glBindTexture()でポリゴンに貼るテクスチャを設定
- glBegin()〜glEnd()でポリゴンの各頂点を設定
- glTexCoord(s,t)でテクスチャ座標(0.0〜1.0)の設定
- glVertex2f(x,y)で頂点座標の設定
glEnable( GL_TEXTURE_2D ); //テクスチャマップを有効にする glBindTexture( GL_TEXTURE_2D, texture ); //生成したテクスチャをバインド glBegin( GL_QUADS ); //四角形ポリゴン //左上から時計回りの四角形 glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.0f, 0.0f ); //左上 glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 128.0f, 0.0f ); //右上 glTexCoord2f( 1.0f, 1.0f ); glVertex2f( 128.0f, 128.0f ); //右下 glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.0f, 128.0f ); //左下 glEnd(); glBindTexture( GL_TEXTURE_2D, 0 ); //テクスチャ解除 glDisable( GL_TEXTURE_2D ); //テクスチャマップ無効
ちなみにテクスチャは以下のように作っています。
DWORD pixel[ 64 * 64 ]; int index = 0; for( int y = 0; y < 64; y ++ ) { for( int x = 0; x < 64; x ++ ) { Color color; color.r = x / 63.0f; color.g = 0.0f; color.b = y / 63.0f; color.a = 1.0f; pixel[ index ] = color.to_R8G8B8A8(); index ++; } }
ピクセルフォーマット
VC++2010ExpressEditionで32ビットテクスチャを作る場合、デフォルトで上位バイトからR8G8B8A8のフォーマットしか使えません(OpenGL 1.1)。Direct3Dと同じA8R8G8B8を使いたければ、こちらから「glext.h」「glxext.h」「wglext.h」をダウンロード、インストールして(VCのパスを通す)、インクルードする必要があります。(OpenGL 1.2以上)
format | type | |
---|---|---|
GL_BGRA | GL_UNSIGNED_INT_8_8_8_8 | 0xbbggrraa |
GL_RGBA | GL_UNSIGNED_INT_8_8_8_8 | 0xrrggbbaa |
GL_BGRA | GL_UNSIGNED_INT_8_8_8_8_REV | 0xaabbggrr |
GL_RGBA | GL_UNSIGNED_INT_8_8_8_8_REV | 0xaarrggbb |
/** * ピクセルフォーマット **/ struct PixelFormat { enum Type { Unknown, b8g8r8a8, //0xbbggrraa r8g8b8a8, //0xrrggbbaa a8r8g8b8, //0xaarrggbb a8b8g8r8, //0xaabbggrr }; };
int format = 0, type = 0; switch( pixel_format ) { case PixelFormat::b8g8r8a8: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8; break; case PixelFormat::r8g8b8a8: format = GL_RGBA, type = GL_UNSIGNED_INT_8_8_8_8; break; case PixelFormat::a8r8g8b8: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8_REV; break; case PixelFormat::a8b8g8r8: format = GL_RGBA, type = GL_UNSIGNED_INT_8_8_8_8_REV; break; default: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8; break; } glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, format, type, &pixel[ 0 ] );
テクスチャインターフェイス
デバッグ用にテクスチャの情報を出力するために文字列化インターフェイスを実装しておくと便利かもしれません。
/** * テクスチャインターフェイス */ class ITexture : public IStringizable //ストリームへ出力可能 , noncopyable //インスタンスのコピー禁止 { public: /** * デストラクタ */ virtual ~ITexture(){} public: /** * サイズを取得 */ virtual Size GetSize()const = 0; /** * ピクセルフォーマットを取得 */ virtual PixelFormat::Type GetPixelFormat()const = 0; };
OpenGLテクスチャクラス
/** * テクスチャクラス(OpenGLによる実装) */ class OpenGLTexture : public ITexture { // ------------------------------------------------------------------------------- // 生成と破棄 // ------------------------------------------------------------------------------- public: /** * コンストラクタ */ OpenGLTexture( const std::vector< DWORD >& pixel, const Size& size, PixelFormat::Type pixel_format ); /** * デストラクタ */ ~OpenGLTexture(); // ------------------------------------------------------------------------------- // ITexture実装 // ------------------------------------------------------------------------------- public: /** * テクスチャサイズ取得 */ Size GetSize()const{ return size; } /** * ピクセルフォーマット取得 */ PixelFormat::Type GetPixelFormat()const{ return pixel_format; } // ------------------------------------------------------------------------------- // IStringizable実装 // ------------------------------------------------------------------------------- private: /** * 文字列への変換 */ String to_string()const; // ------------------------------------------------------------------------------- // 基本機能 // ------------------------------------------------------------------------------- public: /** * インスタンスを取得 */ GLuint GetInstance()const{ return instance; } private: Size size; ///< テクスチャサイズ PixelFormat::Type pixel_format; ///< ピクセルフォーマット GLuint instance; ///< OpenGLテクスチャの実体 };
/** * コンストラクタ * * @param pixel ピクセル配列 * @param size テクスチャサイズ * @param pixel_format ピクセルフォーマット */ OpenGLTexture::OpenGLTexture( const std::vector< DWORD >& pixel, const Size& size, PixelFormat::Type pixel_format ) : size( size ) , instance( 0 ) , pixel_format( pixel_format ) { //ピクセルフォーマットの選択 int format = 0, type = 0; switch( pixel_format ) { case PixelFormat::b8g8r8a8: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8; break; case PixelFormat::r8g8b8a8: format = GL_RGBA, type = GL_UNSIGNED_INT_8_8_8_8; break; case PixelFormat::a8r8g8b8: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8_REV; break; case PixelFormat::a8b8g8r8: format = GL_RGBA, type = GL_UNSIGNED_INT_8_8_8_8_REV; break; default: format = GL_BGRA, type = GL_UNSIGNED_INT_8_8_8_8; break; } //テクスチャ生成 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); glGenTextures( 1, &instance ); glBindTexture( GL_TEXTURE_2D, instance ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, format, type, &pixel[ 0 ] ); glBindTexture( GL_TEXTURE_2D, 0 ); } /** * デストラクタ */ OpenGLTexture::~OpenGLTexture() { glDeleteTextures( 1, &instance ); } /** * 文字列への変換。サイズを出力 */ String OpenGLTexture::to_string()const { std::stringstream ss; ss << size; return ss.str(); }
使い方
//適当なテクスチャを作成 std::vector< DWORD > pixel( 64 * 64 ); int index = 0; for( int y = 0; y < 64; y ++ ) { for( int x = 0; x < 64; x ++ ) { Color color; color.r = ( x & 63 ) / 63.0f; color.g = 0.0f; color.b = ( y & 63 ) / 63.0f; color.a = 1.0f; pixel[ index ] = color.to_a8r8g8b8(); index ++; } } OpenGLTexture texture( pixel, Size( 64, 64 ), PixelFormat::a8r8g8b8 ); //適当なポリゴンを描画 glEnable( GL_TEXTURE_2D ); //テクスチャマップを有効にする glBindTexture( GL_TEXTURE_2D, texture.GetInstance() ); //生成したテクスチャをバインド glPushMatrix(); glBegin( GL_QUADS ); //四角形ポリゴン //左上から時計回りの四角形 glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.0f, 0.0f ); //左上 glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 128.0f, 0.0f ); //右上 glTexCoord2f( 1.0f, 1.0f ); glVertex2f( 128.0f, 128.0f ); //右下 glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.0f, 128.0f ); //左下 glEnd(); glPopMatrix(); glBindTexture( GL_TEXTURE_2D, 0 ); //テクスチャ解除 glDisable( GL_TEXTURE_2D ); //テクスチャマップ無効