I was trying to make a model/simulation of the moon using python by pyopengl and pygame. I used an open source 3d model of the moon in .obj file and tried to merge it in my code. But for some reason, an error occurs with a tag of
OpenGL.error.GLError: GLError(err = 1282,description = b'invalid operation',baseOperation = glGetAttribLocation,cArguments = (6, b'position\x00')
My implementation is separated into different classes (like OOP) but the main ones i.e the shader, the moon class and the class where i use that program are listed below. The OBJ loader is directly from the official pygame website.
Vertex Shader
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 newColor;
layout (location = 2) in vec2 verTexCoord;
out vec3 color;
out vec2 fragTexCoord;
// other methods like scaling, rotation
void main(){
vec4 pos = vec4(position, 1.0);
// apply translation, rotation and scaling
gl_Position = pos;
fragTexCoord = verTexCoord;
color = newColor;
}
Fragment Shader
#version 330
in vec3 color;
in vec2 fragCoord;
out vec4 outColor;
uniform sampler2D ourTexture;
void main(){
outColor = texture2D(ourTexture, fragCoord);
}
Moon
from objloader import *
class Moon(Shape):
def __init__(self):
Shape.__init__(self)
self.obj = OBJ("Moon\moon.obj", swapyz=True)
self.drawing_type = GL_POLYGON
self.setup_shaders()
self.setup_buffers()
def setup_shaders(self):
# Get and Compile the shaders here
self.program = glCreateProgram()
glAttachShader(self.program, vertexShader)
glAttachShader(self.program, fragmentShader)
glLinkProgram(self.program)
def setup_buffers(self):
self.vao = glGenVertexArrays(1)
self.vbo = glGenBuffers(1)
v = []
# buildlist will give a list that contains the moons vertices including the texture coordinates.
v = self.buildList(self.obj)
self.vertexes = np.stack(v)
self.vertex_length = len(self.vertexes)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, self.vertexes.nbytes, self.vertexes, GL_STATIC_DRAW)
glBindVertexArray(self.vao)
# This is the line the error occurs at.
positionLocation = glGetAttribLocation(self.program, "position")
Not necessary but here is the Shape class and the function where the drawing text place(It is in a different class than Shape).
class Shape():
def __init__(self):
self.vao = None
self.vbo = None
self.program = None
self.vertexes = None
self.drawing_type = None
self.vertex_length = None
Drawing Function
def draw(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for shape in self.shapes:
glUseProgram(shape.program)
glBindVertexArray(shape.vao)
glDrawArrays(shape.drawing_type, 0, shape.vertex_length)
glBindVertexArray(0)
glGetAttribLocation
gives an invalid operation error, because the program object self.program
is not linked correctly.
The program is not linked, because the output variables of the vertex shader does not match the input variables of the fragment shader.
Vertex shader:
out vec3 color;
out vec2 fragTexCoord;
Fragment shader:
in vec3 color;
in vec2 fragCoord;
Change the fragment shader like this, to solve the issue:
#version 330
in vec3 color;
in vec2 fragTexCoord; // "fragTexCoord" insted of "fragCoord"
out vec4 outColor;
uniform sampler2D ourTexture;
void main(){
outColor = texture2D(ourTexture, fragTexCoord);
}
Note, if a program object has been linked successfully can be checked by glGetProgramiv( self.program, GL_LINK_STATUS )
:
glLinkProgram( self.program )
if not glGetProgramiv( self.__prog, GL_LINK_STATUS ):
print( 'link error:' )
print( glGetProgramInfoLog( self.__prog ) )
For the sake of completeness, if a shader object has been compiled successfully can be checked by glGetShaderiv( shaderObj, GL_COMPILE_STATUS )
:
glCompileShader( shaderObj )
if not glGetShaderiv( shaderObj, GL_COMPILE_STATUS ):
print( 'compile error:' )
print( glGetShaderInfoLog( shaderObj ) )