1

Env:

pyglet - 1.4.2
python - 3.6.6

Background:

For an example there is 160000+ GL_QUADS in a batch, which relates to same pyglet.graphics.TextureGroup and should have same tex_coords in all period of time.

And for an example there is a logic: each X seconds all these GL_QUADS should change their tex_coords with new same value.

Problem:

I know only one way to change tex_coords on vertices - it's iterate through them and explicitly change it like vert.tex_coords = new_text_coords.
But obviously it will take a long time.

Question:

  1. How to change tex_coords for a huge count of vertices?
  2. Is it possible at all in OpenGL perspective?

Code with example:

rgba.png - is 4*4px image (just an example, real texture could be bigger)

import pyglet
import time


class Window(pyglet.window.Window):

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.batch = pyglet.graphics.Batch()
        self.position = [400, 200, 300.0]
        self.collection = []

        image = pyglet.image.load("rgba.png")  # image is 4px on 4px, just example
        image_grid = pyglet.image.ImageGrid(image, 2, 2)
        texture_grid = image_grid.get_texture_sequence()
        self.texture_group = pyglet.graphics.TextureGroup(texture_grid)

        pyglet.graphics.glTexParameteri(
            pyglet.graphics.GL_TEXTURE_2D,
            pyglet.graphics.GL_TEXTURE_MAG_FILTER,
            pyglet.graphics.GL_NEAREST
        )
        pyglet.graphics.glTexParameteri(
            pyglet.graphics.GL_TEXTURE_2D,
            pyglet.graphics.GL_TEXTURE_MIN_FILTER,
            pyglet.graphics.GL_NEAREST
        )
        self.tex_map_for_blue_block = texture_grid[0].tex_coords
        self.tex_map_for_transparent_block = texture_grid[1].tex_coords
        self.tex_map_for_red_block = texture_grid[2].tex_coords
        self.tex_map_for_green_block = texture_grid[3].tex_coords

        for x in range(400):
            for y in range(400):
                self.add_vertex_block(x, y)

        self.next_color_generator = self.next_color()
        pyglet.clock.schedule_interval(self.update, 1 / 2)

    def next_color(self):
        while True:
            yield self.tex_map_for_red_block
            yield self.tex_map_for_green_block
            yield self.tex_map_for_blue_block
            yield self.tex_map_for_transparent_block

    def update(self, delta_time):
        start = int(time.time() * 1000)
        new_text_coords = next(self.next_color_generator)
        for vert in self.collection:
            vert.tex_coords = new_text_coords
        print(f"finish changes in {int(time.time() * 1000) - start}ms")

    def add_vertex_block(self, x, y):
        x *= 2
        y *= 2
        tex_coords = ('t3f', self.tex_map_for_red_block)

        vertices = self.batch.add(
            4, pyglet.gl.GL_QUADS,
            self.texture_group,
            ('v3f', (x, y, 0,
                     x + 2, y, 0,
                     x + 2, y + 2, 0,
                     x, y + 2, 0)
             ),
            tex_coords
        )
        self.collection.append(vertices)

    def set_3d(self):
        width, height = self.get_size()
        pyglet.graphics.glEnable(pyglet.graphics.GL_BLEND)
        pyglet.graphics.glBlendFunc(
            pyglet.graphics.GL_SRC_ALPHA,
            pyglet.graphics.GL_ONE_MINUS_SRC_ALPHA)
        pyglet.graphics.glViewport(0, 0, width, height)
        pyglet.graphics.glMatrixMode(pyglet.graphics.GL_PROJECTION)
        pyglet.graphics.glLoadIdentity()
        pyglet.graphics.gluPerspective(90, width / height, 0.1, 6000.0)
        pyglet.graphics.glMatrixMode(pyglet.graphics.GL_MODELVIEW)
        pyglet.graphics.glLoadIdentity()
        x, y, z = self.position
        pyglet.graphics.glTranslatef(-x, -y, -z)

    def on_draw(self):
        self.clear()
        self.set_3d()
        self.batch.draw()


if __name__ == '__main__':
    window = Window(width=600, height=400, caption='Pyglet', resizable=True)
    pyglet.app.run()

Log:

finish changes in 504ms
finish changes in 499ms
finish changes in 498ms
...

What I have tried:

I thought there should be some way to "share" array with used tex_coords and if values will be changed on initial array - it will lead to changing on vertices's arrays too.
But I was wrong, and as I understand - each vertex has it our array with tex_coords with is not related to initial self.shared_tex_coords

class Window(pyglet.window.Window):
    def __init__():
        ...
        self.shared_tex_coords = [x for x in self.tex_map_for_blue_block]
        ...

    def update(self, delta_time):
        new_text_coords = next(self.next_color_generator)
        for ind, value in enumerate(new_text_coords):
            self.shared_tex_coords[ind] = value

    def add_vertex_block(self, x, y):
        tex_coords = ('t3f', self.tex_map_for_red_block)
        ...
Yuriy Leonov
  • 536
  • 1
  • 9
  • 33
  • In this case [Batched rendering](https://pyglet.readthedocs.io/en/pyglet-1.3-maintenance/programming_guide/graphics.html#batched-rendering) is not the proper solution. I recommend to create 1 quad and to render it at different locations by different translations. In "modern" OpenGL this can be achieved by [Instancing](https://www.khronos.org/opengl/wiki/Vertex_Rendering#Instancing). Sadly this is not provided by pyglet, as far as I know. – Rabbid76 Aug 21 '19 at 20:18
  • @Rabbid76 Thanks for "Instancing" link. I'll try to implement it using OpenGL calls tomorrow. And will read somothing on this area. – Yuriy Leonov Aug 21 '19 at 20:24
  • Note, that is a really broad topic, because you've to use a [Shader](https://www.khronos.org/opengl/wiki/Shader) and of course a [Vertex Array Object](https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object). Possibly [Visualizing a 3D NumPy array with PyOpenGL](https://stackoverflow.com/questions/18085655/visualizing-a-3d-numpy-array-with-pyopengl/55290300#55290300) gives you an idea what to do. The answer is implemented with PyOpenGL rather than pyglet, but at least it is Python. – Rabbid76 Aug 21 '19 at 20:26

0 Answers0