Reputation: 31
So I have been following alone with the learnopengl.com book and have been having trouble getting texture units working. At first I was calling glGetUniform1i in the main loop like he does in the book but was advised (via the #learnprogramming IRC) to limit any texturing operations to before the main loop. With the book's code the issue is that the textures do not mix correctly as defined in the fragment shader and only the second texture (in this case "faceTexture") bound to GL_TEXTURE_2D is rendered. Flipping the order of rendering renders whichever texture used to come first.
However, placing the texture unit code before the main loop results in an Invalid Operation on the glUniform1i call:
File "C:/Users/1117254/Documents/Python Experiments/OpenGL/OpenGL Testing/main.py", line 171, in main
glUniform1i(wood_texture_loc, 0)
File "C:\Users\1117254\AppData\Local\Programs\Python\Python36\lib\site-packages\OpenGL\platform\baseplatform.py", line 402, in __call__
return self( *args, **named )
File "errorchecker.pyx", line 53, in
OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError (src\errorchecker.c:1218)
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glUniform1i,
cArguments = (23724032, 0)
)
The error to me seems to be related to the location of the uniform variable in the frag shader, but I don't know for sure if the location glGetUniformLocation gives (appears to be 23724032) is valid or not.
Relevant source below along with the vertex and fragment shaders:
# Shader
shader = shader_loader.Shader("vertex.vs", "fragment.fs")
# Vertex Buffering
vao = GLuint(0)
vbo = GLuint(0)
ebo = GLuint(0)
glGenVertexArrays(1, vao)
glGenBuffers(1, vbo)
glGenBuffers(1, ebo)
glBindVertexArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, 4 * len(vertices), vertices, GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * len(indices), indices, GL_STATIC_DRAW)
# Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(3 * 4))
glEnableVertexAttribArray(1)
# Texture attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(6 * 4))
glEnableVertexAttribArray(2)
# Unbinding buffers
glBindVertexArray(0)
# Texturing
wood = Image.open("resources/wood.jpg")
wood.load()
face = Image.open("resources/awesomeface.jpg")
face.load()
# face.transpose(Image.FLIP_LEFT_RIGHT)
wood_texture_loc = glGetUniformLocation(shader.shader_program, "woodTexture")
face_texture_loc = glGetUniformLocation(shader.shader_program, "faceTexture")
wood_data = list(wood.getdata())
wood_data = numpy.array(wood_data, dtype=numpy.uint8)
face_data = list(face.getdata())
face_data = numpy.array(face_data, dtype=numpy.uint8)
# Wood texture
texture1 = GLuint(0)
glGenTextures(1, texture1)
glBindTexture(GL_TEXTURE_2D, texture1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
wood.size[0], wood.size[1],
0,
GL_RGB,
GL_UNSIGNED_BYTE,
wood_data)
glGenerateMipmap(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
# Face texture
texture2 = GLuint(0)
glGenTextures(1, texture2)
glBindTexture(GL_TEXTURE_2D, texture2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
face.size[0], face.size[1],
0,
GL_RGB,
GL_UNSIGNED_BYTE,
face_data)
glGenerateMipmap(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, texture1)
glUniform1i(wood_texture_loc, 0)
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, texture2)
glUniform1i(face_texture_loc, 1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
glClearColor(0.4667, 0.7373, 1., 1.0)
glClear(GL_COLOR_BUFFER_BIT)
shader.use()
glBindVertexArray(vao)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
glBindVertexArray(0)
pygame.display.flip()
clock.tick(fps)
Vertex Shader:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoords;
out vec3 ourColor;
out vec2 texCoordsOut;
void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
texCoordsOut = vec2(texCoords);
}
Fragment Shader:
#version 330
in vec3 ourColor;
in vec2 texCoordsOut;
out vec4 color;
uniform sampler2D woodTexture;
uniform sampler2D faceTexture;
void main()
{
color = mix(texture(woodTexture, texCoordsOut), texture(faceTexture,
texCoordsOut), 0.2);
}
Any insight is greatly appreciated.
Upvotes: 2
Views: 3731
Reputation: 474316
glUniform*
does not take a program object to modify. As such, it modifies the program that is currently in use. Since no program is currently in use, you get an error.
Use the program before calling this function.
Upvotes: 10