0

编辑 - 为了帮助澄清最上面的问题.. 我想我正在寻找哪种排序会表现更好:按程序排序或按纹理排序?有关系吗?我所有的对象都在相似的 z 空间中,并且都存储在同一个 VBO 中。如果我不通过 glUseProgram 切换着色器,我是否必须为每个对象重新设置属性?

原帖:

这是一个两部分的问题。我试图弄清楚在绘制之前如何最好地对我的 3d 对象进行排序,以及每个 glDrawElements 必须执行哪些打开的 gl 调用,以及每次屏幕刷新(甚至一次)可以完成哪些调用。目的当然是为了速度。对于我的游戏,让我们假设从前到后的 z 不是什么大问题(大多数对象都在同一个 z 上)。因此,除了最后对所有具有透明度的对象进行排序外,我不会对 z 进行排序。

当然,我不希望排序过程花费比渲染未排序更长的时间。

第 2 部分是每个 glDrawElements 必须使用哪些 open gl 调用,哪些只能在信息更改时执行?presentRenderbuffer 是否会清除某些内容,以便您必须重新调用它们。

大多数 opengl 2 演示都会对每个对象进行每次调用。实际上大多数演示只绘制一个对象。所以在 3d 引擎中(就像我正在写的那样)我想避免不必要的冗余调用。

这是我做的顺序(未排序,未优化):

glUseProgram(glPrograms[useProgram]);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);

Loop through objects {

   Do all matrix calcs

   Set Uniforms (matrix, camera pos, light pos, light colors, material properties)

   Activate Textures.. (x2)
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, texture0);
   glUniform1i(glUniforms[useProgram][U_textureSampler], 0);

   Bind VBOs
   glBindBuffer(GL_ARRAY_BUFFER, modelVertVBO);
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelIndVBO);

   Set Attributes (vertexpos, texcoord, norm, tan, bitan)

   glDrawElements(GL_TRIANGLES, models[modelToUse].indSize, GL_UNSIGNED_INT, (void *) (models[modelToUse].indOffset * sizeof(GLuint)));
}

当然,这只在所有对象使用相同的着色器/程序时才有效。在实践中他们不会。

3D 对象位于一个数组中,其中包含每个对象的所有属性:模型 ID、着色器 ID、纹理 ID、位置等。所以我的想法是进行快速简单的排序,以将类似对象的索引号堆叠在其他数组中。然后在每个数组中绘制项目。我可以按 3d 模型(对象类型)、纹理或着色器排序。许多模型共享相同的纹理。许多模型共享相同的着色器。此时我有 3 个着色器。所有对象共享一个 VBO。

我可以这样做吗?

Bind the VBO - since all objects use the same one
Loop through object types {
   If shader hasn't changed
      glUseProgram
      Set Attributes
   If texture hasn't changed
      glActiveTexture(s) - based on which program is active
   Loop through objects of that type {
      Do matrix calcs
      Set Uniforms - based on which program is active
      glDrawElements
   }
}

编辑 - 要清楚 - 我仍在绘制所有对象,只是以不同的顺序组合着色器和/或纹理的使用,以避免绑定,然后在游戏的一个“帧”内再次重新绑定。

我目前在第二次刷新时遇到 glDrawElements 崩溃,但我认为这很容易找到。我只包括这个事实,因为它让我认为绑定纹理可能不会延续到第二帧(或 presentBuffers)。

避免更改着色器或更改纹理会更快吗?属性、vbo 和纹理是否会在多个 glDrawElement 调用中保持活动状态?跨多个presentBuffers?

4

1 回答 1

0

回答我自己的问题。

首先是一些背景。我目前有 3 个着色器,预计最终不会超过 4 或 5 个。示例我有一个使用基础纹理和法线纹理的凹凸贴图着色器。我还有一个着色器,它不使用基础纹理,而是为对象使用纯色,但仍然具有正常纹理。然后我有相反的,一个仅使用基础纹理的平面照明简单着色器。

我有许多不同的 3d 模型,但都使用相同的 VBO。一些 3d 模型使用与其他模型相同的纹理。

因此,在 3d 对象的定义中,我添加了一个 renderSort 属性,我可以预先知道它使用什么着色器程序以及它需要什么纹理。

然后当我更新对象并确定它们是否需要在屏幕上绘制时,我还根据它们的 3d 对象类型的 renderSort 属性对它们进行一次简单排序......我只是将对象的数组索引扔到一个“桶”数组。我没有看到超过 10 个这样的存储桶。

更新和快速排序后我渲染。

渲染遍历桶,并在桶内遍历每个桶中的对象。在内部循环中,我检查程序自上一个对象以来是否发生了变化,如果发生了变化,则执行 glUseProgram。与纹理相同。我仅在当前未绑定时绑定它们。然后更新所有其他制服并执行 glDrawElements。

以前的方式..未排序..如果有 1000 个对象,它将调用 glUseProgram,绑定纹理,绑定 vbo,设置所有属性.. 1000 次。

现在..它只在需要时改变这些东西..如果它需要 1000 次它仍然会做 1000 次。但是对于桶排序,每个桶只需要执行一次。这样,即使它们没有正确排序,我也会优先正确地绘制。

这是代码:

排序...

if (drawThisOne) {
        // if an object needs to be drawn - toss it in a sort bucket.
        // each itemType has a predetermined bucket number so that objects will be grouped into rough program and texture groups
        int itemTypeID = allObjects[objectIndex].itemType;
        int bucket = itemTypes[itemTypeID].renderSort;

        sorted3dObjects[bucket][sorted3Counts[bucket]]=objectIndex;
        // increment the count for that bucket
        sorted3Counts[bucket]++;
}

正在渲染...

// only do these once per cycle as all objects are in the same VBO
glBindBuffer(GL_ARRAY_BUFFER, modelVertVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelIndVBO);

for (int bucket=0; bucket<10; bucket++) {
    // does this bucket have anything in it?
    if (sorted3Counts[bucket]>0) {
        // if so itterate though items in that bucket
        for (int thisObject=0; thisObject < sorted3Counts[bucket]; thisObject++) {
            // get the object index for this object in this bucket
            int objectIndex = sorted3dObjects[bucket][thisObject];
            int itemTypeID = candyPieces[objectIndex].pieceType;

            int modelToUse = itemTypes[itemTypeID].model;

            // switching to psudocode...

            GLuint useProgram = itemTypes[itemTypeID].shader;
            if (Program Changed or is not set) {
                glUseProgram(glPrograms[useProgram]);
                glDisable(GL_BLEND);
                glEnable(GL_CULL_FACE);
                currentProgram=useProgram;

                USE glVertexAttribPointer to set all attributes
            }

            // based on which program is active set textures and program specific uniforms
            switch (useProgram) { ....
                if (Texture Changed or is not set) {
                     glActiveTexture(s)
                }
            }

            Matrix Calculations
            glUniform - to set unforms

            glDrawElements(GL_TRIANGLES, models[modelToUse].indSize, GL_UNSIGNED_INT, (void *) (models[modelToUse].indOffset * sizeof(GLuint)));
          }}}
于 2013-04-26T10:41:00.193 回答