Question

Edit: rotoglup found the problems in my code, adding the shaders I had removed completed the solution. See my answer below for the correct code (with shaders).

Hi all !

I'm trying to learn some basics of modern OpenGL from this tutorial.

I'd like to do it with python/pyglet instead of C++ though. I know pyglet can abstract much of the low level OpenGL away; I want to understand some of the basics before moving on to hiding them behind layers of abstraction though.

My problem is extremely simple: the code below only draws a single point instead of the 3 I am expecting. My code is, as far as I can tell, identical to the C++ in the tutorial, except for the removal of vertex and fragment shaders (done via gletools in python), which appears to make no difference to my problem.

Simplifying things to a single point shows behaviour I do not understand (the first coordinate appears to be the only one that affects anything), leading me back to my belief that I've simply failed to understand something very basic about either pyglet, OpenGL, or even 3D in general :p

Here's the relevant code:

import pyglet
from pyglet.gl import *

window = pyglet.window.Window()

positionBufferObject = GLuint()
vao = GLuint()

vertexPositions = [0.0, 0.0, 0.0,
                   0.25, 0.0, 0.0,
                   1.75, 1.75, 0.0]

vertexPositionsGl = (GLfloat * len(vertexPositions))(*vertexPositions)

@window.event
def on_draw():
    glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
    glEnableVertexAttribArray(0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)
    glDrawArrays(GL_POINTS, 0, 3)
    glDisableVertexAttribArray(0)

glGenBuffers(1, positionBufferObject)
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)

glClearColor(0.0, 0.0, 0.0, 0.0)
pyglet.app.run()
Was it helpful?

Solution

glDrawArrays(GL_POINTS, 0, 1)

instructs to draw 1 point, in your tutorial, 1 is 3 :

glDrawArrays(GL_POINTS, 0, 3)

Notice also that the 4th (w) component of your vertices should be 1, not 0 :

  vertexPositions = [0.0, 0.0, 0.0, 1.0,
                     0.25, 0.0, 0.0, 1.0,
                     1.75, 1.75, 0.0, 1.0]

Alternatively, you could remove the w component,

  vertexPositions = [0.0, 0.0, 0.0,
                     0.25, 0.0, 0.0,
                     1.75, 1.75, 0.0]

and change the following call to :

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)

Another thing, I'm not an expert in pyglet, but it's possible that glBufferData, like its C counterpart, take a size in bytes, not in elements. Each float being 4 bytes, you could try :

glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)

OTHER TIPS

I finally got this right !

It seems I was being misled by the fact that fiddling with vertices, glDrawArrays and glVertexAttribPointer sometimes resulted in a single dot being shown. This appears to be an accident: with the corrections provided by rotoglup's answer, nothing at all is drawn. This is the "correct" behaviour for the code in my original question.

An inventory of my mistakes in case it helps anyone:

  • setting the w coordinate to 0, instead of 1, completely missing the explanations for clip-space transformation in the tutorial.

  • giving glBufferData the size of the buffer in vertices when it expects bytes.

  • removing the vertex and fragment shaders (to simplify the code while looking for the above two issues). This ensured that nothing would ever be rendered... except the (buggy ?) single dot I was sometimes getting.

For the record, the code below displays a single triangle, with pass through shaders, in what I hope to be up to date and correct OpenGL. Requirements are pyglet and gletools.

import pyglet
from pyglet.gl import *
from gletools import ShaderProgram, FragmentShader, VertexShader

window = pyglet.window.Window()

positionBufferObject = GLuint()

vertexPositions = [0.75, 0.75, 0.0, 1.0,
                   0.75, -0.75, 0.0, 1.0,
                   -0.75, -0.75, 0.0, 1.0]
vertexPositionsGl = (GLfloat * len(vertexPositions))(*vertexPositions)

program = ShaderProgram(
    FragmentShader('''
    #version 330
    out vec4 outputColor;
    void main()
    {
       outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
    }'''),
    VertexShader('''
    #version 330
    layout(location = 0) in vec4 position;
    void main()
    {
        gl_Position = position;
    }''')
)

@window.event
def on_draw():
    with program:
        glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)
        glDrawArrays(GL_TRIANGLES, 0, 3)
        glDisableVertexAttribArray(0)

glGenBuffers(1, positionBufferObject)
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)

pyglet.app.run()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top