在一个 vbo 中绘制多个形状

Draw multiple shapes in one vbo

我想从一个 vbo 渲染多个 3D 立方体。每个立方体都有统一的颜色。 这时,我创建了一个vbo,其中每个顶点都有一个颜色信息。

是否可以为一种形状(顶点列表)只上传一种颜色?

我还想在同一着色器的 glDrawElements 方法中混合使用 GL_TRIANGLESGL_LINES。可能吗?

//编辑:我只有 OpenGL 2.1。稍后我想在 Android 上构建这个项目。

//编辑2: 我想渲染大量立方体(最多 150.000)。一个立方体有 24 个几何和颜色的顶点和 34 个索引。现在我的想法是创建一些 vbo(也许 50 个)并将多维数据集共享给 vbo。我希望这可以最大限度地减少开销。

关于您的问题:

是否可以为一种形状只上传一种颜色?

是的,你可以使用一个统一的而不是一个顶点属性(当然这意味着更多地方的变化)。但是,您需要为每个形状设置制服,并为每个不同颜色的形状设置不同的绘制调用。

是否可以在 glDrawElements 中混合使用 GL_TRIANGLES 和 GL_LINES?

是也不是。是的,但您将需要一个新的绘图调用(这是显而易见的)。你不能在同一个 drawcall 上做一些形状 GL_TRIANGLES 和一些形状 GL_LINES.

在伪代码中,这将如下所示:

draw shapes 1,2,10 from the vbo using color red and GL_TRIANGLES
draw shapes 3,4,6 from the vbo using color blue and GL_LINES
draw shapes 7,8,9 from the vb using color blue and GL_TRIANGLES

画很多立方体

是的,如果你想画一堆立方体,你可以为每个立方体指定一次颜色。

  1. 创建一个包含一个立方体顶点的 VBO。

    // cube = 36 vertexes with glDrawArrays(GL_TRIANGLES)
    vbo1 = [v1] [v2] [v3] ... [v36]
    
  2. 为每个立方体创建另一个具有视图矩阵和颜色的 VBO,并使用 1 的属性除数。(您可以使用相同的 vbo,但我会使用单独的。)

    vbo2 = [cube 1 mat, color] [cube 2 mat, color] ... [cube N mat, color]
    
  3. 呼叫glDrawElementsInstanced()glDrawArraysInstanced()。这将一遍又一遍地绘制立方体。

或者,您可以对每个立方体使用 glUniform(),但这会限制您可以绘制的立方体数量。以上方法,让你轻松画出万千

混合 GL_TRIANGLESGL_LINES

您必须为每种类型的基元调用一次 glDraw????()。如果愿意,您可以两次使用相同的着色器。

对于 OpenGL 2.1,我认为没有一种合理的方法可以让每个立方体只指定一次颜色,并且仍然在一次绘制调用中绘制所有内容。

最直接的方法是,不要在 VBO 中使用颜色属性,而是在绘制调用之前直接指定它。假设您正在使用通用顶点属性,您当前将拥有:

glEnableVertexAttribArray(colorLoc);
glVertexAttripPointer(colorLoc, ...);

你这样做:

glDisableVertexAttribArray(colorLoc);
glVertexAttrib3f(colorLoc, r, g, b);

其中 glDisableVertexAttribArray() 仅在先前为该位置启用阵列时才需要。

最大的缺点是您只能在一次绘制调用中绘制具有相同颜色的立方体。在极端情况下,每个立方体一个绘制调用。当然,如果您有多个颜色相同的立方体,您仍然可以将它们批处理到一个绘制调用中。

您想知道这是否比为 VBO 中的每个顶点设置颜色更有效?不能笼统地说。在这种情况下,您总是会得到相同的答案:尝试两者,然后进行基准测试。我怀疑你会发现它有益。根据我的经验,获取顶点数据很少会成为主要的性能瓶颈。因此,删除一个属性可能不会给你带来太大的好处。另一方面,进行许多小的绘图调用绝对会(而且经常会)损害性能。

您可以使用一个混合选项。我不一定推荐它,只是为了集思广益。如果您使用的颜色数量相当有限,则可以在编码 "color index" 的 VBO 中使用单个标量属性。然后在顶点着色器中,您可以使用纹理查找将 "color index" 转换为实际颜色。

真正好的选择超出了 OpenGL 2.1。 @DietrichEpp 很好地解释了实例化渲染,对于这种情况,这是一个优雅的解决方案。

不,您可以在同一个绘图调用中有直线和三角形。即使是 OpenGL 4.x 中最灵活的绘制调用,如 glDrawElementsIndirect(),仍然只采用一种基元类型。