Оптимизирайте скрипта на pyglet, за да можете да изобразявате повече обекти

Създадох прост скрипт за изобразяване на пиксели на екрана. Всичко, което скриптовете правят, е да получат произволни низове от 4 символа от 0s и 1s (тези 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, fps пада до около 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