7

这是代码。5000 个弹跳旋转的红色方块。(16x16 png)在 pygame 版本上,我得到 30 fps 但使用 pyglet 时得到 10 fps。对于这种事情,OpenGl 不应该更快吗?

pygame版本:

import pygame, sys, random
from pygame.locals import *
import cProfile

# Set FPS
FPS = 60.0
clock = pygame.time.Clock()

# Set window
WINDOWWIDTH= 800
WINDOWHEIGHT = 600

pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))

screen.fill((0,0,0))
background = screen.copy().convert()
image = pygame.image.load("square.png").convert()

class Square(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.v_x = random.randint(1,100)
        self.v_y = random.randint(1,100)
        self.v_r = random.randint(-100,100)
        self.rotation = 0

    def __rep__(self):
        return "Square %d,%d"%(self.x,self.y)

    def update(self,dt):
        if self.x > WINDOWWIDTH:
            self.v_x *= -1
        elif self.x < 0:
            self.v_x *= -1
        if self.y > WINDOWHEIGHT:
            self.v_y *= -1
        elif self.y < 0:
            self.v_y *= -1

        self.x += self.v_x * dt
        self.y += self.v_y * dt
        self.rotation += self.v_r * dt

    def draw(self):
        screen.blit(pygame.transform.rotate(image,self.rotation),(self.x,self.y))


sqrs = []
for _ in range(5000):
    sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )


def main_loop():
    tick = 0.0
    elapsed = 0.0

    while elapsed < 10.0:
        dt = tick/1000.0
        # Events
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        # Logic
        for s in sqrs:
            s.update(dt)

        # Drawing
        screen.blit(background,(0,0))
        for s in sqrs:
            s.draw()

        pygame.display.update()
        pygame.display.set_caption('test program FPS: %s'%(clock.get_fps() ) )
        tick = clock.tick(FPS)
        elapsed += tick/1000.0
    pygame.quit()

cProfile.run("main_loop()")
i = input("...")

pyglet 版本:

import cProfile
import pyglet, random
# Disable error checking for increased performance
pyglet.options['debug_gl'] = False

from pyglet import clock

clock.set_fps_limit(60)

WINDOWWIDTH = 800
WINDOWHEIGHT = 600
FPS = 60.0

batch = pyglet.graphics.Batch()
window = pyglet.window.Window(WINDOWWIDTH,WINDOWHEIGHT)
fps_display = pyglet.clock.ClockDisplay()

image = pyglet.resource.image("square.png")

class Square(pyglet.sprite.Sprite):
    def __init__(self,x,y):
        pyglet.sprite.Sprite.__init__(self,img = image,batch=batch)
        self.x = x
        self.y = y
        self.v_x = random.randint(1,100)
        self.v_y = random.randint(1,100)
        self.v_r = random.randint(-100,100)

    def update(self,dt):
        if self.x > WINDOWWIDTH:
            self.v_x *= -1
        elif self.x < 0:
            self.v_x *= -1
        if self.y > WINDOWHEIGHT:
            self.v_y *= -1
        elif self.y < 0:
            self.v_y *= -1

        self.x += self.v_x * dt
        self.y += self.v_y * dt
        self.rotation += self.v_r * dt

sqrs = []
for _ in range(5000):
    sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )

elapsed = 0.0

def update(dt):
    global elapsed
    elapsed += dt
    if elapsed >= 10.0:
        clock.unschedule(update)
        window.close()
    else:
        for s in sqrs:
            s.update(dt)

@window.event
def on_draw():
    window.clear()
    batch.draw()
    fps_display.draw()


clock.schedule_interval(update, 1.0/FPS)

if __name__ == '__main__':
    cProfile.run("pyglet.app.run()")
    c = input("...")

