I'm looking for good-practice tips for a simple and light weight renderer that I can build upon over time, as I'm in the process of learning OpenGL ES2 and simultaneously, I'm looking to completely overhaul my extremely flawed ES1 Render Manager at every level of its logic.
My ES1 engine is a 2D sprite system, whereby each game-object owns its own vertex and UV set (two triangles), and is then syphoned each frame into batching sets to minimize GPU state changes per frame. No VBO/VAOs. complete 100% vertex/UV upload per frame - which doesn't feel totally wasted since nearly everything moves independently and constantly anyway (in my last game). The Render Manager takes a set of objects that were grouped based on compatible render attributes, and then makes the state changes, builds the vertex/uv array, and fires the call. Definitely a lot of superflous stuff happening, but it wasn't broken so I left it alone and finished my game.
I never actually benchmarked for comparison whether the batched method was even actually faster or not than rendering each sprite's triangles on their own and making hundreds of render instructions instead of 10 or so. Everything was in spritesheets so the number of calls was always very low.
It worked ok, I got enough performance (on iPhone).. but I've seen way, way better, and am not at all surprised
So I'd really love to get some general architecture advice from people that have tackled all this stuff before me.
There's some key things I'm wondering like:
- In a 2D game, say side on - sprite based, if I have a lot of objects coming in and out of existence, and in and out of view, constantly moving/rotating/scaling, what's the best way to manage all the data that eventually has to make its way to OpenGL? Unlike rendering large meshes, it just makes me question whether batching is actually the correct approach.
- Is dynamically building a complete vertex stack each frame (and submitting it to OpenGL) throwing a lot fo performance away? If so, what are some better techniques?
- Is there a known rule of thumb for some number of vertices at which point batching becomes essential? Was it a waste of time to even worry about when my vertex count would have theoretically always probably maxed at about 3000? (1000 triangles / 500 draw calls)? Keeping in mind that my target platform is mobile where performance is significantly more important than desktop.
There's so much good information on how to do individual specific tasks in OpenGL, but very little content that I've ever been able to find regarding good architecture practices.
I'm not creating middleware, so I don't need something all-purpose where every base is covered, I really just want to create a simple renderer that adheres to techniques that are known to be generally sound.
One idea I had - and this would be keeping similar with my existing ES1 setup:
Make a RenderLayer class, where one "layer" essentially corresponds to one shader, or a subset of settings. Each frame, as the engine iterates the game objects, it submits their vertices/uvs to that layer's stack. At the end of the update cycle, the render layers are supplied to the Render Manager to fire off the (hopefully batched) calls. Without a depth buffer (which to me seems wasted in 2D), this imposes layering restrictions that can cause difficulties at a visual design level though.
Also without knowing the needed stack size of any given layer in advance, I guess I would set a max object count and pre-allocate a chunk of memory.
I would love to have some better ideas though. I am fully prepared for the likelihood that everything I've just said sounds ludicrous
I'm sure it must be evident that I'm very much still learning a great deal in OpenGL.
If you've read this far, then I say thank you already!