はじめに
OpenGL ES 3.0、始まってきましたね。Androidが4.3にて正式サポートを開始し、いよいよモバイルデバイスでもPlayStation 3 / Xbox 360世代を少し上回るような高度な表現が可能になってきました。
いずれ、近いうちにiOSも追従してサポートするでしょうし、今後モバイルデバイスで3Dを扱いたい人はぜひES 3.0をマスターしましょう。
OpenGL ES 3.0で何が変わったかについては、以下のサイトが詳しいです。
組み込み向け3DグラフィックスAPIの最新版「OpenGL ES 3.0」が登場
しかし、試そうにもES 3.0に対応したモバイルデバイスはまだまだ少ないのが実情です。できれば、Windows上で試したいですよね。実は、デスクトップ向けのOpenGL4.3に対応したGPUでは、OpenGL ES 3.0互換環境を利用することができます。
この記事では、その利用方法(OpenGL ES 3.0コンテキストの初期化方法)について解説します。
前提知識
OpenGLについて、ある程度なれている方が前提です。
また、WGLについても、多少の知識があることが望ましいです。
前提環境
- Window XP以降(筆者はWindows 7 64bit で動作確認)
- OpenGL4.3に対応したnVidia社製 GPU(筆者はGeforce GT 520で動作確認)
(GPUのドライバーは最新のバージョンをインストールしてください)
準備
OpenGL Registry から wglext.h をダウンロードし、インクルードします。
コード説明
以下が初期化コードになります。
このコードだけじゃ全体像がわからないよ! という方は、
こちらのサイト様のサンプルコードをご覧ください。
OpenGL(WGL)サンプルプログラム on Windows7(fujinsブログ様)
以下のコードは、上記サイト様のサンプルコードの初期化コード部分を、私がOpenGL ES 3.0にあわせて改変したものになります。
ちなみにWGLとは、Windows依存のOpenGL関連機能(Windows向けのOpenGLレンダリングコンテキストを作成したり、OpenGLの拡張関数を取得するなど)を利用するためのAPIです。
処理の手順としては、次のようになります。
- PIXELFORMATDESCRIPTOR型の変数として、ピクセルフォーマットを作成する。
- ChoosePixelFormat() を使って、フォーマットのマッチングを行う。
- 4のステップのために、通常の手段で 仮のContext を作成し wglMakeCurrent() でコンテキストを有効にする。
- WGL の拡張 API 、wglCreateContextAttribsARB() を取得する。
- wglCreateContextAttribsARB() を使って OpenGL ES 3.0 コンテキストを作る。
- 3のステップで作った仮のコンテキストを削除する。
int initGL( HWND hwnd, HDC *p_hdc, HGLRC *p_hglrc ) {
// ピクセルフォーマットの指定
static PIXELFORMATDESCRIPTOR pformat= {
sizeof(PIXELFORMATDESCRIPTOR),
1,
0
|PFD_DRAW_TO_WINDOW
|PFD_SUPPORT_OPENGL
|PFD_DOUBLEBUFFER
,
PFD_TYPE_RGBA,
32, // color
0, 0, // R
0, 0, // G
0, 0, // B
0, 0, // A
0, 0, 0, 0, 0, // AC R G B A
24, // depth
8, // stencil
0, // aux
0, // layertype
0, // reserved
0, // layermask
0, // visiblemask
0 // damagemask
};
// デバイスコンテキストを取得する
HDC hDC= GetDC( hwnd );
// フォーマットのマッチングを行う
int pfmt= ChoosePixelFormat( hDC, &pformat );
// ピクセルフォーマットを設定
SetPixelFormat( hDC, pfmt, &pformat );
// wglCreateContextAttribsARBを取得するために、仮のコンテキストを取得
HGLRC hGLRC_old = wglCreateContext( hDC );
// 仮のコンテキストを有効にする
wglMakeCurrent( hDC, hGLRC_old );
// wglCreateContextAttribsARB 関数の取得
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( "wglCreateContextAttribsARB" );
// 取得したいOpenGL環境(今回はES 3.0)の指定
static const int opengl_es30[]= {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 0,
WGL_CONTEXT_FLAGS_ARB, 0,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
0,
};
// ES3.0のコンテキストを取得
HGLRC hGLRC= wglCreateContextAttribsARB( hDC, 0, opengl_es30 );
// コンテキストを有効にする
wglMakeCurrent( hDC, hGLRC );
// 仮のコンテキストを削除
wglDeleteContext( hGLRC_old );
// ベンダー情報の取得
const GLubyte *strVendor = glGetString(GL_VENDOR);
std::cout << "GL_VENDOR : " << strVendor << std::endl;
// レンダラー情報の取得
const GLubyte *strRenderer = glGetString(GL_RENDERER);
std::cout << "GL_RENDERER : " << strRenderer << std::endl;
// バージョン情報の取得
const GLubyte *strVersion = glGetString(GL_VERSION);
std::cout << "GL_VERSION : " << strVersion << std::endl;
// OpenGL GLSL バージョンの取得
const GLubyte * strShaderLanguageVersion = glGetString (GL_SHADING_LANGUAGE_VERSION);
std::cout << "GL_SHADING_LANGUAGE_VERSION : " << strShaderLanguageVersion << std::endl;
// OpenGL拡張の取得
const GLubyte * strExtensions = glGetString (GL_EXTENSIONS);
std::cout << "GL_EXTENSIONS : " << strExtensions << std::endl;
*p_hdc= hDC;
*p_hglrc= hGLRC;
return 0;
}
描画コードについて
ただし、上記サイト様のサンプルコードの描画処理や透視変換関数は、OpenGL ES 3.0とは互換性がないため、描画コードもろもろ(シェーダーや頂点オブジェクトの作成処理なども含む)については床井研究室様の以下のページで説明されているサンプルコードを利用してください。
http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20120909
ただし、このコードでも注意点が。Windowsでは、標準で使えるOpenGLの関数はバージョン1.1までのものしかなく、それ以外の最近の関数はwglGetProcAddress関数で取得する必要があります。
以下のように行ってください。
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress( "glGenVertexArrays" );
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress( "glBindVertexArray" );
また、シェーダープログラムについては、OpenGL ES 3.0に対応させるため、以下のコードで置き換えてください。
// バーテックスシェーダのソースプログラム
static const GLchar vsrc[] =
"#version 300 es\n"
"in lowp vec4 pv;\n"
"void main(void)\n"
"{\n"
" gl_Position = pv;\n"
"}\n";
// フラグメントシェーダのソースプログラム
static const GLchar fsrc[] =
"#version 300 es\n"
"out lowp vec4 fc;\n"
"void main(void)\n"
"{\n"
" fc = vec4(1.0, 0.0, 0.0, 0.0);\n"
"}\n";
以上で、動作するはずです。以下のような描画が行えれば成功です。
おわりに
一部のコードしか示さず、あとはあっちを参考にしてごにょごにょしろとか、おまいなめとんのか的な説明になってしまい大変申し訳ないです(汗)
私の手元で動いているコードを全部晒せれば手っ取り早いのですが、いろいろ汚いこともありまして、後日の課題とさせてくださいorz
ともかく、OpenGL4.3はOpenGL ES 3.0と互換性が確保されていますので、OpenGL4.3に対応するGPUならOpenGL ES 3.0のプログラム開発を行うことができます。
もちろん、本当にモバイルデバイスで動くかは、実機で検証した方がいいと思いますが、とっかかりの開発環境として使えると思います。