I cannot figure out why the glDrawElements is not working. I've used the glDrawArrays successfully. But the moment I try to draw with glDrawElements, it is not working.
I am following the learnopengl.com website's tutorials in python, so it adds a bit to the headache. Any idea why this is not working? I've been looking at it for almost a day and can't see the error in my ways.
import glfw
import numpy as np
import OpenGL
from OpenGL.GL import *
from OpenGL.GL import shaders, ArrayDatatype
from ctypes import sizeof, c_float, c_void_p
def main():
width = 800
height = 600
title = 'Hello Triangle'
vertex = """#version 410 core
in vec3 aPos;
void main() {
gl_Position = vec4(aPos, 1.0);
}"""
fragment = """#version 410 core
out vec4 FragColor;
void main() {
FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}"""
if not glfw.init():
raise TypeError('Unable to initalize glfw')
glfw.window_hint(glfw.SAMPLES, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
glfw.window_hint(glfw.OPENGL_DEBUG_CONTEXT, True)
window = glfw.create_window(width, height, title, None, None)
if not window:
raise TypeError('Unable to create the window')
glfw.make_context_current(window)
glfw.set_framebuffer_size_callback(window, framebuffer_size)
verts = np.array([[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]], dtype=np.float)
indices = np.array([[0, 1, 3], [3, 1, 2]], dtype=np.uint)
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex_shader, vertex)
glCompileShader(vertex_shader)
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragment_shader, fragment)
glCompileShader(fragment_shader)
shader_program = glCreateProgram()
glAttachShader(shader_program, vertex_shader)
glAttachShader(shader_program, fragment_shader)
glLinkProgram(shader_program)
glDeleteShader(vertex_shader)
glDeleteShader(fragment_shader)
vao_id = glGenVertexArrays(1)
vbo_id = glGenBuffers(1)
ebo_id = glGenBuffers(1)
glBindVertexArray(vao_id)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_id)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
#glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
glBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, None)
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(shader_program)
glBindVertexArray(vao_id)
glEnableVertexAttribArray(0)
#glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glBindVertexArray(0)
glfw.swap_interval(1)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.destroy_window(window)
glfw.terminate()
def framebuffer_size(window, width, height):
glViewport(0, 0, width, height)
if __name__ == '__main__':
main()
There are two tricky issues that need to be addressed in this code, and both of them are subtle and python-specific.
First, you should replace the 0
in glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
with None
. I suspect this is because PyOpenGL uses ctypes to wrap OpenGL and None
is recommended to represent the NULL
pointer according to the ctypes documentation. If you need to use offsets for your buffers later, you should look at this answer.
Second, if you just do step 1 and run the code, you might find the output to not be what you expect:
What happened to our orange rectangle? Well, the problem here is with the data we are passing to our buffer objects. If you are on a 64-bit device, the numpy data types (dtype) will be 64-bit too if not fully specified. OpenGL expects 32-bit floats and integers rather than doubles, so we need to use np.float32
instead. I would also use np.uint32
for your index buffer for consistency's sake, but this is not strictly necessary. If we fix your verts
and indices
initialization statements to this:
verts = np.array([[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]], dtype=np.float32)
indices = np.array([[0, 1, 3], [3, 1, 2]], dtype=np.uint32)
The results should be more like what you expect:
Hope this helps!