Search code examples
pythonopenglpyglet

Pyglet/OpenGL image flickering on mouse movement


I was following the "Pyglet Python and OpenGL - part 01 - Hello Triangle" tutorial by Attila Toth on YouTube to draw a triangle with Pyglet, as I have never used Pyglet before. As far as I know, the code is identical to what is in the video, however when I move my mouse the image flickers, but there are no error messages.

For reference, my computer has 4 gigabytes of RAM, an i3 7020U and integrated graphics, with DirectX version 12. I am using Windows 10 build 18632.

The code:

import pyglet
from pyglet.gl import *
class Window(pyglet.window.Window):
    def __init__(self, *args,**kwargs):
        super().__init__(*args, **kwargs)
        self.set_minimum_size(400, 300)

        self.triangle = Triangle()

    def ondraw(self):
        self.triangle.vertices.draw(GL_TRIANGLES)

class Triangle():
    def __init__(self):
        self.vertices = pyglet.graphics.vertex_list(3, ('v3f', [-0.5,-0.5,0.0, 0.5,-0.5,0.0, 0.0,0.5,0.0]),
            ('c3B', [100,200,220, 200,110,100, 100,250,100]))

if __name__ == "__main__":
    window = Window(800, 600, "The Game", resizable=True)
    window.ondraw()
    pyglet.app.run()


Solution

  • I can't reproduce the issue, there's no flickering on my machine. (GTX 1070, i7 from 6 years ago and 16GB of RAM, windows 10, etc)

    However, there are some minor issues with your code.
    For one, it's on_draw not ondraw, which will become important later on as it's a hook-override for pyglet.window.Window.on_draw function which gets called at certain events.

    And another important function here is to set the glViewport otherwise nothing will show on the screen. So the minimal code you need, is this:

    import pyglet
    from pyglet.gl import *
    class Window(pyglet.window.Window):
        def __init__(self, *args,**kwargs):
            super().__init__(*args, **kwargs)
            self.set_minimum_size(400, 300)
    
            self.triangle = Triangle()
    
        def on_draw(self):
            self.clear()
            self.triangle.vertices.draw(GL_TRIANGLES)
    
        def on_resize(self, width, height):
            glViewport(0, 0, width, height)
    
    class Triangle():
        def __init__(self):
            self.vertices = pyglet.graphics.vertex_list(3, ('v3f', [-0.5,-0.5,0.0, 0.5,-0.5,0.0, 0.0,0.5,0.0]),
                ('c3B', [100,200,220, 200,110,100, 100,250,100]))
    
    if __name__ == "__main__":
        window = Window(800, 600, "The Game", resizable=True)
        pyglet.app.run()
    

    It's very important to understand that the on_*** events are triggered by internal mechanics of Pyglet, not something you should call manually (as you did in your if __name__ ... by doing window.ondraw()), it's not a good idea.

    Instead, if you want to force a draw event, simply trigger it by triggering a Pyglet event, some examples are:

    • Mouse movement
    • Keyboard input (try hitting spacebar)
    • Setting a clock/timer to schedule updates

    The flickering probably comes from your graphics card (or lack of proper driver) which simply can't handle the refresh-rate you're demanding of it. Try hitting space bar a couple of times really fast, that probably causes the flickering too. In which case, you probably won't get the performance out of that machine that you're expecting.

    A workaround could be: batched rendering which significantly improves rendering times, altho, for a simple triangle you shouldn't experience problems already.