从OpenGL中的单个VBO渲染任意大小的实例

时间:2012-06-21 15:44:25

标签: java opengl gpu lwjgl vbo

考虑填充多个对象的单个VBO(或可能是多个VBO),每个对象具有任意顶点计数。出于演示目的,假设有一个苹果,有500个顶点和一个橙色,在VBO中存储了650个顶点。

通常如果我想绘制橙色,我只需调用glDrawRangeElements并指示我想绘制元素500-1150。如果我想在空间的特定位置绘制橙色,我会使用模型转换。

但是,如果我想绘制可能数千个物体呢?如果VBO包含几个对象作为一种“对象库”,那么该怎么办呢?我不想使用立即模式将我想要绘制的内容传输到我的GPU(即,为每个对象手动调用 glDrawRangeElements )。这会在与GPU通信时增加大量昂贵的开销。

我正在寻找的是一次性使用OpenGL上传某种数组的方法。这个数组将包含我想要绘制的每个对象的某种标识符,并且可能包含每个对象的转换(位置,旋转)。因此,如果我想在任意位置绘制不同水果的海洋,我只需计算一次索引并上传它。阵列可以是交错的。例如,数组可能如下所示:[object id 1 ],[position 1 ],[rotation 1 ] ... [对象id n ]。

2 个答案:

答案 0 :(得分:3)

最终,你正在尝试做的事情(绘制许多完全不同的对象)并不适用于“实例化”。

实例化适用于相同的对象。也就是说,在不同位置绘制的重复对象。你正在做的只是绘制很多不同的对象。为此,您将不得不发出多个绘制调用。没有避免这种情况。

您可以做的最好的事情是最小化状态变化。使用相同的着色器渲染对象。使用纹理图集,可能在数组纹理中,这样您就不必更改对象之间的纹理。 使用glVertexAttribPointer(超过初始设置)或更改元素缓冲区。

最后一部分的关键是glDrawElementsBaseVertex。只要缓冲区对象中的所有对象使用相同的顶点格式,就可以将它们全部放在与巨型数组相同的缓冲区中。然后使用索引列表将它们分开。基本顶点部分允许您保持索引相对较小。

最终,您想要的是更改对象之间对象的模型空间位置。你有很多选择来处理它。

最简单的方法就是正常使用glUniform来更改每个对象的模型到相机矩阵。你现在应该知道如何做到这一点。

稍微复杂的是use a uniform buffer来存储您想要绘制的所有对象的所有模型到相机矩阵。在对象之间,使用glBindBufferRange绑定该对象的特定矩阵。没有关于这是否比前一种方法更快或更慢的信息。请注意,实现具有implementation-dependent alignment for ranges of uniform buffers

现在技术上,GL 4.x硬件允许您在表示渲染命令的缓冲区对象中创建一些数据,然后使用它进行渲染。这是4.0的核心,是called indirect rendering。一般的想法是,OpenCL或一些专门的GL着色器进程会将数据写入缓冲区对象,而客户端代码只需说“渲染他所说的”,而不是必须回读数据并手动发出glDrawElements电话。

这对你没有帮助,因为每个电话都必须单独发出。即使使用AMD's multi-indirect-drawing functionality,它仍然无法帮助您,因为您希望为每个对象提供不同的变换。多画面不允许对象之间进行不同的变换。

答案 1 :(得分:1)

听起来像你想要instancing

Look加入ARB_instanced_arrays / ARB_draw_instanced

Here's a comparison of various techniques

如果您使用的是固定功能pipline,那么您就是SOL :(