I recently got into OpenGL, and used PyOpenGL and the fixed-function pipeline (I know, I know) to draw cubes and stuff.
Anyway, everyone told me that fixed-function is horrible and deprecated, so I got into core-profile OpenGL just now. I've been followig this tutorial, which is in C++, by just transforming everything into Python with basically the same libraries.
I've gotten to the point where I want to render a single 2D triangle using VBOs and VAOs, and the code runs, but doesn't actually draw anything.
Here it is (bear in mind, I'm totally new to this, so I probably messed up an elementary function call somewhere, and I don't really know how everything works):
import numpy as np
import glfw
from OpenGL.GL import *
def main():
glfw.init()
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 5)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
window = glfw.create_window(800, 600, "helo wold", None, None)
glfw.make_context_current(window)
vertices = np.array([-0.5, -0.5, 0, 0.5, -0.5, 0, 0, 0.5, 0], dtype = 'float32')
vertexShaderSource = '''#version 450 core
layout (location = 0) in vec3 aPos;
void main() {
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
'''
vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, vertexShaderSource)
glCompileShader(vertexShader)
fragmentShaderSource = '''#version 450 core
out vec4 FragColor;
void main() {
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
'''
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, fragmentShaderSource)
glCompileShader(fragmentShader)
shaderProgram = glCreateProgram(1)
glAttachShader(shaderProgram, vertexShader)
glAttachShader(shaderProgram, fragmentShader)
glLinkProgram(shaderProgram)
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
vbo, vao = glGenBuffers(1), glGenVertexArrays(1)
glBindVertexArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, len(vertices), vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, 0)
glEnableVertexAttribArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
while not glfw.window_should_close(window):
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(shaderProgram)
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, 3)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
if __name__ == '__main__':
main()
It opens the window fine, and has the background color I gave it, but it doesn't draw the triangle in any way.
I'd love it if someone could tell me what I'm doing wrong, thanks!
The 2nd parameter of glBufferData
has to be the size in bytes, len(vertices)*4
rather than len(vertices)
:
glBufferData(GL_ARRAY_BUFFER, len(vertices)*4, vertices, GL_STATIC_DRAW)
Since PyOpenGL's glBufferData
is overloaded, the size parameter can be omitted (if data is a ctypes
array or numpy.array
):
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW)
The last parameter of glVertexAttribPointer
ahs to be of type const GLvoid *
. Thus it has to be None
or ctypes.c_void_p(0)
rather than 0:
Either
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, None)
or
import ctypes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, ctypes.c_void_p(0))
Further more I recommend to evaluate if the shaders are compiled successfully (glGetShaderiv
):
vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, vertexShaderSource)
glCompileShader(vertexShader)
if not glGetShaderiv(vertexShader, GL_COMPILE_STATUS ):
print('vertex shader compile error:')
print(glGetShaderInfoLog(vertexShader))
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, fragmentShaderSource)
glCompileShader(fragmentShader)
if not glGetShaderiv(fragmentShader, GL_COMPILE_STATUS):
print('fragment shader compile error:')
print(glGetShaderInfoLog(fragmentShader))
And the program is linked successfully (glGetProgramiv
):
glLinkProgram(shaderProgram)
if not glGetProgramiv(shaderProgram, GL_LINK_STATUS):
print('link error:')
print(glGetProgramInfoLog(shaderProgram))