OpenGL - 使用 glDrawElements 错误地映射纹理

Posted

技术标签:

【中文标题】OpenGL - 使用 glDrawElements 错误地映射纹理【英文标题】:OpenGL - texture are mapped incorrectly using glDrawElements 【发布时间】:2015-07-27 09:37:51 【问题描述】:

我正在创建一个 OBJ 解析器,它读取文件并使用 glDrawElements 绘制它。这里的问题是模型被正确绘制但是当我尝试给它一个纹理时,它被错误地映射。我读过here,“OpenGL 只能使用一个索引缓冲区,而 OBJ 按属性使用一个索引缓冲区”。我还研究了使用 glDrawElements 时纹理被错误映射的问题,发现我需要重新排列纹理,因为只共享顶点而不共享纹理。说了这么多,我应该如何重新排列纹理?我应该复制一些纹理吗?请参考这个link 我得到的示例输出。

【问题讨论】:

【参考方案1】:

OBJ 格式指定唯一的纹理坐标、顶点和面。

当然,Opengl 与 OBJ 无关,所以它只需要正确位置的正确信息。

在你的 OBJ 中想象两个这样的面(注意两个面上的顶点 1 texcoords)

f:    v1 |t1|     v2 t2      v3 t3 
f:    v1 |t2|     v4 t4      v5 t5 

您的 INDEX 缓冲区如下所示:

1 2 3     1 4 5

你的 opengl VERTEX 缓冲区首先看起来像这样:

v1 v2 v3 v4 v5

如果你添加纹理坐标,你在哪里添加它们?像这样?

v1 t1     v2 t2     v3 t3     v4 t4      v5 t5

这可能是你现在所拥有的,它是错误的,因为 opengl 使面孔像这样:

f:    v1 |t1|      v2 t2      v3 t3 
f:    v1 |t1|      v4 t4      v5 t5 

因为 v1 和 t1 是通过 indexbuffer 链接在一起的,所以请注意 OBJ 和 OpenGL 中的顶点之间的区别。

有几种方法可以解决这个问题。我建议摆脱索引缓冲区,因为它只会使一切复杂化。如果没有索引缓冲区,您只需提供所有面,就好像它们是唯一的一样,并使用不同的绘制调用 (glDrawArrays)。您的顶点缓冲区将如下所示:

v1 |t1|      v2 t2       v3 t3       v1 |t2|       v4 t4        v5 t5

您复制了 v1,但实际上大多数时候它并没有那么多额外数据,因为您不必再​​指定索引缓冲区。

这种东西想起来真的很烦,我尽力让它平易近人,希望我没有犯任何错误。

【讨论】:

感谢您的回复,抱歉回复晚了。这对我真的很有帮助,现在很清楚了。使用索引缓冲区是因为我打算使用 GL_TRIANGLE_STRIP 而我无法让它在 glDrawArrays 中工作。【参考方案2】:

我对OBJ不太熟悉,但是你说的是OBJ可以通过每个顶点的索引来引用不同的属性。你有一个大数组 xyz,另一个大数组 uv。然后每个顶点都有一个指向 xyz 数组的索引和另一个指向 uv 数组的索引。但是opengl每个顶点只有一个索引!因此,如果 xyz 和 uv 索引不同,opengl 将无法工作。解决此问题的一种简单方法是遍历所有顶点,如果它们的 uv 索引与 xyz 索引不同,只需将两者的数据复制到其缓冲区的末尾并将索引设置为那个。

【讨论】:

我会记住这一点,因为我真的想让它与 glDrawElements 一起工作。我只是好奇,我真的应该将两者都复制到缓冲区的末尾还是只是纹理?

以上是关于OpenGL - 使用 glDrawElements 错误地映射纹理的主要内容,如果未能解决你的问题,请参考以下文章

无法让 openGL 的 glDrawElements 与几何着色器一起使用

OpenGL ES - glDrawElements - 无法理解索引

glDrawElement 的 OpenGL 渲染问题

OpenGL glDrawElements 没有颜色

OpenGL glDrawElements

OpenGL - glDrawElements vs 顶点数组对象