传递给片段着色器的纹理坐标都是0

时间:2013-08-06 14:13:17

标签: opengl glsl shader fragment-shader

我为自己正在研究的一些openGL 2.0应用程序编写了自己的Vertex和Fragment着色器。 一切似乎都很好,除了一件事,每个顶点的纹理坐标似乎都是(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)  

编辑:顺便说一句,这个编辑器中的换行符有什么问题?

2 个答案:

答案 0 :(得分:2)

听起来您需要为纹理坐标启用客户端状态,因此请务必为位置和纹理坐标调用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,“position”);
  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]);
}

答案 1 :(得分:2)

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

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

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

唯一保证由OpenGL规范别名到特定属性槽的数组指针。是顶点指针,它别名为插槽0。

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