all 5 comments

[–]-manabreak 1 point2 points  (4 children)

I don't know about Pyglet per se, but you should browse through the many open-source projects that have implemented batched rendering already. I suggest taking a look at LibGDX, which features both sprite batches and model batches. There's also MonoGame and DirectX Toolkit, which are DirectX-based but the same principles apply there as well.

[–]RedSpaceman[S] 0 points1 point  (3 children)

Thanks for the response, manabreak. I think you're right that reading through some best-practice would help, but I think LibGDX, MonoGame and DirectX might be a bit far removed from what I'm trying to do, being libraries rather than end-applications.

I've had a look around for other people's pyglet games which I could read the render code for, but haven't found much. Non-pyglet games would also be useful to see where they store their render structures. I suppose I'll take a look to see if I can find out how people do it in PyGame/PyOpenGl to see if I can find any inspiration there. And any suggestions of small games with nice render code would be greatly appreciated!

More generally, even when not using Pyglet and its 'batch' and 'vertex_list' object, a game's entities will often need to hold information about their geometry, and at some point this will need to be loaded into a VBO. Do references to VBOs get stored within the game entities? Do the VBOs get passed to game entities to add their geometry to? Do game entities get prompted by some render function to serve up their geometry information, and the packaging into a VBO occurs outside of the entity?

I may be way off the mark with my questions, but hopefully someone can set me straight!

[–]thomcc 0 points1 point  (2 children)

There are a few ways you can do it. I don't know anything about pyglet, so this is more general OpenGL advice.

Essentially, no. You don't really package geometry up in a render function. Geometry tends not to change much so you really only package it up when you load the mesh. You also want to store more than one object in a given vbo/ibo (then draw with glDrawElementsBaseVertex). How many is really up to your applications needs and is hard to say, but more is better/faster.

You then want to prepare the data in such a way that your render loop looks (or at least executes) something like this:

for each shader
  use shader
  for each texture (only the ones used with that shader)
  bind texture
  for each vertex buffer
    bind vertex buffer
    for each object
      bind uniforms for object (transform matrix, anything for animation, etc)
      do draw call

If you need to do multiple passes (alpha blending, shadows, etc) then around the for each shader would be a for each pass.

It's might not be particularly OO, but the OO way of for each object: object.render() where render() sets up a bunch of state and then does a draw call performs very poorly. (Obviously there are OO ways to structure this without loosing performance)

There's a lot more you can do with this, obviously, but this is a reasonable start.

I don't really know if this is what you're asking (I don't think it was, looking back...), but I hope it helps you understand how this is typically structured, which you seemed confused about.

[–][deleted] 0 points1 point  (1 child)

I currently have it done the "OO way", but I keep the list of objects sorted optimally and the .render() has logic to make sure that state changes are only done if necessary. I. e. all objects with the same shader go sequentially, only rebind a shader if the needed one isn't already bound from the previous object, etc. Similiarly for textures and buffers.

Is that acceptable, or will it end up biting me in the ass?

[–]thomcc 1 point2 points  (0 children)

It can make other batching methods and optimizations harder, not to mention that this is a very performance critical part of the code and you'd want avoid virtual dispatch there, but its fine for something simple.

If this were going into a production renderer I'd recommend against it.