Question

I've been trying to convert some old OpenGL code over to use shaders, and I've run into a problem getting my fragment shader to draw a texture on a cube. However, all I see is a grey cube instead. I've debugged my .obj loader code and I know that the UVs are getting loaded correctly, and I know the texture is being loaded from disk and put on the GPU correctly. After quite a lot of testing, I found out that my UV values are not being interpolated across the face of each triangle. That is, it looks like every fragment gets the uv value 0.0,0.0 (This is the first uv value in my buffer) Any ideas why?

Here is my fragment shader:

#version 430 core

in vec3 color;
in vec2 uv;
uniform sampler2D tex;
out vec3 frag_color;

void main()
{
    //frag_color = color;
    frag_color = texture(tex,uv).rgb;
}

And my vertex shader:

#version 430 core

layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 uv;
uniform mat4 mvMatrix;
uniform mat4 mvpMatrix;
attribute vec3 lightPos;
out vec3 color;
out vec2 uv_out;

void main()
{
uv_out = uv;

vec3 modelViewVertex = vec3(mvMatrix * vec4(pos,1.0));
vec3 modelViewNormal = vec3(mvMatrix * vec4(normal,0.0));
vec3 modelViewLightPos = vec3(mvMatrix * vec4(lightPos,1.0));

vec3 lightVector = normalize(lightPos - pos);
float diffuse = clamp(dot(normal,lightVector),0,1);

gl_Position = mvpMatrix * vec4(pos,1.0);
color = vec3(diffuse,0.0,0.0);

}

Here is where I set up the buffers:

glGenVertexArrays(1, &vertexBufferObjectID);
glBindVertexArray(vertexBufferObjectID);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vec3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size()*sizeof(vec3), &normals[0], GL_STATIC_DRAW);
glGenBuffers(1, &UVBuffer);
glBindBuffer(GL_ARRAY_BUFFER, UVBuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size()*sizeof(vec2), &uvs[0], GL_STATIC_DRAW);

Finally, here is my render loop:

glUseProgram(shaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(textureID, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, UVBuffer);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

mvpMatrix = projectionMatrix * viewMatrix * modelMatrix;
glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, &mvpMatrix[0][0]);
mvMatrix = viewMatrix * modelMatrix;
glUniformMatrix4fv(mvMatrixID, 1, GL_FALSE, &mvMatrix[0][0]); 
glVertexAttrib3fv(lightposID, &lightpos[0]);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);

Again, everything looks correct based off what I've read. Anything look wrong?

Was it helpful?

Solution

You have to hand the uv varying from the vertex to the fragment shader. You can not have an in attribute of the same name in both the vertex and the fragment shader. Instead you must have some in attribute in the vertex shader, which is then passed to an out varying with the same name as an corresponding in in the fragment shader.

In your case your vertex shader already has an out varying uv_out. Hence the fragment shader varying needs to be named uv_out as well, i.e. in the fragment shader

in vec2 uv_out

Of course the name uv_out is then a bit misleading.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top