[この記事は Games Developer Advocate の Shanee Nishry による Android Developers Blog の記事 "Game Performance: Layout Qualifiers " を元に、萩倉が翻訳・加筆したものです。詳しくは元記事をご覧ください。]
今日は OpenGL Shading Language (GLSL)を利用してゲームのパフォーマンスを最適化し、ワークフローを簡素化するベスト プラク
ティスについてお伝えします。Layout Qualifiers は特にコードの確定性を高め、作業者の負荷を減らしてパフォーマンスを高めます。
簡単な頂点シェーダーに変更を加えてみましょう。
位置座標とテクスチャ座標を取得し、頂点の位置を変換し、フラグメント シェーダーにデータを渡す、基本的な頂点シェーダーの例を次に示します。
attribute vec4 vertexPosition ;
attribute vec2 vertexUV ;
uniform mat4 matWorldViewProjection ;
varying vec2 outTexCoord ;
void main ()
{
outTexCoord = vertexUV ;
gl_Position = matWorldViewProjection * vertexPosition ;
}
頂点属性インデックス
画面にメッシュを描画するには、頂点バッファを作成し、頂点データ(ここでは位置座標、テクスチャ座標など)を登録する必要があります。
サンプル シェーダーで頂点データを次のように記述します。
struct Vertex
{
Vector4 Position ;
Vector2 TexCoords ;
};
これに従い、頂点シェーダーの属性を次のように定義します。
attribute vec4 vertexPosition ;
attribute vec2 vertexUV ;
glGetAttribLocation へのコールによって指定された名前の属性の処理が行われ、頂点データがシェーダー属性と関連づけられます。すると属性フォーマットが glVertexAttribPointer へのコールとともに記述されます。
GLint handleVertexPos = glGetAttribLocation ( myShaderProgram , "vertexPosition" );
glVertexAttribPointer ( handleVertexPos , 4 , GL_FLOAT , GL_FALSE , 0 , 0 );
GLint handleVertexUV = glGetAttribLocation ( myShaderProgram , "vertexUV" );
glVertexAttribPointer ( handleVertexUV , 2 , GL_FLOAT , GL_FALSE , 0 , 0 );
しかし、vertexPosition 属性をもつ複数のシェーダーがある場合、各シェーダーの glGetAttribLocation を呼び出すのはパフォーマンスを無駄にし、ゲームの読み込み時間が長くなります。
Layout Qualifiers を利用すると、頂点シェーダー属性の宣言を次のように変更できます。
layout ( location = 0 ) in vec4 vertexPosition ;
layout ( location = 1 ) in vec2 vertexUV ;
またそのためには、使用するシェーダーが GL ES 3.1 に対応していることをシェーダー コンパイラーに伝える必要があります。
以下のバージョン宣言を追加します。
#version 300 es
例示のシェーダーがどのようになるかを見てみましょう。変更点を太字で示します。
#version 300 es
layout ( location = 0 ) in vec4 vertexPosition ;
layout ( location = 1 ) in vec2 vertexUV ;
uniform mat4 matWorldViewProjection ;
out vec2 outTexCoord ;
void main ()
{
outTexCoord = vertexUV ;
gl_Position = matWorldViewProjection * vertexPosition ;
}
OutTexCoord が varying 変数から out 変数に変わっていることもご確認ください。Varying キーワードはバージョン 300 es から動作が保証されなくなったため、シェーダーを機能させるには変更が必要です。
頂点属性の修飾子 と #version 300 es は OpenGL ES 3.0 以降でサポートされています。デスクトップ版は OpenGL 3.3 でサポートされ、#version 330 が使用されています。
ここで位置属性が常に 0 で、テクスチャ座標が 1 になるとわかったら、glGetAttribLocation を使わずに次のようにシェーダー
フォーマットをバインドできます。
const int ATTRIB_POS = 0 ;
const int ATTRIB_UV = 1 ;
glVertexAttribPointer ( ATTRIB_POS , 4 , GL_FLOAT , GL_FALSE , 0 , 0 );
glVertexAttribPointer ( ATTRIB_UV , 2 , GL_FLOAT , GL_FALSE , 0 , 0 );
この簡単な変更でパイプラインを明確にし、コードをシンプルにして、起動の際の負荷を削減できます。
Android でのパフォーマンスの詳細については、Android Performance Patterns の動画シリーズ をご覧ください。
Posted by Takeshi Hagikura - Developer Relations Team