[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Python - Pygame - PyOpenGL performance

That's called a texture atlas, but be careful with the mipmaps. They
usually have to be generated specially I think.


On Mon, Mar 16, 2009 at 1:49 PM, Zack Schilling
<zack.schilling@xxxxxxxxx> wrote:
> If someone did this and I could drop it in to my code, that would be very
> nice. But for right now, PyOpenGL is serving my needs just fine. I can use
> about 600 independently textured and animated sprites onscreen, scaled and
> rotated, without stressing a low-end system more than 40%.
> 40% is a significant amount of overhead, but Peter is wrong of a few points.
> You certainly can animate a sprite in OpenGL using texture coords. Just load
> all your animation frames, convert to strings, stick them all together, and
> pass to OpenGL as one very tall texture. This works perfectly fine. That
> means VBOs are definitely suitable. You can also push a VBO up piecemeal,
> changing the active texture between parts (and achieving the expected
> effect).
> Everything you see here is done with pygame and PyOpenGL:
> http://www.youtube.com/watch?v=cBFoXqKrBa8
> Positioning the quads directly doesn't seem to be too much of an issue,
> since in my game, they move each frame anyway. The cost of adding
> coordinates in Python and pushing them into a numpy array is much less than
> an OpenGL push, translate/rotate, pop call for each and every sprite. It
> makes a lot of sense to me that this would be the case in other languages as
> well.
> -Zack
> On Mar 16, 2009, at 1:00 PM, Forrest Voight wrote:
>> Would writing a replacement for PyOpenGL in C instead of in Python
>> with ctypes help? I think it really would ... PyOpenGL is internally
>> pretty complex, sometimes when I get tracebacks the error is 5 or 6
>> levels into PyOpenGL. Even a C library that only implemented the
>> common functions and relied on PyOpenGL for the constants and
>> functions that do complex things like handling strings would probably
>> help a lot.
>> On Fri, Feb 27, 2009 at 11:19 AM, Peter Gebauer
>> <peter.gebauer@xxxxxxxxxxxxxxxxxxxxx> wrote:
>>> Hi!
>>> I've done a few sprite thingies in OpenGL here are some pointers:
>>> Afaik display lists and VBO's can't bind different textures (?)
>>> per list/array. You can't animate lists by changing texcoords
>>> independently per element, so no go. VBO's have texture coords,
>>> but only one texture. Again, I'm no expert, might be wrong.
>>> With the quad aproach you should try
>>> to make the number of calls as few as possible. If you get
>>> rid of the push and translate for each sprite you'll get some
>>> extra speed. Try positioning each quads directly. The downside
>>> with sharing matrix over all sprites is the obvious lack of
>>> using OpenGL transformations, but some vector math aplied to
>>> the quads has been faster for me than having one transformed
>>> matrix per quad.
>>> Since I haven't been able to animate a list/vbo with independent
>>> textures and texture coords for each element/buffer object I've only
>>> used it for backdrops. The speed increase is tremendous.
>>> I also partition the elements so only one list/vbo is displayed per
>>> visible section, if you're screen display is smaller than the
>>> entire scene, this helps even more.
>>> If you put all your sprites and their animation frames into one
>>> big texture you could use VBO's, but I've never had the tenacity
>>> to try that aproach.
>>> Another way to increase speed is to write an opengl rendering engine
>>> in C and call and make it available as a Python extension. This is
>>> a major speed boost, in particular for a large number of iterations.
>>> Iirc PyOpenGL bindings are generated, many times this is suboptimal
>>> code for what you're trying to do, writing the Python extension in C
>>> manually have been faster for me many times. This is indeed true
>>> if you put your iterations inside a C loop instead of calling the
>>> C function from Python many times.
>>> In any case, still waiting for that OO 2D game engine with tons of
>>> OpenGL features and effects, including simple things like frame
>>> animation,
>>> LERP-like features and a simple 2D scenegraph. No luck yet, all attempts
>>> I've tried so far lack at least one "must have" feature. :)
>>> /Peter
>>> On 2009-02-26 (Thu) 11:29, Casey Duncan wrote:
>>>> Immediate mode calls (glVertex et al) are the very slowest way to use
>>>> OpenGL. In fact they are deprecated in OpenGL 3.0 and will eventually be
>>>> removed.
>>>> The display list is better as you discovered, but you still are making a
>>>> few OpenGL state changes per sprite, which is likely slowing you down.
>>>> Also there is some overhead for the display list call, which makes them
>>>> sub-optimal for just drawing a single quad.
>>>>>       glPushMatrix()
>>>>>       glTranslate(self.positionx,self.positiony,0)
>>>>>       glCallList(self.displist)
>>>>>       glPopMatrix()
>>>> You really need to batch the quads up into a few vertex arrays or vbos
>>>> to stream them to the card in one go. pyglet has a high-level python
>>>> sprite api that automates this for you fwiw.
>>>> -Casey
>>>> On Feb 26, 2009, at 11:04 AM, Zack Schilling wrote:
>>>>> I know the PyOpenGL mailing list might be a better place to ask this
>>>>> question, but I've had a lot of luck talking to the experienced people
>>>>> here so I figured I'd try it first.
>>>>> I'm trying to migrate a game I created from using the Pygame / SDL
>>>>> software rendering to OpenGL. Before attempting the massive and
>>>>> complex conversion involved with moving the whole game, I decided to
>>>>> make a little test program while I learned OpenGL.
>>>>> In this test, I set up OpenGL to work in 2D and began loading images
>>>>> into texture objects and drawing textured quads as sprites. I created a
>>>>> little glSprite class to handle the drawing and translation. At first
>>>>> its draw routine looked like this:
>>>>>       glPushMatrix()
>>>>>       glTranslate(self.positionx,self.positiony,0)
>>>>>       glBindTexture(GL_TEXTURE_2D, self.texture)
>>>>>       glBegin(GL_QUADS)
>>>>>       glTexCoord2f(0, 1)
>>>>>       glVertex2f(0, 0)
>>>>>       glTexCoord2f(1, 1)
>>>>>       glVertex2f(w, 0)
>>>>>       glTexCoord2f(1, 0)
>>>>>       glVertex2f(w, h)
>>>>>       glTexCoord2f(0, 0)
>>>>>       glVertex2f(0, h)
>>>>>       glEnd()
>>>>>       glPopMatrix()
>>>>> Note: self.texture is a texture ID of a loaded OpenGL texture object.
>>>>> My sprite class keeps a dictionary cache and only loads the sprite's
>>>>> image into a texture if it needs to.
>>>>> I'd get maybe 200 identical sprites (same texture) onscreen and my CPU
>>>>> would hit 100% load from Python execution. I looked into what could be
>>>>> causing this and found out that it's probably function call overhead.
>>>>> That's 14 external library function calls per sprite draw.
>>>>> The next thing I tried was to create a display list at each sprite's
>>>>> initialization. Then my code looked like this:
>>>>>       glPushMatrix()
>>>>>       glTranslate(self.positionx,self.positiony,0)
>>>>>       glCallList(self.displist)
>>>>>       glPopMatrix()
>>>>> Well, that's nice, down to 4 calls per draw. I was able to push ~500
>>>>> sprites per frame using this method before the CPU tapped out. I need
>>>>> more speed than this. My game logic uses 30-40% of the CPU alone and
>>>>> I'd like to push at least 1000 sprites. What can I do? I've looked into
>>>>> passing sprites as a matrix with vertex arrays, but forming a proper
>>>>> vertex array with numpy can sometimes be more trouble than it's worth.
>>>>> Plus, I can't swap out textures easily mid-draw, so it makes things
>>>>> much more complex than the simple way I'm doing things now.
>>>>> Is there any design pattern I could follow that will get me more speed
>>>>> without sending me off the deep end with complexity.
>>>>> Thanks,
>>>>> Zack