Reputation: 1789
I use this code for all OpenGL preparations. I took these pieces from my sources, so there can be omitted parts and uninitialized or undeclared variables, etc. but this works. I tried to post only the meaningful parts of the code.
// Texture reading
int w{}, h{}, channels{};
unsigned char * bytes = stbi_load(path.c_str(), &w, &h, &channels, 0);
// produce Texture object
// GL texture code
glCall(glGenTextures(1, &m_textureId));
glCall(glBindTexture(GL_TEXTURE_2D, m_textureId));
glCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
glCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
glCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_texture->width, m_texture->height, 0, GL_BGR, GL_UNSIGNED_BYTE, m_texture->bytes));
glCall(glGenerateMipmap(GL_TEXTURE_2D));
// Create shader (I omitted this code) and bind texture
glCall(glActiveTexture(GL_TEXTURE0));
glCall(glBindTexture(GL_TEXTURE_2D, m_textureId));
glCall(glUseProgram(m_programId)); // using the shader
// pass texture index into shader
glCall(location = glGetUniformLocation(m_programId, "u_tex0"));
glCall(glUniform1i(location, 0));
// code that sets up uv VBO
/* UV0 positions */
glCall(glGenBuffers(1, &m_VBO[2]));
glCall(glBindBuffer(GL_ARRAY_BUFFER, m_VBO[2]));
glCall(glBufferData(GL_ARRAY_BUFFER, m_model->uv0SizeBytes(), m_model->uv0.data(), GL_STATIC_DRAW));
glCall(glEnableVertexArrayAttrib(m_VAO, 2));
glCall(glVertexAttribPointer(2, m_model->uv0Channels /* 2 here */, GL_FLOAT, GL_FALSE, m_model->uv0Channels * sizeof(m_model->uv0.front()), nullptr));
Shader code:
#version 460 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec3 a_norm;
layout (location = 2) in vec2 a_uv0;
uniform mat4 u_mMVP;
uniform sampler2D u_tex0;
out vec4 v_vertexColor;
void main()
{
gl_Position = u_mMVP * vec4(a_pos, 1.0);
v_vertexColor = texture(u_tex0, a_uv0);
}
If I draw uv's instead of texture
(v_vertexColor = vec4(a_uv0, 0.0, 1.0);
), then it looks correct to me:
Upvotes: 1
Views: 411
Reputation: 210878
You have to look up the texture in the fragment shader. The vertex shader is just executed for each vertex coordinate of a primitive. However the fragment shader is executed for each fragment. The vertex shader outputs are interpolated along the primitives and passed to the fragment shader. Therefore your code lookup the texture just for the 4 corners of the quad.
Pass the texture coordinates to the fragment shader:
#version 460 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec3 a_norm;
layout (location = 2) in vec2 a_uv0;
uniform mat4 u_mMVP;
out vec2 v_uv;
void main()
{
gl_Position = u_mMVP * vec4(a_pos, 1.0);
v_uv = a_uv0;
}
Use the interpolated texture coordinate in the fragment shader to lookup the texture for each fragment:
#version 460 core
in vec2 v_uv;
out vec4 FragColor;
uniform sampler2D u_tex0;
void main()
{
vec4 vertexColor = texture(u_tex0, v_uv);
FragColor = vertexColor;
}
Upvotes: 1