尤其是在渲染粒子效果时,需要对同一对象进行几次渲染,并对其属性进行一些修改。但是,这些更改通常仅限于姿势或纹理之类的属性,而不是对象本身的几何形状。

不同的姿势(平移,旋转)只是与顶点的矩阵相乘,而具有已应用的纹理图集的不同纹理只是不同的纹理坐标。

的粒子需要绘制,我目前通过为每个粒子调用glDrawElements来实现,同时适当地设置均匀。到目前为止,这足以实时渲染场景,但是对于更复杂的场景或仅对于粒子系统发出的更多粒子而言,这很容易导致帧速率下降。

因此,一种减少非常相似对象的绘制调用次数的方法?

评论

我知道OpenGL中有Instancing,这就是为什么我也在这里发布答案。但是也许还有其他方法可以达到相同的结果。

似乎您是对的... :)

#1 楼

有很多很多方法可以在OpenGL中进行绘制,因此有时自然会造成混淆。您所描述的第一种方法是设置着色器参数并为每个对象发出一个绘画调用,通常效率最高,因为API开销很大。第二种方法是使用实​​例化绘图,对于具有相同参数的对象,它是一种更为智能的方法。

特别是对于粒子,我知道并测试了另外两种方法:


第一个较为传统且易于实现的方法是为应用程序代码中的每个粒子生成唯一的四边形。然后,使用OpenGL的几个优化的缓冲区流路径之一上载此数据并发出一个画图调用。这是最简单的方法,可提供良好的结果。如果可以映射顶点/索引缓冲区(glMapBuffer/MapBufferRange),它将涉及很少的API调用。
另一种方法是使用“变换反馈”将整个对象移至着色器程序。这种方法的启动和运行有点复杂,但是您可以在该主题上找到很多参考资料,例如本教程。这是一条最佳路径,因为它将整个模拟移至GPU。

这些是渲染粒子效果的一些优化方法。但是OpenGL提供了其他几种适用于不同情况的渲染路径,其中一种是间接绘图,目前尚无法在ES上使用,但可能是现代PC OpenGL中最快的绘图路径之一。变换反馈还需要一个几何着色器,因此它不适用于当前的OpenGL-ES。

有关OpenGL优化渲染路径的更多信息,我建议观看NVidia的演示文稿:接近零驱动程序在OpenGL中的开销。在演讲结束时,他们展示了几种方法的非常有趣的基准,以及它们如何与Direct3D等效方法进行比较。

#2 楼

在OpenGL ES中,提供了实例化,该实例允许多次渲染一个对象。

使用Instancing时,您可以使用统一数组来提供不同的信息,例如每个粒子的转换矩阵。然后,在着色器中,可以使用gl_InstanceID区分各个粒子并从均匀阵列中选择适当的索引。

attribute vec4 position;
uniform mat4 transformations[16];
// other attributes, uniforms, etc
void main() {
    // ...
    gl_Position = ... * transformations[gl_InstanceID] * position;
}


您需要使用glDrawElementsInstanced绘制对象注意:在OpenGL ES 2中,您需要使用glDrawElementsgl_InstanceIDEXT,因为它是那里的扩展名。该参数将对象数作为附加参数(与glDrawElementsInstancedEXT相比)。另外,您还必须使用

#extension GL_EXT_draw_instanced : enable

在着色器中启用它