OpenGL (GLSL) のユニフォームブロックでのシェーダーリフレクションを試してみました。
ここで使った vertexShader, fragment shaderは以下のようなものです。
// vertex shader #version 410 core layout( location=0 ) in vec3 inPosition; layout( location=1 ) in vec3 inNormal; layout( location=2) in vec2 inTexcoord; uniform mat4 matProjection; uniform mat4 matView; uniform vec3 cameraPosition; struct Material { vec4 diffuse; vec3 specularColor; }; struct Light { vec4 color; vec3 direction; }; struct ModelMesh { Material material; mat4 matWorld; vec4 vUser[4]; }; uniform LightBlock { Light uLight; }; uniform ModelMeshBlock { ModelMesh uModelMesh; }; // 略 // fragment shader #version 410 core in VS_Out { vec4 Color; vec3 Normal; vec2 UV0; } PSIn; out vec4 out_color0; uniform sampler2D gSampler0; uniform samplerCube gSampler1; // 略
これらのシェーダーについて情報を出してみるとこのような感じになりました。
まずはシェーダーユニフォームの一覧.
Shader uniform(s) ---- uniformIndex=0 : loc=0, "cameraPosition" type=vec3, size=1 uniformIndex=1 : loc=1, "gSampler0" type=sampler2D, size=1 uniformIndex=2 : loc=2, "gSampler1" type=samplerCUBE, size=1 uniformIndex=3 : loc=3, "matProjection" type=mat4, size=1 uniformIndex=4 : loc=4, "matView" type=mat4, size=1 uniformIndex=5 : loc=-1, "uLight.color" type=vec4, size=1 uniformIndex=6 : loc=-1, "uLight.direction" type=vec3, size=1 uniformIndex=7 : loc=-1, "uModelMesh.matWorld" type=mat4, size=1 uniformIndex=8 : loc=-1, "uModelMesh.material.diffuse" type=vec4, size=1 uniformIndex=9 : loc=-1, "uModelMesh.material.specularColor" type=vec3, size=1 uniformIndex=10 : loc=-1, "uModelMesh.vUser[0]" type=vec4, size=4
ユニフォームブロックの中身のメンバには、ロケーションIDは振られていないことが確認できます。ユニフォームのインデックスは振られており、情報はこちら軽油で取得できるようです。
そして、ユニフォームブロックに関して情報を取得してみます。
0: LightBlock blockDataSize = 32 0 > uniformIndexInBlock=5 : "uLight.color" offset= 0,type=vec4 1 > uniformIndexInBlock=6 : "uLight.direction" offset= 16,type=vec3 1: ModelMeshBlock blockDataSize = 160 0 > uniformIndexInBlock=7 : "uModelMesh.matWorld" offset= 32,type=mat4 1 > uniformIndexInBlock=8 : "uModelMesh.material.diffuse" offset= 0,type=vec4 2 > uniformIndexInBlock=9 : "uModelMesh.material.specularColor" offset= 16,type=vec3 3 > uniformIndexInBlock=10 : "uModelMesh.vUser[0]" offset= 96,type=vec4
ユニフォームブロック内でのシェーダー定数のオフセットが取得できました。
ユニフォームブロック内に構造体を配置しても、従来のシェーダー定数の場合と変わらないような名前でオフセットやデータ型を取得できることがわかります。
std140 とかレイアウト指定をしない場合、シェーダーによって(環境によって?)定数の位置が変わりそうです。
そのため、UBOを複数のシェーダーで使い回すのは難しそうです。この場合結局定数毎に書き込む位置を見てバッファ内のデータ更新という手続きをとるので、あまりUBOによる描画効率化に繋がらないように感じます。
ユニフォームブロック内の定数であっても GL_ACTIVE_UNIFORMS にて有効なユニフォーム変数としてカウントされていることに少々驚きました。ただしユニフォームブロック内の変数名からは有効なロケーションが取得できません。ユニフォームブロック内の変数についてはロケーション=-1となっているようです。