pygame 的 cProfile 结果:

         5341607 function calls in 9.429 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    9.429    9.429 <string>:1(<module>)
  1335000    2.259    0.000    2.259    0.000 pygame-test.py:32(update)
  1335000    1.323    0.000    5.969    0.000 pygame-test.py:46(draw)
        1    0.772    0.772    9.429    9.429 pygame-test.py:55(main_loop)
        1    0.000    0.000    9.429    9.429 {built-in method exec}
      267    0.020    0.000    0.020    0.000 {built-in method get}
        1    0.237    0.237    0.237    0.237 {built-in method quit}
  1335000    3.479    0.000    3.479    0.000 {built-in method rotate}
      267    0.013    0.000    0.013    0.000 {built-in method set_caption}
      267    0.067    0.000    0.067    0.000 {built-in method update}
  1335267    1.257    0.000    1.257    0.000 {method 'blit' of 'pygame.Surface' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
      267    0.000    0.000    0.000    0.000 {method 'get_fps' of 'Clock' objects}
      267    0.001    0.000    0.001    0.000 {method 'tick' of 'Clock' objects}

Pyglet cProfile 输出:- 很长,这是部分输出,完整版在这里

         9982775 function calls (9982587 primitive calls) in 10.066 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      123    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1596(_handle_fromlist)
        1    0.000    0.000   10.067   10.067 <string>:1(<module>)
       11    0.000    0.000    0.000    0.000 __init__.py:1055(_ensure_string_data)
       11    0.000    0.000    0.000    0.000 __init__.py:1061(_get_gl_format_and_type)
       58    0.000    0.000    0.000    0.000 __init__.py:1140(clear)
       75    0.000    0.000    0.012    0.000 __init__.py:1148(dispatch_event)
        1    0.000    0.000   10.067   10.067 __init__.py:115(run)
   ...
        1    0.000    0.000    0.000    0.000 lib.py:124(decorate_function)
     1108    0.005    0.000    0.005    0.000 lib_wgl.py:80(__call__)
   285000    1.409    0.000    9.872    0.000 pyglet-test.py:29(update)
       58    0.105    0.002    9.982    0.172 pyglet-test.py:49(update)
   ...
   855000    5.436    0.000    7.551    0.000 sprite.py:378(_update_position)
   285000    0.172    0.000    2.718    0.000 sprite.py:441(_set_x)
   851800    0.177    0.000    0.177    0.000 sprite.py:445(<lambda>)
   285000    0.174    0.000    2.670    0.000 sprite.py:451(_set_y)
   851115    0.155    0.000    0.155    0.000 sprite.py:455(<lambda>)
   285000    0.182    0.000    2.692    0.000 sprite.py:461(_set_rotation)
   285000    0.051    0.000    0.051    0.000 sprite.py:465(<lambda>)
   ...
     4299    0.007    0.000    0.025    0.000 vertexattribute.py:308(get_region)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:380(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:384(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:387(set_pointer)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:461(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:466(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:469(set_pointer)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:501(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:508(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:511(set_pointer)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:293(__init__)
      348    0.000    0.000    0.001    0.000 vertexbuffer.py:311(bind)
      348    0.000    0.000    0.001    0.000 vertexbuffer.py:314(unbind)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:381(__init__)
      348    0.001    0.000    0.004    0.000 vertexbuffer.py:388(bind)
     4299    0.006    0.000    0.016    0.000 vertexbuffer.py:420(get_region)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:424(resize)
     4299    0.002    0.000    0.002    0.000 vertexbuffer.py:460(__init__)
   855232    0.735    0.000    1.053    0.000 vertexbuffer.py:466(invalidate)
   ...
   855058    0.687    0.000    1.762    0.000 vertexdomain.py:581(_get_vertices)
   ...
     4300    0.002    0.000    0.002    0.000 {built-in method POINTER}
   ...
   841451    0.162    0.000    0.162    0.000 {built-in method cos}
   ...
2417/2415    0.000    0.000    0.000    0.000 {built-in method len}
   855489    0.142    0.000    0.142    0.000 {built-in method max}
   855469    0.176    0.000    0.176    0.000 {built-in method min}
  465/407    0.000    0.000    0.000    0.000 {built-in method next}
   ...
   841451    0.072    0.000    0.072    0.000 {built-in method radians}
       62    0.000    0.000    0.000    0.000 {built-in method setattr}
   841451    0.120    0.000    0.120    0.000 {built-in method sin}
   ...
4

2 回答 2

2

瓶颈在于 pyglet sprite 旋转。如果您在 Square update() 方法中注释 'self.rotation' 行,您的 fps 将几乎翻倍。

于 2013-11-06T21:09:26.450 回答
2

Pyglet 图像(和精灵)可以围绕任意锚点旋转。如果您查看pyglet/sprite.py,您会发现这是使用 Python 数学模块完成的,这就是它相当慢的原因。通过使用 OpenGL glRotate 甚至顶点着色器旋转精灵,这里似乎有优化的空间。

于 2013-11-12T12:13:25.397 回答