OpenGL - 纹理映射不完整
Posted
技术标签:
【中文标题】OpenGL - 纹理映射不完整【英文标题】:OpenGL - texture mapping is incomplete 【发布时间】:2015-08-05 02:45:16 【问题描述】:我在 OpenGL 中对 OBJ 文件进行纹理处理时遇到了这个奇怪的问题。我已经成功地正确解析和渲染模型,我现在正在尝试对其应用纹理。这是我的做法。
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// bind the vertices coord
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, cc * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
// bind the textures coord
GLuint tcbuffer;
glGenBuffers(1, &tcbuffer);
glBindBuffer(GL_ARRAY_BUFFER, tcbuffer);
glBufferData(GL_ARRAY_BUFFER, tcc * sizeof(GLfloat), textures GL_STATIC_DRAW);
// for the texture itself
GLuint tid;
glGenTextures(1, &tid);
glBindTexture(GL_TEXTURE_2D, tid);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nptr);
glEnableVertexAttribArray(m_vert);
glBindBuffer(GL_ARRAY_BUFFER, vbufferid);
glVertexAttribPointer(m_vert, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(m_texcoord);
glBindBuffer(GL_ARRAY_BUFFER, tcbufferid);
glVertexAttribPointer(m_texcoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, vc);
对于解析器中的纹理坐标,我交换 y 坐标(从 1 中减去 y)以获得纹理的正确方向。此代码适用于不同的模型,但对于这个特定的模型,纹理是不完整的。您可以here 获得我使用此模型获得的输出,here 获得工作模型。希望你能帮忙! :)
P.S: 代码被缩短以供查看:)
【问题讨论】:
不确定这是否是您的直接问题,但glGenerateMipmap()
调用必须在glTexImage2D()
之后。否则它没有纹理数据来生成 mipmap。
@RetoKoradi 感谢您的指出。我尝试在 glTexImage2D 之后移动它,但它并没有解决问题。我注意到的是纹理本身只提供了模型的一半,看这里link 我在说什么:D 但是我应该做些什么来以某种方式复制纹理吗?据我所知,obj 会处理这个问题,因为它提供每个面的纹理坐标。
文件的纹理坐标是否超出 [0.0, 1.0] 范围?尝试将GL_REPEAT
用于纹理环绕模式。
@RetoKoradi - 我尝试使用 GL_REPEAT,现在它可以工作了!谢谢 :) 我只是想问一下 GL_REPEAT 是否总是可以在其他模型中使用?因为我的计划是为任何模型制作一个 OBJ 解析器,而不需要修改我尝试过的所有其他模型的代码。
@RetoKoradi - 我刚刚测试了其他模型,效果很好!谢谢老兄。
【参考方案1】:
根据建模程序生成纹理和纹理坐标的方式,它可能会生成超出标准 [0.0, 1.0] 范围的纹理坐标。由于您将换行模式设置为:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
所有超出此范围的纹理坐标都将获得最近边缘纹素的颜色。看起来你的纹理边缘有黑色,所以所有这些像素都将被采样为黑色。
如果是这个问题,需要设置参数为:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
从理论上讲,建模程序生成纹理坐标以处理镜像重复也是有可能的,尽管可能性较小。如果切换到GL_REPEAT
后,纹理图像出现在当前黑色的部分,但它们看起来像纹理的错误部分,您也可以尝试:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
OP 已经发现了一个相关问题,但我会在这里提到它,以防其他有类似问题的人遇到这个答案:在我看到的带有纹理的 OBJ 文件中,第二个纹理坐标(y
或 t
,如果您更喜欢该命名法)与 OpenGL 使用它们的方式相反(又名 y 反转)。我不确定这是否是 OBJ 中的标准,或者取决于生成文件的软件。典型的症状是纹理显示在几何体上,但纹理的完全错误部分被映射。这可以通过在读取文件时镜像第二个坐标(将y
替换为1.0 - y
)或通过在着色器中应用纹理坐标的相应映射来解决。
【讨论】:
以上是关于OpenGL - 纹理映射不完整的主要内容,如果未能解决你的问题,请参考以下文章