I have been following an online tutorial on OpenGL lately to test integration of PyOpenGL into a PyQt5 application with QOpenGLWidget. I was able to follow every episode with no issues until the textures episode; I cannot get the texture to render at all.
My code is as follows (wrappers removed to make the code simpler, but I have tested it to make sure it is the same):
def FirstFrame():
positions = [
-0.5, -0.5, 0.0, 0.0,
+0.5, -0.5, 1.0, 0.0,
+0.5, +0.5, 1.0, 1.0,
-0.5, +0.5, 0.0, 1.0
]
indices = [
0, 1, 2,
2, 3, 0,
]
global g_vao
vao = g_vao = glGenVertexArrays(1)
glBindVertexArray(vao)
global g_posBuffer
posBuffer = g_posBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, posBuffer)
glBufferData(GL_ARRAY_BUFFER, (GLfloat * len(positions))(*positions), GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), c_void_p(0))
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), c_void_p(8))
global g_idxBuffer
idxBuffer = g_idxBuffer = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxBuffer)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLuint * len(indices))(*indices), GL_STATIC_DRAW)
vertexShader = """
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_TexCoord;
void main()
{
gl_Position = position;
v_TexCoord = texCoord;
}
"""
fragmentShader = """
#version 330 core
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 colorTemp;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
void main()
{
vec4 texColor = texture(u_Texture, v_TexCoord);
color = texColor;
}
"""
global g_shader
shader = g_shader = compileProgram(compileShader(vertexShader, GL_VERTEX_SHADER),
compileShader(fragmentShader, GL_FRAGMENT_SHADER))
glUseProgram(shader)
global g_data
g_data, width, height = ParseRGBA8DDS("ChernoLogo.dds") # Parses input DDS file and returns bytearray of flipped texture
localBuffer = (GLubyte * len(g_data)).from_buffer(g_data) # Making a copy instead of using from_buffer does not work either
global g_tex
tex = g_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, localBuffer) # Passing g_data directly does not work either
glBindTexture(GL_TEXTURE_2D, 0)
glActiveTexture(GL_TEXTURE0 + 0)
glBindTexture(GL_TEXTURE_2D, tex)
global g_tex_loc
tex_loc = g_tex_loc = glGetUniformLocation(shader, "u_Texture")
assert tex_loc != -1
glUniform1i(tex_loc, 0)
def MainLoopIteration():
glClear(GL_COLOR_BUFFER_BIT)
global g_shader, g_r, g_vao, g_idxBuffer
glUseProgram(g_shader)
glBindVertexArray(g_vao)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_idxBuffer)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, c_void_p(0))
I have tried color = vec4(v_TexCoord, 0.0, 1.0)
and color = vec4(u_Texture, 0.0, 0.0, 1.0)
(and binding to slot 1) in the fragment shader to make sure these variables are set correctly and indeed they are.
In fact, I have checked texColor
and it looks to be (0.0, 0.0, 0.0, 1.0)
for all pixels.
I have also verified the output of ParseRGBA8DDS()
by hand and it looks to be correct.
I found the issue. This is something the tutorial does not mention, but I needed to rebind and reactivate the texture on each frame. Althought I'm not sure why it still works for the person giving the tutorial.