Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

basic openGL, vertex buffers and pyglet

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()
like image 284
Nicolas Lefebvre Avatar asked Jan 06 '11 19:01

Nicolas Lefebvre


People also ask

What is a vertex buffer in OpenGL?

A vertex buffer object (VBO) is an OpenGL feature that provides methods for uploading vertex data (position, normal vector, color, etc.) to the video device for non-immediate-mode rendering.

What is pyglet GL?

pyglet provides an interface to OpenGL and GLU. The interface is used by all of pyglet's higher-level API's, so that all rendering is done efficiently by the graphics card, rather than the operating system. You can access this interface directly; using it is much like using OpenGL from C.

Does pyglet use GPU?

Although it is pure Python, Pyglet offers excellent batch processing and GPU rendering performance.

What is pyglet module in Python?

pyglet is a library for the Python programming language that provides an object-oriented application programming interface for the creation of games and other multimedia applications. pyglet runs on Microsoft Windows, macOS, and Linux; it is released under BSD Licence.


2 Answers

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)
like image 78
rotoglup Avatar answered Oct 12 '22 11:10

rotoglup


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()
like image 25
Nicolas Lefebvre Avatar answered Oct 12 '22 10:10

Nicolas Lefebvre