0

最新の OpenGL (3.x+) では、位置、色、法線、テクスチャ座標、およびインデックスなどの頂点属性を含むバッファー オブジェクトを作成します。

次に、これらのバッファーは、対応する頂点配列オブジェクト (VAO)に割り当てられます。VAO には、基本的にすべてのデータとデータの形式へのポインターが含まれています。

VAO の作成方法と使用方法については、多くのチュートリアルがあります。残念ながら、大規模なアプリケーションやゲームで VAO をどのように使用すべきかは明確ではありません。

たとえば、ゲームには多くの 3D モデルが含まれる場合があり、各モデルを異なる VAO で分離することが適切と思われます。

一方、パーティクル システムには、互いに独立して移動する多くの切断されたプリミティブが含まれています。このシナリオでは、システムごとに 1 つの VAO を使用すると、CPU-GPU 転送のパフォーマンスが向上する可能性があります。ただし、この場合、プリミティブは互いに異なる方法で変換する必要があるため、各パーティクルを非常に小さな VAO に分離することが実行可能に見えるかもしれません。

質問:

  • 大量の小さなデータ セット (クワッドのパーティクル システムなど) の場合、すべてのデータを 1 つの VAO にパックするか、多数の VAO に分割する必要がありますか? 各方法のパフォーマンスの利点/欠点は何ですか?

1 つの VAO が使用されると仮定すると、データの独立した各サブユニットを変換する唯一の明らかな方法は、実際の位置情報を変更して GPU に再ロードすることです。これを何度も行うと、時間パフォーマンスの点でコストがかかります。

多くの VAO が使用されていると仮定すると、GPU は各 VAO の重複したフォーマット情報を保存する必要があります。これはスペースの点でコストがかかるようです (ただし、これが必ずしも遅いかどうかはわかりません)。

補足:
はい、私は個人的に粒子システムの管理に興味があります。この質問をより一般的なものにし、他の人にとってより役立つようにするために、VAO 管理全体について質問しています。保存するデータの種類と、求められるパフォーマンスの種類 (時間/空間) を考えるとき、どのような管理方法が適切であるかを知りたいと思います。


VAO の作成については、こちらで詳しく説明しています。

4

2 に答える 2

2

パーティクルの場合は、インスタンス化されたレンダリングを使用するのが最適です。このレンダリングでは、すべてのパーティクルを 1 回の描画呼び出しでレンダリングできますが、それぞれに異なる位置を属性として割り当てることができます。glSubData を使用して既存のバッファを更新できます。そうすれば、フレーム間で CPU 側の位置を更新してから、バッファを更新できます。

より複雑な例では、必要な属性をインスタンス化できます。

インスタンス化されたレンダリングを呼び出して、コードで設定する方法は次のとおりです。

void CreateInstancedAttrib(unsigned int attribNum,GLuint VAO,GLuint& posVBO,int numInstances){
    glBindVertexArray(VAO);
    posVBO = CreateVertexArrayBuffer(0, sizeof(vec3),numInstances,GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(attribNum);
    glVertexAttribPointer(attribNum, 3, GL_FLOAT, GL_FALSE, sizeof(vec3), 0);
    glVertexAttribDivisor(attribNum, 1); 
    glBindVertexArray(0);
}

posVBO は通常の属性データで、次の行は位置のバッファを設定します。レンダリング時:

void RenderInstancedStaticMesh(const StaticMesh& mesh, MaterialUniforms& uniforms,const vec3* positions){

    for (unsigned int meshNum = 0; meshNum < mesh.m_numMeshes; meshNum++){

        if (mesh.m_meshData[meshNum]->m_hasTexture){
            glBindTexture(GL_TEXTURE_2D, mesh.m_meshData[meshNum]->m_texture);
        }

        glBindVertexArray(mesh.m_meshData[meshNum]->m_vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, mesh.m_meshData[meshNum]->m_instancedDataBuffer);
        glBufferSubData(GL_ARRAY_BUFFER,0, sizeof(vec3) * mesh.m_numInstances, positions);
        glUniform3fv(uniforms.diffuseUniform, 1, &mesh.m_meshData[meshNum]->m_material.diffuse[0]);
        glUniform3fv(uniforms.specularUniform, 1, &mesh.m_meshData[meshNum]->m_material.specular[0]);
        glUniform3fv(uniforms.ambientUniform, 1, &mesh.m_meshData[meshNum]->m_material.ambient[0]);
        glUniform1f(uniforms.shininessUniform, mesh.m_meshData[meshNum]->m_material.shininess);
        glDrawElementsInstanced(GL_TRIANGLES, mesh.m_meshData[meshNum]->m_numFaces * 3, 
                                GL_UNSIGNED_INT, 0,mesh.m_numInstances);
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

理解するのは大変ですが、重要な行は DrawElementsInstance と glBufferSubData です。両方の関数でいくつかのグーグルを実行すると、インスタンス化されたレンダリングがどのように機能するかを理解できるようになると確信しています。もう質問してください

于 2014-11-26T07:57:59.007 に答える
1

一般的なルールは、ドローコールの量を最小限に抑えることです。個々の VAO に何かを入れる場合、各 VAO に対してドローコールを実行する必要があります。また、VAO と VBO の切り替えにもコストがかかります。VAO と VBO を「モデル」コンテナーと考え​​ないでください。各 VBO / VAO を使用して、同一のプロパティのデータを結合する必要があるメモリ プールと考えてください。

パーティクル システムは、すべてを 1 つの VBO/VAO にまとめるのに最適な候補です。通常は、VBO に各パーティクルの配置場所に関する情報が含まれるインスタンス化されたレンダリングを使用します。

于 2014-11-26T09:14:53.263 に答える