传递给片段着色器的纹理坐标全部为 0

Posted

技术标签:

【中文标题】传递给片段着色器的纹理坐标全部为 0【英文标题】:Texture coordinates passed to fragment shader are all 0 【发布时间】:2013-08-06 14:13:17 【问题描述】:

我已经为我正在开发的一个小型 openGL 2.0 应用程序编写了自己的顶点和片段着色器。 一切似乎都很好,除了一件事,每个顶点的纹理坐标似乎是 (0, 0)。

当我不使用自己的着色器时,即当我使用openGL的默认着色器时,那么一切都被绘制出来了 很好

当我激活我自己的着色器时,形状仍然可以,顶点位置是正确的。但是纹理坐标都变成了(0, 0)。

这是顶点着色器的代码:

in vec2 position;
in vec2 texcoord;

out vec2 coord;

void main(void) 
    gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 0, 1);
    coord = vec2(gl_TextureMatrix[0] * vec4(texcoord, 1, 1));

这是片段着色器:

uniform sampler2D texture;

uniform float redFactor;
uniform float greenFactor;
uniform float blueFactor;

in vec2 coord;
void main(void) 
    vec4 color = texture2D(texture, coord);
    float grey = (color.r * redFactor + color.g * greenFactor + color.b * blueFactor);
    gl_FragColor = vec4(grey, grey, grey, color.a);

同样,它可以正常工作没有我自己的着色器。所以 VBO 的设置是正确的。

顺便说一句,texcoords 正确地从顶点着色器传递到片段着色器。 例如,当我更改行时

coord = vec2(gl_TextureMatrix[0] * vec4(texcoord, 1, 1));  

在顶点着色器中这样做:

coord = vec2(0.5, 0.5);  

我得到了正确的结果。

这是我的 VBO 内容的样子: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0]

这是绘图的 IBO:

[0, 1, 2, 2, 3, 0]

这里是指针:

VERTEX_ARRAY_POINTER(size = 2, stride = 16, offset = 0),   
TEXCOORD_ARRAY_POINTER(size = 2, stride = 16, offset = 8)  

编辑:顺便问一下,这个编辑器的换行有什么问题?

【问题讨论】:

换行符用两个空格完成,如果你是这个意思的话。 您的#version 指令在哪里? in/out110 中无效。着色器编译/链接日志中有任何内容吗? 【参考方案1】:

听起来你需要为纹理坐标启用客户端状态,所以一定要调用glEnableVertexAttribArray​来获取位置和纹理坐标

更多详情:http://www.opengl.org/wiki/Vertex_Specification#Vertex_Array_Object

但那是如果你使用的是顶点数组,从你的问题来看,你似乎是。

就我个人而言,我在调用 glDraw*() 之前启用了我正在使用的所有数组,然后在绘制调用之后禁用除位置数组之外的所有数组。

要知道用于glEnableVertexAttribArray 的索引,您可以使用0 作为您的职位,使用1 作为您的texcoords。

一个更可靠的答案是,在您编译并链接您的程序后,使用glUseProgram() 使其成为最新版本,然后

GLuint positionIndex = 0; GLuint texcoordIndex = 1; glUseProgram(programId); glBindAttribLocation(programId, positionIndex, "位置"); glBindAttribLocation(programId, texcoordIndex, "texcoord");

然后在你的glDraw*() 之前

glEnableVertexAttribArray(positionIndex); glEnableVertexAttribArray(texcoordIndex);

这仍然是一种相当硬编码的处理方式,如果您想要更通用的方法,请发表评论。

由于这里被要求,这是一种了解着色器正在使用多少顶点属性的通用方法

glUseProgram(programId);

int attribCount;
glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &attribCount);

GLuint attribLoc[] = new GLuint[attribCount];

for (int attrib=0; attrib<attribCount; ++attrib) 
    char szName[32];
    int size;
    GLenum vecType;
    glGetActiveAttrib(programId, attrib, sizeof(szName), 0, &size, &vecType, szName);

    attribLoc[attrib] = glGetAttribLocation(programId, szName);
    glBindAttribLocation(programId, attribLoc[attrib], szName);        

