我希望升级使用Python库" Pygame"它基于SDL 1 C ++库,使用更现代的OpenGL代码。我有一个简单的Pygame程序,它绘制了2000个矩形:
import pygame
import random
import time
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rectangle():
'''Draw a rectangle'''
def __init__(self):
'''These are the rectangle's attributes.'''
self.x = 0
self.y = 0
self.width = 0
self.height = 0
self.change_x = 0
self.change_y = 0
self.color = [0, 0, 0]
def draw(self, screen):
'''Drawing the rectangle.'''
pygame.draw.rect(screen, self.color, [self.x, self.y, self.width, self.height])
def move(self):
'''Moving the rectangle around the screen.'''
self.x += self.change_x
self.y += self.change_y
def main():
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
my_list = []
color_list = []
'''Creates 1000 rectangles.'''
for i in range(2000):
my_object = Rectangle()
r = random.randrange(256)
g = random.randrange(256)
b = random.randrange(256)
my_object.color = [r, g, b]
color_list.append(my_object)
my_object.x = random.randrange(701)
my_object.y = random.randrange(501)
my_object.change_x = random.randrange(-3, 4)
my_object.change_y = random.randrange(-3, 4)
my_object.width = random.randrange(20, 71)
my_object.height = random.randrange(20, 71)
my_list.append(my_object)
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
# Start the clock
start = time.time()
for item in my_list:
item.draw(screen)
item.move()
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# End the clock
elapsed = time.time() - start
print(elapsed)
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
main()
在我的电脑上绘制每一帧大约需要0.012秒。
我还有一个使用Python Pyglet库来访问OpenGL的程序。我正在使用顶点缓冲区加快速度。这是代码:
"""
This example uses OpenGL via Pyglet and draws
a bunch of rectangles on the screen.
"""
import random
import time
import pyglet.gl as GL
import pyglet
import ctypes
# Set up the constants
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
RECT_WIDTH = 50
RECT_HEIGHT = 50
class VertexBuffer():
""" Class to hold vertex buffer info. """
def __init__(self, vbo_id, size, width, height, color):
self.vbo_id = vbo_id
self.size = size
self.width = width
self.height = height
self.color = color
def create_rect(width, height, color):
""" Create a vertex buffer for a rectangle. """
v2f = [-width / 2, -height / 2,
width / 2, -height / 2,
width / 2, height / 2,
-width / 2, height / 2]
vbo_id = GL.GLuint()
GL.glGenBuffers(1, ctypes.pointer(vbo_id))
data2 = (GL.GLfloat*len(v2f))(*v2f)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id)
GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
shape = VertexBuffer(vbo_id, len(v2f)//2, width, height, color)
return shape
def render_rect_filled(shape, x, y):
""" Render the shape at the right spot. """
# Set color
GL.glDisable(GL.GL_BLEND)
GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, shape.vbo_id)
GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0)
GL.glLoadIdentity()
GL.glTranslatef(x + shape.width / 2, y + shape.height / 2, 0)
GL.glDrawArrays(GL.GL_QUADS, 0, shape.size)
class Rectangle():
def __init__(self, x, y, width, height, delta_x, delta_y, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.delta_x = delta_x
self.delta_y = delta_y
self.color = color
self.vbo = create_rect(self.width, self.height, self.color)
def move(self):
self.x += self.delta_x
self.y += self.delta_y
def draw(self):
render_rect_filled(self.vbo, self.x, self.y)
class MyApplication():
""" Main application class. """
def setup(self):
""" Set up the game and initialize the variables. """
# Set background to white
GL.glClearColor(1, 1, 1, 1)
self.shape_list = []
for i in range(2000):
x = random.randrange(0, SCREEN_WIDTH)
y = random.randrange(0, SCREEN_HEIGHT)
width = random.randrange(20, 71)
height = random.randrange(20, 71)
d_x = random.randrange(-3, 4)
d_y = random.randrange(-3, 4)
red = random.randrange(256)
green = random.randrange(256)
blue = random.randrange(256)
alpha = random.randrange(256)
shape_type = random.randrange(2)
shape = Rectangle(x, y, width, height, d_x, d_y, (red, green, blue))
self.shape_list.append(shape)
def animate(self, dt):
""" Move everything """
for shape in self.shape_list:
shape.move()
def on_draw(self):
"""
Render the screen.
"""
start = time.time()
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
for shape in self.shape_list:
shape.draw()
elapsed = time.time() - start
print(elapsed)
def main():
window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
app = MyApplication()
app.setup()
pyglet.clock.schedule_interval(app.animate, 1/60)
@window.event
def on_draw():
window.clear()
app.on_draw()
pyglet.app.run()
main()
OpenGL代码绘制每帧需要0.056秒。我希望我能更接近Pygame的表现。甚至更好。我可以采用哪些OpenGL技巧来加快速度?
答案 0 :(得分:0)
好的,根据我从Reddit学到的东西,我可以做两件事来加快速度。
而不是2,000个VBO,使用一个。这是一个更快的例子:
"""
This example uses OpenGL via Pyglet and draws
a bunch of rectangles on the screen.
"""
import random
import time
import pyglet.gl as GL
import pyglet
import ctypes
# Set up the constants
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
RECT_WIDTH = 50
RECT_HEIGHT = 50
def render_rect_filled(shape, offset):
""" Render the shape at the right spot. """
# Set color
GL.glLoadIdentity()
GL.glColor3ub(shape.color[0], shape.color[1], shape.color[2])
GL.glTranslatef(shape.x + shape.width / 2, shape.y + shape.height / 2, 0)
GL.glDrawArrays(GL.GL_QUADS, offset, 4)
class Rectangle():
def __init__(self, x, y, width, height, delta_x, delta_y, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.delta_x = delta_x
self.delta_y = delta_y
self.color = color
def move(self):
self.x += self.delta_x
self.y += self.delta_y
def create_rects(rect_list):
""" Create a vertex buffer for a set of rectangles. """
v2f = []
for shape in rect_list:
v2f.extend ([-shape.width / 2, -shape.height / 2,
shape.width / 2, -shape.height / 2,
shape.width / 2, shape.height / 2,
-shape.width / 2, shape.height / 2])
vbo_id = GL.GLuint()
GL.glGenBuffers(1, ctypes.pointer(vbo_id))
data2 = (GL.GLfloat*len(v2f))(*v2f)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id)
GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
return vbo_id
class MyApplication():
""" Main application class. """
def setup(self):
""" Set up the game and initialize the variables. """
# Set background to white
GL.glClearColor(1, 1, 1, 1)
self.shape_list = []
for i in range(2000):
x = random.randrange(0, SCREEN_WIDTH)
y = random.randrange(0, SCREEN_HEIGHT)
width = random.randrange(20, 71)
height = random.randrange(20, 71)
d_x = random.randrange(-3, 4)
d_y = random.randrange(-3, 4)
red = random.randrange(256)
green = random.randrange(256)
blue = random.randrange(256)
alpha = random.randrange(256)
shape_type = random.randrange(2)
shape = Rectangle(x, y, width, height, d_x, d_y, (red, green, blue))
self.shape_list.append(shape)
self.vertex_vbo_id = create_rects(self.shape_list)
def animate(self, dt):
""" Move everything """
for shape in self.shape_list:
shape.move()
def on_draw(self):
"""
Render the screen.
"""
start = time.time()
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
GL.glDisable(GL.GL_BLEND)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vertex_vbo_id)
GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0)
offset = 0
for shape in self.shape_list:
render_rect_filled(shape, offset)
offset += 4
elapsed = time.time() - start
print(elapsed)
def main():
window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
app = MyApplication()
app.setup()
pyglet.clock.schedule_interval(app.animate, 1/60)
@window.event
def on_draw():
window.clear()
app.on_draw()
pyglet.app.run()
main()
此外,您可以将VBO用于颜色。这使用了VBO,甚至更快:
"""
This example uses OpenGL via Pyglet and draws
a bunch of rectangles on the screen.
"""
import random
import time
import pyglet.gl as GL
import pyglet
import ctypes
# Set up the constants
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
RECT_WIDTH = 50
RECT_HEIGHT = 50
def create_rect(width, height, color):
""" Create a vertex buffer for a rectangle. """
v2f = [-width / 2, -height / 2,
width / 2, -height / 2,
width / 2, height / 2,
-width / 2, height / 2]
vbo_id = GL.GLuint()
GL.glGenBuffers(1, ctypes.pointer(vbo_id))
data2 = (GL.GLfloat*len(v2f))(*v2f)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id)
GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
shape = VertexBuffer(vbo_id, len(v2f)//2, width, height, color)
return shape
def render_rect_filled(shape, offset):
""" Render the shape at the right spot. """
# Set color
GL.glLoadIdentity()
#GL.glColor4ub(shape.color[0], shape.color[1], shape.color[2], 255)
GL.glTranslatef(shape.x + shape.width / 2, shape.y + shape.height / 2, 0)
GL.glDrawArrays(GL.GL_QUADS, offset, 4)
class Rectangle():
def __init__(self, x, y, width, height, delta_x, delta_y, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.delta_x = delta_x
self.delta_y = delta_y
self.color = color
def move(self):
self.x += self.delta_x
self.y += self.delta_y
def create_rects(rect_list):
""" Create a vertex buffer for a set of rectangles. """
v2f = []
for shape in rect_list:
v2f.extend ([-shape.width / 2, -shape.height / 2,
shape.width / 2, -shape.height / 2,
shape.width / 2, shape.height / 2,
-shape.width / 2, shape.height / 2])
vbo_id = GL.GLuint()
GL.glGenBuffers(1, ctypes.pointer(vbo_id))
data2 = (GL.GLfloat*len(v2f))(*v2f)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id)
GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
return vbo_id
def create_colors(rect_list):
""" Create a vertex buffer for a set of rectangles. """
v2f = []
for shape in rect_list:
for i in range(4):
v2f.extend(shape.color)
vbo_id = GL.GLuint()
GL.glGenBuffers(1, ctypes.pointer(vbo_id))
data2 = (GL.GLfloat*len(v2f))(*v2f)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo_id)
GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(data2), data2, GL.GL_STATIC_DRAW)
return vbo_id
class MyApplication():
""" Main application class. """
def setup(self):
""" Set up the game and initialize the variables. """
# Set background to white
GL.glClearColor(1, 1, 1, 1)
self.shape_list = []
for i in range(2000):
x = random.randrange(0, SCREEN_WIDTH)
y = random.randrange(0, SCREEN_HEIGHT)
width = random.randrange(20, 71)
height = random.randrange(20, 71)
d_x = random.randrange(-3, 4)
d_y = random.randrange(-3, 4)
red = random.random()
green = random.random()
blue = random.random()
shape = Rectangle(x, y, width, height, d_x, d_y, (red, green, blue))
self.shape_list.append(shape)
self.vertex_vbo_id = create_rects(self.shape_list)
self.color_vbo_id = create_colors(self.shape_list)
def animate(self, dt):
""" Move everything """
for shape in self.shape_list:
shape.move()
def on_draw(self):
"""
Render the screen.
"""
start = time.time()
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glDisable(GL.GL_BLEND)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vertex_vbo_id)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
GL.glVertexPointer(2, GL.GL_FLOAT, 0, 0)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.color_vbo_id)
GL.glEnableClientState(GL.GL_COLOR_ARRAY)
GL.glColorPointer(3, GL.GL_FLOAT, 0, 0)
offset = 0
for shape in self.shape_list:
render_rect_filled(shape, offset)
offset += 4
elapsed = time.time() - start
print(elapsed)
def main():
window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
app = MyApplication()
app.setup()
pyglet.clock.schedule_interval(app.animate, 1/60)
@window.event
def on_draw():
window.clear()
app.on_draw()
pyglet.app.run()
main()