Оптимизируйте скрипт pyglet, чтобы иметь возможность отображать больше объектов.

Я создал простой скрипт для рендеринга пикселей на экран. Все сценарии делают случайные строки из 4 символов из 0 и 1 (эти 4 символа составляют объект), а затем многократно рисуют объекты в виде пикселей на экране.

import random
from pyglet.gl import *
from pyglet import clock
from pyglet.window import key


W = 1280
H = 720
NUM_OBJECTS = 200
CELL_SIZE = 4
BACKGROUND_COLOR = [1.0, 1.0, 1.0, 1.0]
OBJECT_COLOR = [241, 148, 138]


class GameWindow(pyglet.window.Window):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        glClearColor(*BACKGROUND_COLOR)

        self.positions = []
        self.render_objects = []
        self.main_batch = None
        self.init_objects()

    def init_objects(self):
        self.main_batch = pyglet.graphics.Batch()
        self.render_objects = [''.join(random.choice("01") for _ in range(4)) for _ in range(4)]
        self.positions = []

        # Init positions
        current_x = 1
        current_y = 1
        for i in range(NUM_OBJECTS):
            if current_x * CELL_SIZE >= W - 4*CELL_SIZE:
                current_x = 1
                current_y += CELL_SIZE + 1

            self.positions.append((current_x, current_y))
            current_x += CELL_SIZE + 1

    def draw_object(self, position):

        row_count = position[0]
        for row in self.render_objects:
            col_count = position[1]
            for i in row:
                st_x = row_count * CELL_SIZE
                st_y = col_count * CELL_SIZE
                nd_x = st_x + CELL_SIZE
                nd_y = st_y + CELL_SIZE
                self.draw_pixel(st_x, st_y, nd_x, nd_y,
                                int(i) == 1)
                col_count += 1
            row_count += 1

    def on_draw(self):
        self.clear()
        self.main_batch.draw()
        print(clock.get_fps())

    def reset(self):
        self.init_objects()

    def draw_pixel(self, x, y, x1, y1, is_draw, color=None):
        if not is_draw:
            return

        self.main_batch.add(4, pyglet.gl.GL_QUADS, None,
                            ('v2f', [x, y, x1, y, x1, y1, x, y1]),
                            ('c3B', (OBJECT_COLOR if color is None else color) * 4))

    def update(self, dt):
        [self.draw_object(p)
         for p in self.positions]

    def on_key_press(self, symbol, modifiers):
        if symbol == key.R: self.reset()

    def on_mouse_press(self, x, y, button, modifiers):
        pass


if __name__ == "__main__":
    game = GameWindow(W, H)
    pyglet.clock.schedule_interval(game.update, 1 / 60)
    pyglet.app.run()

В приведенном выше скрипте 200 объектов (переменная с именем NUM_OBJECTS) визуализируются в каждом кадре (в пакетном режиме), когда я увеличиваю это число, скажем, до 500, частота кадров падает примерно до 16. Объекты отрисовываются при каждом вызове update, потому что в будущем я хочу иметь возможность менять положение всех этих объектов в каждом кадре.

Моя цель состоит в том, чтобы иметь возможность отображать больше объектов на экране (скажем, 1k-2k объектов), и я почти уверен, что делаю что-то не так в сценарии либо относительно opengl, либо относительно pyglet. Также есть ли способ сохранить рисунок opengl в объекте и просто добавлять его в пакет каждый кадр?


person sujay_br    schedule 01.12.2020    source источник


Ответы (1)


В вашем коде вы постоянно добавляете вершины в каждом кадре, поэтому это снижает производительность.

Ваш draw_pixel добавляет вершины в пакет, что вы делаете каждый кадр.

Что вам нужно сделать, так это отделить создание вашего объекта от ваших обновлений. batch.add возвращает список вершин, который вы можете обновить.

Сделайте это только один раз для каждого объекта и сохраните его где-нибудь: vertex_list = batch.add(..)

Затем, чтобы обновить позиции вершин, вы бы сделали. vertex_list.vertices[:] = new_list_of_vertices

person Charlie    schedule 14.12.2020