然后当你去画画

for (int attrib=0; attrib<attribCount; ++attrib) 
    glEnableVertexAttribArray(attribLoc[attrib]);


glDraw*();

for (int attrib=0; attrib<attribCount; ++attrib) 
    glDisableVertexAttribArray(attribLoc[attrib]);

【讨论】:

我对更通用的方法感兴趣。 我不是只为绘制调用启用和禁用顶点数组状态的忠实粉丝。创建顶点数组对象是为了持久存储独立于顶点缓冲区的顶点数组设置。实际上,您可以为单个 VBO 使用 2 个以上不同的 VAO,具体取决于您的材质(着色器)需要哪些顶点属性,以及它们需要它们的位置。然后,您只需绑定一个 VAO,该 VAO 会在您绘制批次时适当地安排您的 VBO 数据。纹理设置也是如此,现在您应该绑定采样器对象,而您真正想做的只是修改纹理过滤器状态。 从论坛帖子中,人们给我的印象是 VAO 的使用速度很慢,因为 VAO 更改了多少状态。在寻找支持这一说法的信息时,我发现 VAO 的速度并不快或慢,因此使用 VAO 会是一种更优雅的方法。【参考方案2】:

如果您使用的是直上顶点数组指针、texcoord 数组指针等... API 调用,那么您将需要在着色器中使用相应的数组。

更准确地说,当您想要访问着色器中纹理单元 0 的纹理坐标时,您可以使用 gl_TexCoord [0],而不是使用 in vec2 texcoord(用于通用顶点属性)。

这里的根本问题是您将弃用的 API 功能 (glTexCoordPointer) 与新的 GLSL 结构 (inout) 混合在一起。 nVIDIA 驱动程序实际上会将glTexCoordPointer (...) 之类的调用别名为特定的顶点属性槽,但这是非标准行为,您通常不应混合和匹配两者。

唯一一个被 OpenGL 规范保证别名为特定属性槽的数组指针。是顶点指针,别名为attrib slot 0。

最后,您会想要切换到顶点属性数组,因为它们更加灵活并且实际上得到核心 OpenGL 的支持:)

【讨论】:

我明白了。这很有意义。因此,如果我想保留旧版本(因为我已经以这种方式设置了所有渲染代码),我需要删除 In/Out 变量并改用 gl_Vertex 和 gl_TexCoord? 正确,如果您使用旧的 glVertexPointer、glTexCoordPointer 等调用来设置您的顶点数组,那么您应该使用 gl_Vertex、gl_TexCoord 等来访问着色器中的顶点数据。如果/当您转换为使用顶点属性数组时,您将在变量中使用。顺便说一句,您的着色器 sort 现在工作的唯一原因是因为 glVertexPointer 将自己别名为属性槽 0(换句话说,着色器中的第一个 in 属性)。 In 变量实际上是为顶点属性保留的,或者从前一个着色器阶段获取输出(例如,与将数据传递给 fs) 在任何情况下,您都应该养成在着色器顶部附加 #version 指令的习惯,以避免将来出现混淆。如果您想限制自己仅使用纯 OpenGL 2.0 中存在的功能,您可以使用#version 110(尽管这是自动假定的)。从#version 130 (OpenGL 3.0) 开始,“in”/“out”替换了“variing”和“attribute”类型限定符,着色器阶段不再有自己的类型限定符(“attribute”过去用于 vs 输入,“ Varying' 用于 vs 输出/fs 输入等。)

以上是关于传递给片段着色器的纹理坐标全部为 0的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL几何着色器传递纹理坐标

如何将浮点矩阵作为 2D 纹理传递给片段着色器?

为啥我的着色器中的 GLSL 纹理坐标不是线性的?

OpenGL/C++:将多个纹理传递给一个着色器的问题

片段着色器究竟如何用于纹理?

THREE.js - 大型int作为Uniform