3

GLSL ユニフォーム ブロックのサイズが間違っているという問題が発生しています。

これはシェーダーのブロックです。

uniform MaterialInfo {
    vec3 Ka;
    vec3 Ks;    
    vec3 Kd;
};

次に、次のコードを使用して、均一なバッファー オブジェクトを準備します。

blockIndex = glGetUniformBlockIndex(program, "MaterialInfo");
 if (blockIndex == -1) {
   fprintf(stderr, "Could not bind uniform block\n");
}

printf("Found blockindex materialinfo: %d\n", blockIndex);

 glGetActiveUniformBlockiv(program, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
 blockBuffer = (GLubyte *) malloc(blockSize);
 cout << "GLSL blocksize: " << blockSize << endl;
 cout << "sizeof glm::vec3 type: " << sizeof(mesh->Ka) << endl;
 cout << "sizeof 3 x glm::vec3 type: " << 3 * sizeof(mesh->Ka) << endl;

は次のように報告しています。

GLSL blocksize: 48
sizeof glm::vec3 type: 12
sizeof 3 x glm::vec3 type: 36

要約すると、GLSL のブロックサイズは 48 ではなく 36 であると予想していました。

また、HD4000 ベータ ドライバー (OpenGL 4.0.0 Build 9.17.10.2792) を使用していることにも注意してください。別のコンピューターでテストする機会はありませんでした。これは私が何か誤解しているのでしょうか?

返信後のフォローアップ:

したがって、この場合、glm::vec3 フロートを送信する正しい方法は次のとおりですか?

glGetUniformIndices(program, 3, namesMaterial, indices);
glGetActiveUniformsiv(program, 3, indices, GL_UNIFORM_OFFSET, offset);

memcpy(blockBuffer + offset[0], glm::value_ptr(mesh->Ka), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[1], glm::value_ptr(mesh->Ks), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[2], glm::value_ptr(mesh->Kd), 4 * sizeof(GLfloat));
4

2 に答える 2

3

多くのGPUは、各ユニフォームをvec4のサイズにパディングします。

OpenGL wiki(私の強調)からのこの実装ノートを参照してください:

実装上の注意:OpenGL実装は、実装に依存する理由でシェーダーを拒否できます。したがって、計算によってアクティブな均一コンポーネントを少なくしても、均一な制限のためにリンクに失敗する可能性があります。これは通常、完全にベクトル化されたハードウェアであるハードウェア上にあります。以前のGeForce8xxxハードウェア、およびすべてのATiハードウェアがこれを行います。この場合、D3Dの場合と同様に、各ユニフォームが4つのコンポーネントを占めると想定する必要があります。つまり、「均一フロート」は4コンポーネント、mat2x4は16コンポーネント(各行は4コンポーネント)ですが、mat4x2は8コンポーネントです。

于 2012-10-04T20:48:36.563 に答える
3

要約すると、GLSL のブロックサイズは 48 ではなく 36 であると予想していました。

なんで?OpenGL 仕様には、ブロック サイズを保証するものは何もありません。

または、少なくとも、均一なブロックの定義ではありません。

適切なメモリ レイアウト修飾子を指定しないと、sharedデフォルトで使用されます。これにより、実装は要素間に快適に感じるパディングを配置できます。vec3したがって、3秒が連続して 12float秒のサイズになると想定することはできません。それぞれvec3が 3 つの連続するfloats になりますが、パディングがないという保証はありません。

統一されたブロックの固定された既知の一貫したstd140レイアウトが必要な場合は、そのレイアウトを使用する必要があります。それ以外の場合は、実装が提供するものを取得しています。OpenGL 仕様では、std140の要素レイアウトのルールについて詳しく説明しています。

もちろん、std140レイアウトでは、すべての要素をsにパディングするため、このブロックのサイズ48 になります。vec3vec4


したがって、この場合、glm::vec3 フロートを送信する正しい方法は次のとおりですか?

これは正しいと仮定すると、次のようになります。

  1. memoryBlockマップされたバッファオブジェクトポインタまたはアップロードしたもののいずれかですglBufferSubData
  2. バッファの先頭または適切なオフセットの 1 つにアップロードしています (glBindBufferRange の均一なブロックのオフセットは に揃える必要がありますGL_UNIFORM_BUFFER_OFFSET_ALIGNMENT)。
  3. mesh->Kaそしてその同類は実際に4つのフロートを行います。それ以外の場合は、未割り当てのメモリからコピーしています。

繰り返しますが、このようなクエリをやめて、レイアウトを使用することを強くstd140お勧めします。その場合、オフセットなどを照会する必要はありません。すべてのハードウェアで GLSL 定義と完全に互換性のあるレイアウトの構造体を設計できます。

于 2012-10-04T20:52:59.490 に答える