DirectXのサンプルを見ているとC++側とHLSL側とで同じ並びの構造体を作ってデータを送っているように見えます。データのレイアウト規則は同じになるのが保証されるのか少々疑問です。一応 D3Dの関数でシェーダーリフレクションが使えるので、調査することはできますが、そこまでやってC++側の定数バッファを作成している例を見かけたことがありません。
一方、OpenGLでは定数バッファ内の変数についてのレイアウトルールは実装依存となることがドキュメント記載されています。これが使いづらいという理由のためか、最近では標準レイアウトルールというものができたようです。uniform ブロックの前に layout(std140) をつけることで使用できます。
ただこのstd140レイアウトルールは使えない場合もある。OpenGL 3.x で定数バッファが導入されているため、ドライバ(やハードウェア)によっては使えない状況というものが生まれてしまう。こういうときをサポートするんであれば、定数バッファ内のどこに何という変数が割り当てられているかをC++側で把握する必要が出てきます。
割り当てられている場所がわかれば、glBufferSubData の関数を用いてデータをUBOにセットしていきます。
さて、D3DReflect と同じことをやるためには、OpenGLではどのような手順で調べるかを書いておきます。OpenGLでももうちょっとシェーダーリフレクションがやりやすくなればいいのにと少し思うくらい手間が多めです。
- glGetProgramiv( GL_ACTIVE_UNIFORM_BLOCKS,… ) で定数バッファの個数を取得
- 以降定数バッファの数だけループ
- glGetActiveUniformBlockName で名前を取得
- 取得した名前を元にブロックのインデックスを取得(blockIndex)
- glGetActiveUniformBlockiv( GL_UNIFORM_BLOCK_DATA_SIZE,…) で定数バッファのサイズを取得
- glGetActiveUniformBlockiv に blockIndex, と GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS をセットして、定数バッファ内にある変数の個数を取得
- glGetActiveUniformBlockiv( GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,…) を用いて、定数バッファ内変数のインデックス値を取得
- glGetActiveUniformsiv( GL_UNIFORM_OFFSET,…) を用いて各変数のオフセットを取得
- 変数の名前を求めるために下記を実行する.
- 各変数のインデックス値をglGetActiveUniformの引数にセット
- ↑変数の名前やデータタイプも取得できる