OpenGL - 纹理使用 glDrawElements 映射不正确
OpenGL - texture are mapped incorrectly using glDrawElements
我正在创建一个 OBJ 解析器,它读取文件并使用 glDrawElements 绘制它。这里的问题是模型绘制正确,但是当我试图给它一个纹理时,它被错误地映射了。我已阅读 here that "OpenGL can only use one index buffer, whereas OBJ use one index buffer by attribute". I have also researched about the textures being incorrectly mapped when using glDrawElements and found out that I need to rearrange the textures because only vertices are shared but not the textures. Having said all of this, how should I suppose to rearrange the textures? Should I duplicate some textures? Please refer to this link 获得的样本输出。
我对OBJ不太熟悉,但是你说的是OBJ可以通过每个顶点的索引来引用不同的属性。你有一个大的 xyz 数组,另一个大的 uv 数组。然后每个顶点都有一个指向 xyz 数组的索引和另一个指向 uv 数组的索引。但是 opengl 每个顶点只有一个索引!所以如果 xyz 和 uv 索引不同,opengl 将无法工作。解决这个问题的一种简单方法是遍历所有顶点,如果它们的 uv 索引与 xyz 索引不同,只需将两者的数据复制到它们缓冲区的末尾并将索引设置为那个。
OBJ 格式指定了唯一的纹理坐标、顶点和面。
当然,Opengl 与 OBJ 无关,所以它想要的只是在正确位置的正确信息。
想象一下您的 OBJ 中有两个像这样的面(注意两个面中的顶点 1 纹理坐标)
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 通过您的索引缓冲区链接在一起,请注意 OBJ 和 OpenGL 中的顶点之间的差异。
有几种方法可以解决这个问题。我建议摆脱索引缓冲区,因为它只会使一切复杂化。如果没有索引缓冲区,您只需提供所有面,就好像它们是唯一的一样,并使用不同的绘制调用 (glDrawArrays)。您的顶点缓冲区将如下所示:
v1 |t1| v2 t2 v3 t3 v1 |t2| v4 t4 v5 t5
您复制了 v1,但实际上大多数时候它并没有那么多额外数据,因为您不必再指定索引缓冲区。
这种东西想起来真烦人,我尽量写得平易近人,希望没有出错。
我正在创建一个 OBJ 解析器,它读取文件并使用 glDrawElements 绘制它。这里的问题是模型绘制正确,但是当我试图给它一个纹理时,它被错误地映射了。我已阅读 here that "OpenGL can only use one index buffer, whereas OBJ use one index buffer by attribute". I have also researched about the textures being incorrectly mapped when using glDrawElements and found out that I need to rearrange the textures because only vertices are shared but not the textures. Having said all of this, how should I suppose to rearrange the textures? Should I duplicate some textures? Please refer to this link 获得的样本输出。
我对OBJ不太熟悉,但是你说的是OBJ可以通过每个顶点的索引来引用不同的属性。你有一个大的 xyz 数组,另一个大的 uv 数组。然后每个顶点都有一个指向 xyz 数组的索引和另一个指向 uv 数组的索引。但是 opengl 每个顶点只有一个索引!所以如果 xyz 和 uv 索引不同,opengl 将无法工作。解决这个问题的一种简单方法是遍历所有顶点,如果它们的 uv 索引与 xyz 索引不同,只需将两者的数据复制到它们缓冲区的末尾并将索引设置为那个。
OBJ 格式指定了唯一的纹理坐标、顶点和面。
当然,Opengl 与 OBJ 无关,所以它想要的只是在正确位置的正确信息。
想象一下您的 OBJ 中有两个像这样的面(注意两个面中的顶点 1 纹理坐标)
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 通过您的索引缓冲区链接在一起,请注意 OBJ 和 OpenGL 中的顶点之间的差异。
有几种方法可以解决这个问题。我建议摆脱索引缓冲区,因为它只会使一切复杂化。如果没有索引缓冲区,您只需提供所有面,就好像它们是唯一的一样,并使用不同的绘制调用 (glDrawArrays)。您的顶点缓冲区将如下所示:
v1 |t1| v2 t2 v3 t3 v1 |t2| v4 t4 v5 t5
您复制了 v1,但实际上大多数时候它并没有那么多额外数据,因为您不必再指定索引缓冲区。
这种东西想起来真烦人,我尽量写得平易近人,希望没有出错。