layers performance

Asked by tobs12

Hello,

to render an isometric map I have to define the order when the single blocks are drawed.
E.g. the blocks on the top of the screen have to be drawn first, and the blocks on the bottom of the screen have to be drawn last. see http://imageshack.us/a/img850/8130/blocksexample.png
So I have to use a lot of layers, i.e. one per horizontal row of blocks.
But this seems to have low performance.

------------------------------------
glcommon/base.py:
    def doTasks(self, target=None):
...
            for layer in self.layers:
                for ref in self.shaders.iterkeyrefs():
                    if ref():
                        shader = ref()
                        shader.doTasks(layer=layer, target=target)
------------------------------------

This looks like the complexity is O(n^2). The other doTasks functions look similar.
Wouldn't it be possible to speed this up, if you had one list of shader (or whatever) per layer, something like:

------------------------------------
glcommon/base.py:
    def doTasks(self, target=None):
            for layer in self.layers:
                for ref in self.shaders_of_layer[layer].iterkeyrefs():
                    if ref():
                        shader = ref()
                        shader.doTasks(layer=layer, target=target)
------------------------------------

Question information

Language:
English Edit question
Status:
Answered
For:
PyGL3Display Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
David Griffin (habilain) said :
#1

Hmm. I'll look into it. I believe that the implementation is O(n), but having had a second look I'm not 100% sure. One thing that I'd just bear in mind is that the inner loop (number of Shader objects) is going to be, for all intents and purposes, a constant.

However, the simple fact of the matter is that no matter how it's done, having a lot of seperate layers is slow. OpenGL is fast when you can batch everything up into arrays. If that can't be done, OpenGL gets slow.

So... ways it could be fixed. makeAdjacentSprites might help (see Platformer) - it returns a list of sprites with order guaranteed, but are all on the same layer. Of course, moving a sprite through the map might be problematic then.

Cheating might also be an option, and rendering combinations of isometric tiles into 2d tiles.

Finally, wait until I implement OrderedSprites, which have been on my roadmap for a while now. These are Sprites which have a Z coordinate which governs order, and all render on the same layer. However this needs some work on internals, which is also tied up with sprite buffers.

Revision history for this message
tobs12 (hans1215) said :
#2

Hello,
thanks for your reply.
You could order the sprites before giving the array to opengl.
The order is more or less static. I don't know when the array has to be transfered to opengl, but probably you could keep an ordered list (e.g. as binary tree) and insert/remove into that when sprites are added/deleted.
For a nearly static map, sprite only need to be added/removed if the map is scrolled.
Probably the idea of OrderedSprite might solve this.

Revision history for this message
David Griffin (habilain) said :
#3

Well, as I said before, getting a bunch of sprites with a guaranteed order can be accomplished with makeAdjacentSprites. But I suspect that for the functionality you need, OrderedSprites will be necessary. I'm reluctant to expose stuff like the OpenGL array because the point of PyGL3Display is to be easy, and the OpenGL array is pretty tricky stuff.

As to adding/removing sprites if the map is being scrolled: almost certainly not necessary. OpenGL will automatically drop stuff which is drawn outside the window boundaries, so I'd just set up every background sprite for a given map and then not care about them. Given that the cost of creating/deleting sprites is quite high, this would be the best performing option.

An AVL Tree would be a decent data structure for sorting the OrderedSprites, but there's an odd caveat here: Python is slow, C is fast. So it might be faster to use list.sort rather than a Python implementation of an AVL tree.

Revision history for this message
Launchpad Janitor (janitor) said :
#4

This question was expired because it remained in the 'Open' state without activity for the last 15 days.

Revision history for this message
David Griffin (habilain) said :
#5

Right, marking this as answered because I've done my tests and decided on a concrete plan of action. It isn't implemented yet (part of the initial changes has caused some major bugs elsewhere), but this is the plan.

All two-d things will be upgraded to have an optional Z coordinate. These optional Z-coordinates will only be relevant if the two-d thing is created as part of an OrderedGroup. OrderedGroups do *not* provide fast performance for adding/removing stuff (although I'll try to get speed as fast as I can..). OrderedGroups interact with layers by the user supplying the Z-ranges of each layer. As the OrderedGroup keeps items sorted in the OpenGL array, changing Z-ranges is a quick operation.

Hence usage for a character moving through an isometric background would be to have the ordered group have two layers, one representing stuff to be drawn before character, one after. The character is assigned to a layer inbetween these two, and hence stuff will be drawn before and after the character correctly.

Timescale for implementation is tricky, because I'm very busy at the moment.

Can you help with this problem?

Provide an answer of your own, or ask tobs12 for more information if necessary.

To post a message you must log in.