OpenGL 在绘制一个网格时绑定多个纹理

OpenGL binding many textures while drawing the one mesh

我想在一个网格上绑定例如 80 个纹理并将其放入我的 VBO 中。 我怎样才能做到这一点?

我读过 glActiveTexture 能够做到这一点,但它最多允许大约 32 个纹理(取决于 GPU)。

我的 VBO 代码:

//Generating VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());

glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

//Drawing VBO:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

glVertexPointer(3, GL_DOUBLE, 0, 0);
glTexCoordPointer(2, GL_DOUBLE, 0, (void*)(vertices.size()*sizeof(Vector3d)));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

绑定许多(数百个)纹理

我不确定有什么方法可以同时绑定那么多单独的纹理。如果您的许多纹理大小相同,则有 bindless textures but I don't have much experience with that extension. You could also use an array texture。但解决这个问题的标准方法是使用 纹理图集 ,将大量纹理打包到一个中,记录它们的放置位置并调整纹理坐标以匹配。

更新:您还可以使用许多纹理数组来存储纹理图集(参见评论和 )。


将多个纹理应用于网格

How will I tell the VBO, what faces will have which texture?

我认为一个更紧迫的问题是如何将不同的纹理(或 materials)应用到同一个网格。有几件事需要考虑...

  1. 应用多个纹理的最常见情况是每个存储不同的 material 属性,但它们都使用相同的纹理坐标/“UV”。例如。漫反射贴图、法线贴图、高光贴图。我想在极端情况下,当你有 100 个不同的属性时,你需要一个数组纹理。

  2. 如果每个纹理需要以不同方式映射,则每个纹理都有一个单独的每个顶点纹理坐标 VBO。然后您必须决定纹理在应用时如何相互作用或混合。

  3. 你的每张脸 materials/texture 完全分开。通常网格上只有几个 material。您呈现它的方式是在单独的批次中,按 material 分组。绑定正确的纹理,设置着色器制服,绘制三角形索引 A 到 B.

  4. 如果几乎每一张脸都有不同的material。我想如果你正在绘制一个包含许多不同方块的基于方块的游戏,可能就是这种情况。 这里的问题是绘制调用的数量成为瓶颈, 所以你必须将不同的 material 组合到同一个绘图调用中。 您可以通过在顶点属性上存储 material 来做到这一点,例如添加顶点颜色 VBO。 不仅仅是颜色,您还可以存储每个顶点的纹理 ID,如果您使用的是纹理图集,则可以在图集中找到纹理的区域。 这开始变得低效,因为您将在三角形的每个顶点上多次存储相同的 material 数据。 为了最小化开销,您可以 为每个顶点存储一个 material 索引 ,它指向在 table 某处定义的 material(或者在小的统一数组,或者如果你需要更多 materials,另一个纹理)。 然后在table.

    中的material添加纹理ID和图集区域

    希望最后一点能回答您的问题。

老实说,如果一个网格有超过 32 个纹理,那么您遇到的问题可能比绑定问题大得多。但是如果你坚持要有那么多纹理,你有两个选择:无绑定或纹理数组。但是,也有缺点: Bindless 会限制您的硬件支持。纹理数组确实要求纹理具有相同的大小和格式。我个人认为 Texture Array 是一个可行的解决方案。如果可能,您可以尝试调整纹理的大小,然后将具有相同大小和格式的纹理分组到一个数组中。现在,您有 32 个数组可以使用,这应该绰绰有余,例如一个数组用于所有反照率纹理,一个用于所有法线贴图等。关于调整大小,考虑将纹理缩放到您拥有的最大尺寸,或者可能分成几类,例如小号中号大号。避免任意大小。