How to update data with a VBO and Pyglet

opengl, pyglet, python, vbo

Solution

You don't need to call `glBufferData` every single time in update - create and fill the VBO once (see `setup_initial_points`) and only update it with `glBufferSubData`. In case you are only working with a single VBO, you can also comment out the `glBindBuffer` call in `update()` (see code below). `GL_DYNAMIC_DRAW` vs `GL_STATIC_DRAW` won't make a big difference in this example since you are pushing very few data onto the GPU.

import pyglet
from pyglet.gl import *
from ctypes import pointer, sizeof

window = pyglet.window.Window(width=800, height=800)

''' update function  '''
c = 0
def update(dt):
    global c
    c+=1
    data = calc_point(c)
    # if there's only on VBO, you can comment out the 'glBindBuffer' call
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data)

pyglet.clock.schedule(update)


''' draw function  '''
@window.event
def on_draw():

    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(0, 0, 0)

    glVertexPointer(2, GL_FLOAT, 0, 0)
    glDrawArrays(GL_POINTS, 0, 2)


''' calculate coordinates given counter 'c' '''
def calc_point(c):
    data = (GLfloat*4)(*[500+c, 100+c, 300+c, 200+c])
    return data


''' setup points '''
def setup_initial_points(c):
    vbo_id = GLuint()
    glGenBuffers(1, pointer(vbo_id))

    data = calc_point(c)
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
    glBufferData(GL_ARRAY_BUFFER, sizeof(data), 0, GL_DYNAMIC_DRAW)

    return vbo_id


############################################

vbo_id = setup_initial_points(c)

glClearColor(0.2, 0.4, 0.5, 1.0)
glEnableClientState(GL_VERTEX_ARRAY)

glPointSize(10)
pyglet.app.run()

Problem

I would like to make a mesh with Pyglet that is changing every frame. Therefore I need to update the vertices very often and I thought that a VBO would be the fastest way to go here (correct me if I am wrong). Below an example for Points. Is this the correct way of doing it? I read that the number of glBindBuffer calls should be minimised, but here it is called every frame. also GL_DYNAMIC_DRAW is enabled, but if I change it to GL_STATIC_DRAW it is still working. It makes me wondering if this is a correct setup for fast computation ``` import pyglet import numpy as np from pyglet.gl import * from ctypes import pointer, sizeof vbo_id = GLuint() glGenBuffers(1, pointer(vbo_id)) window = pyglet.window.Window(width=800, height=800) glClearColor(0.2, 0.4, 0.5, 1.0) glEnableClientState(GL_VERTEX_ARRAY) c = 0 def update(dt): global c c+=1 data = (GLfloat*4)(*[500+c, 100+c,300+c,200+c]) glBindBuffer(GL_ARRAY_BUFFER, vbo_id) glBufferData(GL_ARRAY_BUFFER, sizeof(data), 0, GL_DYNAMIC_DRAW) glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data) pyglet.clock.schedule(update) glPointSize(10) @window.event def on_draw(): glClear(GL_COLOR_BUFFER_BIT) glColor3f(0, 0, 0) glVertexPointer(2, GL_FLOAT, 0, 0) glDrawArrays(GL_POINTS, 0, 2) pyglet.app.run() ```

Original source