【问题标题】:OpenGL binding many textures while drawing the one meshOpenGL在绘制一个网格时绑定许多纹理
【发布时间】:2015-05-26 13:50:49
【问题描述】:

我想在一个网格上绑定例如 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);

【问题讨论】:

    标签: c++ opengl vertex-buffer multitexturing


    【解决方案1】:

    绑定许多(100 个)纹理

    我不确定一次绑定那么多单独的纹理的方法。有bindless textures,但我对该扩展没有太多经验。如果您的许多纹理大小相同,您也可以使用array texture。但是解决这个问题的标准方法是使用纹理图集,将大量纹理打包到一个图集中,记录它们的放置位置并调整纹理坐标以匹配。

    更新:您还可以使用许多纹理数组来存储纹理图集(请参阅 cmets 和 @Ethan's answer)。


    将多个纹理应用于网格

    我将如何告诉 VBO,哪些面孔将具有哪些纹理?

    我认为更直接的问题是如何将不同的纹理(或材质)应用到同一个网格。有几点需要考虑...

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

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

    3. 每个面都有完全独立的材质/纹理。通常,网格上只有几种材料。您渲染它的方式是在单独的批次中,按材质分组。绑定正确的纹理,设置shader uniform,绘制三角形索引A到B。

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

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

    【讨论】:

    • 纹理大小不一样,如果我必须使用纹理图集,那将是非常大的纹理。
    • @ProXicT 您可能需要创建许多纹理图集。阵列纹理也可以用于此。
    • 好吧,我不知道我该怎么做。我将如何告诉 VBO,哪些面孔将具有哪些纹理?
    • 非常感谢!我想我在阅读了你的回答和@Ethan 的回答后明白了。
    【解决方案2】:

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

    【讨论】:

    • 我没有那么多纹理,我想实现可以与我正在加载的任何网格一起使用的纹理加载器。我想我明白了,谢谢:)
    • 你需要同时渲染它们还是高频交换它们?如果没有,就像纹理查看器一样,您可以一次绑定一个,然后在需要绘制不同的纹理时重新绑定。
    • 假设我有一个非常大的网格,分配了许多纹理,并且我存储在 VBO 中的网格。我目前的方法是根据网格有多少纹理将网格分成一定数量的 VBO。因此,例如,如果我在一个网格上有 64 个纹理,我会将其拆分为 2 个较小的网格,每个网格有 32 个纹理,每个网格都有自己的 VBO(在这种情况下为 2 个)。
    • 根据 NVIDIA 的说法,每个 VBO 至少应该有 4MB 的数据才能提供最佳效率。
    • 你能指出说 4Mb 是最佳 VBO 大小的文件吗?这对于一个 VBO 来说似乎很大。如果需要纹理切换,则不需要将网格分成 2 个。只需使用绘制范围并使用第一组纹理绘制所有三角形,然后切换并绘制另一组三角形。或者在切换纹理后重绘整个网格。但这相当低效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多