Just wanted to say that this does work, and for reference it nets about
40,000 sprites at 60fps on my AMD R9 380 GPU. GPU usage is at about 75-80%
in this case. The efficiency comes from the fact that the only one texture
is in use, and that the bulk of the data is already residing on the GPU.
This number of sprites is far more than you would need in a typical 2D game
or application, but it's just to illustrate what you can get.
The real gotcha when it comes to performance is modifying a sprite's x, y,
rotation, scale, etc. properties. This will cause it's internal vertex list
to be updated, which occurs on the CPU. A common mistake is when trying to
implemnt scrolling in a 2D tiled game, some users will try to update every
sprite's x or y attribute each frame. Instead, it's better to do this on
the GPU with a call to something like glTranslatef. Then, only the
non-static sprite movements will need to be done on the CPU.
On Tuesday, February 7, 2017 at 7:50:47 PM UTC+9, Benjamin Moran wrote:
>
> Here's a quick script-ish snippet that shows how to use the batch and
> resource module. It also illustrates the built-in fps display. This should
> probably work OK, but I can't really test it on my machine at the moment.
>
> import random
> import pyglet
> from pyglet import gl
>
>
> COUNT = 1000
>
>
> window = pyglet.window.Window(width=1000, height=600)
> batch = pyglet.graphics.Batch()
> fps_display = pyglet.clock.ClockDisplay(color=(0.9, 0.0, 0.2, 1.0))
> delta_time_display = pyglet.text.Label(x=12, y=70, font_size=25, color=(255,
> 0, 25, 255))
>
> pyglet.resource.path.append('.')
> pyglet.resource.reindex()
>
> sprites = []
>
>
> def initialize_sprites():
> for i in range(COUNT):
> image = pyglet.resource.image("image100x100.jpeg")
> x = random.randint(0, window.width)
> y = random.randint(0, window.height)
> sprite = pyglet.sprite.Sprite(image, x=x, y=y, batch=batch)
> sprites.append(sprite)
>
>
> def initialize_gl():
> gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,
> gl.GL_NEAREST)
> gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,
> gl.GL_NEAREST)
>
>
> @window.event
> def on_draw():
> window.clear()
> batch.draw()
> fps_display.draw()
> delta_time_display.draw()
>
>
> def update_game(dt):
> delta_time_display.text = "Delta Time: " + str(round(dt, 4))
> # update game stuff here
>
>
> if __name__ == "__main__":
> initialize_sprites()
> initialize_gl()
> pyglet.clock.schedule_interval(update_game, 1/60.0)
> pyglet.app.run()
>
>
>
>
> On Tuesday, February 7, 2017 at 6:57:17 PM UTC+9, Benjamin Moran wrote:
>>
>> Hi Kevin,
>>
>> There are a lot of very inificient things you are doing in your code.
>> Calling the draw() method directly on each sprite is not recommended, since
>> it has to set/unset the OpenGL state for each and every one. What you want
>> to do instead is to create a batch: *batch = pyglet.graphics.Batch*, and
>> pass this into each sprite on creation. Then, you can draw everything
>> together with a single call to *batch.draw()* in your on_draw method. There
>> is a bit of information about Batches in the programming guide, but it does
>> need more detail:
>>
>> http://pyglet.readthedocs.io/en/pyglet-1.2-maintenance/programming_guide/graphics.html#batched-rendering
>>
>> That said, pyglet can easily render thousands of sprites if batched
>> properly.
>>
>>
>> On Tuesday, February 7, 2017 at 12:06:49 PM UTC+9, Kevin S. wrote:
>>>
>>> Hello, I started playing around with Pyglet recently and it was going
>>> fine until I started trying to fill the screen with images. I ended up
>>> with an atrocious frame rate, to the point where user mouse clicks weren't
>>> working properly and animations looked really bad. In order to try to test
>>> the limitations, I created the following test game to see what would happen:
>>>
>>>
>>>
>>>
>>>
>>>
>>> *import randomimport pygletfrom pyglet import gl*
>>> *class Game(object):*
>>> * width = 1000*
>>> * height = 600*
>>> * images = [*
>>> * {"filepath": "image100x100.jpeg", "count": 300}*
>>> * ]*
>>> * background_color = (0.3, 0.3, 0.3, 1)*
>>> * report_interval = 5.0*
>>>
>>> * def start(self):*
>>> * self.pyglet_window = pyglet.window.Window(width=self.width,
>>> height=self.height, vsync=False)*
>>> * self.pyglet_window.event(self.on_draw)*
>>> * self.initializeGL()*
>>> * self.reset_report_timer()*
>>> * self.initialize_sprites()*
>>> * pyglet.clock.schedule_interval(self.tick, 0.01)*
>>> * pyglet.app.run()*
>>>
>>> * def initialize_sprites(self):*
>>> * self.sprites = []*
>>> * for image_set in self.images:*
>>> * filepath = image_set["filepath"]*
>>> * count = image_set["count"]*
>>> * image = pyglet.image.load(filepath)*
>>> * for i in range(count):*
>>> * x, y = random.randint(0, self.width), random.randint(0,
>>> self.height)*
>>> * sprite = pyglet.sprite.Sprite(image, x=x, y=y)*
>>> * self.sprites.append(sprite)*
>>>
>>> * def print_report(self):*
>>> * print "======================="*
>>> * print " Call count: {}".format(self.num_calls)*
>>> * print " FPS: {}".format(self.num_calls / self.report_interval)*
>>>
>>> * def reset_report_timer(self):*
>>> * self.report_timer = 0.0*
>>> * self.num_calls = 0*
>>>
>>> * def initializeGL(self):*
>>> * gl.glEnable(gl.GL_TEXTURE_2D)*
>>> * gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,
>>> gl.GL_NEAREST)*
>>> * gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,
>>> gl.GL_NEAREST)*
>>> * gl.glEnable(gl.GL_BLEND)*
>>> * gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)*
>>> * gl.glPushAttrib(gl.GL_ENABLE_BIT)*
>>>
>>> * def tick(self, seconds_passed):*
>>> * self.num_calls += 1*
>>> * self.report_timer += seconds_passed*
>>> * if self.report_timer >= self.report_interval:*
>>> * self.print_report()*
>>> * self.reset_report_timer()*
>>>
>>>
>>> * def on_draw(self):*
>>> * self.pyglet_window.clear()*
>>> * pyglet.gl.glColor4f(*self.background_color)*
>>> * pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,*
>>> * ('v2i', (0, 0, self.width, 0, self.width, self.height, 0,
>>> self.height))*
>>> * )*
>>> * pyglet.gl.glColor4f(1, 1, 1, 1)*
>>> * self.draw_sprites()*
>>>
>>> * def draw_sprites(self):*
>>> * for sprite in self.sprites:*
>>> * sprite.draw()*
>>>
>>>
>>> *if __name__ == "__main__":*
>>> * game = Game()*
>>> * game.start()*
>>>
>>> I attached the file I used as well. The GL commands I used were
>>> designed to get pixel perfect graphics, and I set them up a long time ago
>>> and don't remember exactly what they do. If you think those are teh
>>> problem please let me know and I will test it out.
>>>
>>> The results were pretty crumby. I found that with 100 images I was
>>> sitting at about 60 fps, with 200 images I went down to 30 fps, with 300
>>> images I was down to 20 fps.
>>>
>>> I wanted to test out some features like the atlas and resource packages,
>>> but I figured I would double check to make sure I am not making any obvious
>>> mistakes here. Can anyone confirm that the limitations I am experiencing
>>> are normal? If not, what can I try to get things working a bit better?
>>>
>>> My specs are:
>>>
>>> - MacBook Pro (15-inch, Mid 2012)
>>> - Processor - 2.6 GHz Intel Core i7
>>> - Memory - 8 GB 1600 MHz DDR3
>>> - Graphics - NVIDIA GeForce GT 650M 1024 MB
>>>
>>>
--
You received this message because you are subscribed to the Google Groups
"pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/d/optout.