Search code examples
pythonopenglopengl-3pyopenglvao

glGenVertexArrays error on openGL3+


my professor just gave us a simple code that draws a triangle and it worked fine on the university lab. However at my personal computer I'm running into some weird error that I can't seem to find the solution on line. Up until now all openGL code worked just fine on my computer, so I would appreciate if anyone can tell me what is happening. The problem is with the function glGenVertexArrays(1, vao) when the code execute I get the following error:

ValueError: glGenVertexArrays requires 1 arguments (n), received 2: (1, c_uint(0L))

So from what I understood it only requires one argument but 2 are given, therefore I went ahead and removed the 1 getting glGenVertexArrays(vao). But that also gives me an error:

TypeError: ('an integer is required', 'Failure in cConverter <OpenGL.converters.SizedOutput object at 0x7f582456c380>', (c_uint(0L),), 1, <OpenGL.platform.baseplatform.glGenVertexArrays object at 0x7f58244f3a28>)

From that error I got that I do need that integer, and after looking at the documentation for the function glGenVertexArrays I realized that the integer is only telling how many arrays there are so it should indeed be there. In a desperate attemp I removed the function completely and the code worked, a red triangle was shown to me. But what role does glGenVertexArrays plays in all this? Should I be removing it? After some research it found out the VAO's become required after openGL3+ and then I got confused because this is openGL3+ it uses shader's and it is not fixed function, what am I missing here?

Here is the code in python:

import sys
import numpy as np

from OpenGL.GL import *
from OpenGL.GL import shaders
from OpenGL.GLUT import *

vao = None;
vbo = None;
shaderProgram = None;

def readShaderFile(filename):
    with open('shader330/' + filename, 'r') as myfile:
        return myfile.read()

def init():
    global shaderProgram
    global vao
    global vbo

    glClearColor(0, 0, 0, 0);

    vertex_code = readShaderFile('hello.vp')
    fragment_code = readShaderFile('hello.fp')

    # compile shaders and program
    vertexShader = shaders.compileShader(vertex_code, GL_VERTEX_SHADER)
    fragmentShader = shaders.compileShader(fragment_code, GL_FRAGMENT_SHADER)
    shaderProgram = shaders.compileProgram(vertexShader, fragmentShader)

    # Create and bind the Vertex Array Object
    vao = GLuint(0)
    glGenVertexArrays(1, vao)
    glBindVertexArray(vao)

    # Create and bind the Vertex Buffer Object
    vertices = np.array([[0, 1, 0], [-1, -1, 0], [1, -1, 0]], dtype='f')
    vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW)

    glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, None)  # first 0 is the location in shader
    glBindAttribLocation(shaderProgram, 0, 'vertexPosition')  # name of attribute in shader
    glEnableVertexAttribArray(0);  # 0=location do atributo, tem que ativar todos os atributos inicialmente sao desabilitados por padrao

    # Note that this is allowed, the call to glVertexAttribPointer registered VBO
    # as the currently bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)
    glBindVertexArray(0);

def display():
    global shaderProgram
    global vao

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    # load everthing back
    glUseProgram(shaderProgram)
    glBindVertexArray(vao)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)

    # glDrawArrays( mode , first, count)
    glDrawArrays(GL_TRIANGLES, 0, 3)

    #clean things up
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    glBindVertexArray(0)
    glUseProgram(0)

    glutSwapBuffers()  # necessario para windows!

def reshape(width, height):
    glViewport(0, 0, width, height)

if __name__ == '__main__':
    glutInit()
    glutInitContextVersion(3, 0)
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)

    glutInitWindowSize(640, 480);
    glutCreateWindow(b'Hello world!')

    glutReshapeFunc(reshape)
    glutDisplayFunc(display)

    init()

    glutMainLoop()

Solution

  • Not sure why it worked in your lab, may be you got a buggy code. I'm pretty sure though that the pyopengl doc is wrong.

    If you look at the c++ doc of openGL it says

    void glGenVertexArrays( GLsizei n, GLuint *arrays);

    n - Specifies the number of vertex array object names to generate.

    arrays - Specifies an array in which the generated vertex array object names are stored.

    But if you look here it says theres no need to pass the said pointer and this is one of the differences between the python bindings of opengl and c++ lib.

    And glBindVertexArray(vao) does the work of binding the array to the object.

    So you just have to pass that 1 leaving vao.

    Moreover the error also clearly mentions it -

    ValueError: glGenVertexArrays requires 1 arguments (n)