我想从一个vbo渲染多个3D立方体。每个立方体具有均匀的颜色。 这时,我创建了一个vbo,其中每个顶点都有一个颜色信息。
只为一个形状(垂直列表)上传一种颜色是否可行?
我还希望在同一着色器的GL_TRIANGLES
- 方法中混合使用GL_LINES
和glDrawElements
。它可以吗?
//编辑:我只有OpenGL 2.1。后来我想在Android上构建这个项目。
//编辑2: 我想渲染大量的立方体(高达150.000)。一个立方体有24个几何和颜色的顶点和34个索引。现在我的想法是创建一些vbo(可能是50)并将多维数据集分享给vbo。我希望这可以最大限度地减少开销。
答案 0 :(得分:4)
是的,如果你想绘制一堆立方体,你可以为每个立方体指定一次颜色。
创建一个包含一个立方体顶点的VBO。
// cube = 36 vertexes with glDrawArrays(GL_TRIANGLES)
vbo1 = [v1] [v2] [v3] ... [v36]
使用每个多维数据集的视图矩阵和颜色创建另一个VBO,并使用属性除数为1.(您可以使用相同的vbo,但我会使用单独的一个。)
vbo2 = [cube 1 mat, color] [cube 2 mat, color] ... [cube N mat, color]
致电glDrawElementsInstanced()
或glDrawArraysInstanced()
。这将一遍又一遍地绘制立方体。
或者,您可以对每个多维数据集使用glUniform()
,但这会限制您可以绘制的多维数据集的数量。上面的方法可以让你轻松绘制数千个。
GL_TRIANGLES
和GL_LINES
您必须为每种原语调用glDraw????()
一次。如果您愿意,可以同时使用相同的着色器。
答案 1 :(得分:1)
关于你的问题:
是否可以只为一种形状上传一种颜色?
是的,你可以使用统一而不是顶点属性(ofc这意味着更多地方的变化)。但是,您需要为每个形状设置制服,并为每个不同颜色的形状设置不同的drawcall。
是否可以在glDrawElements中混合使用GL_TRIANGLES和GL_LINES?
是和否。是的,但你需要一个新的drawcall(很明显)。你不能在同一个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
答案 2 :(得分:1)
使用OpenGL 2.1,我不认为每个多维数据集只能指定一次颜色的合理方式,并且仍然可以在一次绘制调用中绘制所有内容。
最直接的方法是,不是在VBO中使用color属性,而是在绘制调用之前直接指定它。假设您正在使用通用顶点属性,那么您目前拥有:
glEnableVertexAttribArray(colorLoc);
glVertexAttripPointer(colorLoc, ...);
你这样做:
glDisableVertexAttribArray(colorLoc);
glVertexAttrib3f(colorLoc, r, g, b);
只有先前为该位置启用了数组时才需要glDisableVertexAttribArray()
。
最大的缺点是你只能在一次绘制调用中绘制具有相同颜色的立方体。在极端情况下,每个立方体有一个绘图调用。当然,如果你有多个具有相同颜色的立方体,你仍然可以将它们分批到一个绘图调用中。
您想知道这是否比VBO中每个顶点的颜色更有效?总的来说不可能说。在这样的情况下,您总会得到相同的答案:尝试两者,并进行基准测试。我怀疑你会觉得它有益。根据我的经验,将顶点数据作为主要性能瓶颈的情况相当罕见。因此,删除一个属性可能不会给你带来太大的收益。另一方面,进行许多小的平局调用绝对会(通常会)损害性能。
您可以使用一种类似混合的选项。我不一定推荐它,只是为了集思广益。如果使用相当有限数量的颜色,则可以在VBO中使用单个标量属性来编码"颜色索引"。然后在顶点着色器中,您可以使用纹理查找来转换"颜色索引"到实际的颜色。
真正好的选择超出了OpenGL 2.1。 @DietrichEpp很好地解释了实例化渲染,这对于像这样的情况来说是一个优雅的解决方案。
不,你可以不在同一个绘图调用中有行和三角形。即使是在OpenGL 4.x中最灵活的绘制调用,如glDrawElementsIndirect()
,仍然只采用一种基本类型。