在OpenGL ES中渲染Obj组

时间:2012-06-26 22:17:07

标签: opengl-es vbo

我是OpenGL ES的新手,我正在编写一个iPad应用程序,需要我加载Wavefront Obj文件,在OpenGL中绘制它们。我的问题是关于渲染Obj文件组的最有效方法。

关于我所拥有的一些背景知识。 Obj模型的所有解析/加载都在工作(我使用GLM来加载文件),所以繁琐的东西就不用了。对于基础项目,我已经在XCode中扩展了OpenGL ES游戏模板,并删除了着色器中的所有调用。我正在使用GLKit的BaseEffect作为着色器,并使用VAO和VBO加载我的所有顶点数据。对于具有16组的模型,在初始时我将每个组分成VAO,每个VAO具有用于顶点数据和法线(交错)的VBO,以及用于纹理坐标的第二VBO。每个组都有一个材质(有时候是纹理,但为了问题,只假设材料)。

在我的渲染例程(下面的伪代码)中,我循环遍历为每个组创建的所有VAO,将组的材质应用于BaseEffect,然后使用DrawArrays绘制它(不使用DrawElements,因为我已经将VBO设置为up,因此数据已经按索引顺序排列,尽管它可能没有图形存储器那么高效。这是有效的,我能够用不同的材料绘制每个模型,但随着组数量的增加,我的帧率下降,因为我必须花更多的时间在渲染函数中循环遍历每个组。对于低模型计数,这很好,但是当我在应用程序中添加更多模型时,帧速率远低于30fps,这是我的基线。

for (groups in model)
{
    Bind VAO for this group

    Apply Material or Texture (if one exists) for this group using GLKBaseEffect

    Call PrepareToDraw for GLKBaseEffect

    DrawArrays passing it the vertex count for this group

    glBindVertexArray(0)   
}

显而易见的答案是简化模型以便减少组,但我很好奇渲染例程是否有任何改进可以让我做同样的事情,但更少的Draw调用。我想仍然有一个详细的obj文件,但我也可以使用最有效的渲染。

这是绘制obj文件的最佳方法,我必须为文件中的每个组使用多个材质/纹理,或者有没有办法可以在不循环遍历每个组并单独绘制它们的情况下完成此操作?我希望能够让每个obj模型只有一次调用DrawArrays / DrawElements,但我不知道如何做到这一点并仍然将多个材质/纹理应用于对象。我一直在看这个代码并且想“必须有一个更好的方法”,但是我不确定那是什么。如果我错过了一个明显的谜题,或者如果你有任何建议可以提供优化,我将永远感激。

1 个答案:

答案 0 :(得分:3)

我认为你几乎有了正确的想法。您实际上只能有一组纹理,或者一次有一个着色器,因此您必须绘制使用该状态的模型部分,切换状态并绘制下一组。

如果在添加更多模型时性能下降,可以尝试对组进行排序,以便在不切换的情况下连续绘制具有相同状态的所有组。

因此,如果您正在绘制100个模型副本,并且模型有三个组A,B和C:那么不要这样做:

foreach(model)
   set state A;
   glDrawArrays(A);
   set state B;
   glDrawArrays(B);
   set state C;
   glDrawArrays(C);

你应该这样做:

sort models into groups;
foreach(group)
    set state
    foreach(instance of group)
         glDrawArrays

这可以节省大约99%的状态转换(着色器切换,纹理绑定等)。这将是一个很大的改进。