Feedback on a pyglet with pymunk tutorial I'm starting

49 views
Skip to first unread message

elliot

unread,
May 14, 2013, 7:50:45 PM5/14/13
to pyglet...@googlegroups.com
Hello,

I wrote the first part of a tutorial on integrating pyglet, pymunk, Numpy and OpenCV.  Any feedback would be appreciated. 


-videos-
 

In case you don't end up reading it but have some insight, the bottleneck in my code right now is translating the dynamic vertices and updating batches.  I have 300+ polygons that are updated every frame, having their vertices rotated and translated.  This runs at 60 fps on my not so great laptop.  Am I doing the best I can?

The update function is only this:

    def translate(self):
        px,py = self.body.position
        theta = self.body.angle
        initiald = self.initial_data
        cost, sint = cos(theta), sin(theta)
        #Just a bunch of multiplication and addition, optimized
        pts = [(px+x+r*(xhelper*(cost-1)-sint*yhelper),py+y+r*(yhelper*(cost-1)+sint*xhelper)) for x,y,r,xhelper,yhelper in initiald]
        #flatten and assign as tuple to batch vertices
        self.vertlist.vertices = tuple(map(int,[val for subl in pts for val in subl]))
 

 ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.019    0.019   49.193   49.193 poly_demo.py:1(<module>)
      ...
     1911    0.035    0.000   44.047    0.023 poly_demo.py:122(on_draw)
     1911    3.940    0.002   42.308    0.022 entities.py:12(step)
   620979    2.838    0.000   37.946    0.000 entities.py:268(update)

So this function takes up 86% of my run time.  The second to last line takes up 2/3 of that, and the last line 1/3.


Thanks everyone,
Elliot

Matt Ebb

unread,
May 14, 2013, 8:41:01 PM5/14/13
to pyglet...@googlegroups.com
How many of those Convex objects are you instantiating, and how many points are in each object? In general it'll be more efficient to larger amounts of geometry at the same time, rather than small amounts of geometry lots of times. By the looks of your video, it's the latter case, i.e. lots of objects with a small number of points each.

The bottleneck in this sort of thing is often the openGL calls - communicating with the graphics card. On every update, it's changing the contents of the vertex buffer once for every object. If you're using a lot of objects, that's a lot of openGL calls. It's much better to structure it so you can update the transformations of all your polygons at once, then send it all to the graphics card in one call. As a quick fix in your code, you could try appending all your Convex object's vertex tuples to another 'global' list at update time, then add it to a single vertex list once per update.

cheers

Matt



--
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 pyglet-users...@googlegroups.com.
To post to this group, send email to pyglet...@googlegroups.com.
Visit this group at http://groups.google.com/group/pyglet-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

elliot

unread,
May 15, 2013, 1:14:47 AM5/15/13
to pyglet...@googlegroups.com
You are right, lots of objects with few vertices.  I figured what you said was the case.  So, should I aggregate a huge list of triangle strip vertices and push it to the batch all at once?  By push I mean assign the vertices directly, not using delete() and add(). I would need to set a flag if any objects are created or destroyed, because then my number of vertices will change and I will have to delete() and add(). Well, I could turn destroyed polygons into degenerate vertices, and only delete()/add() on new vertices being added. But then I worry that if I create this list then I have to update the color and/or texture vertices for each polygon as well.  Or somehow keep the vertices in order so they don't float around on top of the color/textures.

This is my first thought:

    global vertexlist
    verts = []
    
    if not new:     #the 'new' flag is set by space.add when a new polygon was added to the space 
      for ob in l:
        verts.append(ob.translate())   #translate returns degenerate vertices if ob is dead
      self.vertexlist.vertices = tuple(verts)

    else:
      cverts = []   #for colors
      tverts = []   #for textures.  I dont use texture verts now, will this work?
      for ob in l:    
        verts.append(ob.translate())
        cverts.append(ob.colorverts)
        tverts.append(ob.textureverts)
      vertexlist.delete()
      vertexlist = Batch(len(verts)//2,GL_TRIANGLE_STRIP,None,('v2i/dynamic',verts),('c3b',cverts),(however textures are))

Thanks.  This seems reasonable.  I'll give it a shot.  If this is helpful then I think I can tighten it up further.

Anna Mária Nagy

unread,
May 15, 2013, 3:06:58 AM5/15/13
to pyglet...@googlegroups.com

Greg Ewing

unread,
May 15, 2013, 9:52:22 PM5/15/13
to pyglet...@googlegroups.com
> On Wed, May 15, 2013 at 9:50 AM, elliot <offonoff...@gmail.com
> <mailto:offonoff...@gmail.com>> wrote:
>
> This runs at 60
> fps on my not so great laptop. Am I doing the best I can?
>
> | def translate(self):
...
> pts = [(px+x+r*(xhelper*(cost-1)-sint*yhelper),py+y+r*(yhelper*(cost-1)+sint*xhelper)) for x,y,r,xhelper,yhelper in initiald]
> #flatten and assign as tuple to batch vertices
> self.vertlist.vertices = tuple(map(int,[val for subl in pts for val in subl]))

Depending on how many vertices you're processing per call to this function,
you might benefit from using NumPy to do these transformations.

--
Greg

elliot

unread,
May 16, 2013, 11:07:31 AM5/16/13
to pyglet...@googlegroups.com
@matt

I did a quick refactor to build a list of vertices and then touch the batch only after all the objects are updated.  I got very minimal performance gain.  I spend less time in _set_vertices but more time in the extend method of List and in other places.  I need to analyze the profile data more.  The old way was as fast as it could be and this new way probably has more room for improvement, but since I don't have textures and animations implemented yet, I'm going to leave it as it was which was more straight forward.

@greg

Its not very many vertices so numpy would't help.  If I could collect the data from all the polygons (center, theta, vertices and helper data) in one huge array, there could be some gain perhaps.  But building that array would be just as inefficient as updating the the polygons one at a time.

Thanks everyone.  Once I implement textures and animations, and know all the issues related to that, then I'll come back to this question of rendering efficiency.

-Elliot
Reply all
Reply to author
Forward
0 new messages