OpenGL Fast-Object Instancing Error


8

オブジェクトのセットをループしてそれらのオブジェクトのインスタンスをレンダリングするコードがいくつかあります。レンダリングする必要があるオブジェクトのリストはstd :: map>として保存されます。MeshResourceクラスのオブジェクトには実際のデータを含む頂点とインデックスが含まれ、classMeshRendererのオブジェクトはメッシュが配置される空間内のポイントを定義しますでレンダリングされます。

私のレンダリングコードは次のとおりです。

glDisable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glDepthMask(GL_TRUE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
    {
        it->first->setupBeforeRendering();
        cout << "<";
        for (unsigned long i =0; i < it->second.size(); i++)
        {
            //Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
            uniformizeModelMatrix(Matrix4::IDENTITY);
            /**
             * StartHere fix rendering problem.
             * Ruled out:
             *  Vertex buffers correctly.
             *  Index buffers correctly.
             *  Matrices correct?
             */
            it->first->render();
        }
        it->first->cleanupAfterRendering();
    }

    geometryPassShader->disable();
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

ユニフォームの設定を処理するMeshResourceの関数は次のとおりです。

void MeshResource::setupBeforeRendering()
{
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    glEnableVertexAttribArray(4);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
    glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}

オブジェクトをレンダリングするコードは次のとおりです。

void MeshResource::render()
{
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

そして、クリーンアップするコードはこれです:

void MeshResource::cleanupAfterRendering()
{
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
}

この結果、黒い画面が表示されますが、レンダリングコードの後のレンダリングパイプラインの最後(基本的には画面上に軸と線を描画するだけ)は正しく機能するため、問題はないと確信しています。制服の通過。ただし、次のように、レンダリングコードがレンダリングの直前にセットアップを呼び出すようにコードを少し変更するとします。

void MeshResource::render()
{
    setupBeforeRendering();
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

プログラムは必要に応じて機能します。ただし、頂点、マテリアルなどのデータをオブジェクトタイプごとに1回設定し、変換情報のみを更新して各インスタンスをレンダリングすることが目的なので、これを実行する必要はありません。

uniformizeModelMatrixは次のように機能します。

void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
    glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

モデルをレンダリングするための設定はほぼ同じです。レンダーコールを除いて、バッファをバインドし、毎回属性ポインタを設定します。これでパフォーマンスの問題が発生していますか?それは私にとって非常に高速に実行されます。
MichaelHouse

画面上に何百もの同一のオブジェクトがない限り、パフォーマンスの問題に遭遇していませんが、それでもここで何が問題になっているのかを理解することはできません。コードが期待どおりに機能しない理由を知るのは素晴らしいことです。
HJ Media Studios

1
私たちは、彼が常駐するopenGLエキスパートである@NicolBolasの注意を引く必要があります。
MichaelHouse

offsetof頂点属性を指定するときに使用するとよいでしょう
JBeurer

回答:


2

まず第一に、OpenGLには奇妙なものがたくさんあるので、ドライバーのバグはありそうですが、それでも1つの選択肢です-異なる設定(nVidiaとAMD、古いドライバー)でコードを変更してアプリをテストすることを検討してください。たとえば、「glBindBuffer(GL_UNIFORM_BUFFER、0);」を削除することから始めることができます。行-それはとにかく有用な何もしていないようです。

ここのすべてが正しいように見えるので、問題はおそらくここではありません。2つのオプションがあります:gDEBuggerとC ++デバッガーでコードをステップ実行します。描画する直前に何かがリセットされているようです。gDEBuggerには、「呼び出し履歴」機能があり、描画呼び出しの前に行われた呼び出しとその順序を確認するのに役立ちます。

ちなみに、エラーを返すすべての呼び出しを、考えられるすべてのエラーをチェックしてスローするマクロでラップすることを強くお勧めします。これは、リリースビルドで無効にできる拡張デバッグ(ファイル、行、およびコード自体のエラーのある行自体)をサポートするマクロでなければなりません。秘密のルールが破られた場合、そのような設定はそのことをすぐに警告するはずです。


5
Gremedyのサイトへのリンクは避けます。そのバージョンのgDEBuggerは古く、サポートされておらず、非常にバグがあります。 developer.amd.com/tools/heterogeneous-computing/amd-gdebuggerは、WindowsおよびLinuxをサポートする最新のAMD対応バージョンです(残念ながらOS Xはありません)。AMDのサイトには、NVIDIAとIntelが提供するツールは言うまでもなく、他にも素晴らしいGLデバッグ/パフォーマンスツールがいくつかあります。
Sean Middleditch

0

属性を現在のバッファーにバインドする必要があると確信しているため、毎回バッファーを再構築しない限り、フレームごとに属性でこのビジネスをやり直す理由はありません...

したがって、おそらくどちらか一方の方法で行う必要があります。そのままにするか、フレームごとにすべてを再構築します。


0

TL; DR:ドライバーのバグ。

今日(2016年10月)の私のテストでは、ほとんどのドライバーが均一バッファーを適切にサポートしいません

シェーダーのGPUキャッシュの内部コピーがバッファーに一貫して保持されない場合、glUniformBlockBinding一部は統一データ(glBufferSubDataおよびglBufferData)を適切に更新しないことを尊重しません。


私がそれを理解する方法(およびNvidiaもそれを理解する方法)

  • を使用して、OpenGLドライバー/ GPU内のすべてのシェーダーが共有するグローバルテーブルに Uniform Bufferオブジェクトをバインド/マップします。glBindBufferBaseまたはglBindBufferRange
  • glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);この設定を使用して、シェーダーの均一バッファーアクセスをそのグローバルテーブルへのエントリにマップします。これは、シェーダープログラムごとであり、グローバルには共有されません。

注:global_ubo_indexは、均一バッファーオブジェクトの名前ではなく、そのグローバルテーブルへのインデックスです。

この「複雑さ」(これは、照明値などの異なるシェーダー間でUBOを共有するための優れた機能です)は、ほとんどのOpenGLドライバーが間違っているようです。OpenGLドキュメンテーションの表現を公平にすることは、それが最も明白である可能性もあります。

私は他のドライバーのために普通のユニフォームを使用することに頼らざるを得ませんでした。

両方のスクリーンショットは、均一なバッファーオブジェクト、2つの異なるドライバーを使用しています。

均一なバッファのバグ


どのドライバーでテストしましたか?どのプラットフォーム?
akaltar 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.