2
\$\begingroup\$

I'm interested to know how others would do / have done this.

Part 1. Constraints.

My current renderer is being built to support OpenGL ES 2.0 primarily and so aims for performant mobile as well as desktop. Separate render paths for mobile and desktop are avoided for simplicity's sake, so I'm discussing a single, unified ES 2.0 render path here, minimally targeting devices that support glDrawInstanced().

I have different categories of renderables. Terrain chunks, for example, are fully opaque and with the depth buffer turned on, can be rendered in any order. So far, so good. Foliage OTOH consists of semi-transparent objects suited to alpha testing / discard given a desktop GPU.

But because of the mobile requirement, alpha testing is not an option - see impacts of alpha testing / discard on graphics pipeline for mobile GPUs like the PowerVR SGX series: source, and source.

Part 2. Approach.

As a result, I must fall back to alpha blending and the painter's algorithm for transparent objects. So it seems there are two sort-categories of renderables, to be rendered separately and in this order:

  1. solid objects: no explicit sorting (or front-to-back for optimised z-reject), depth buffer write on
  2. transparent objects: back-to-front sort, depth buffer write off

(could there be more of these?)

Given this, I now wish to sort my display lists as efficiently as possible by minimising GL API calls. To this end, it seems best to:

  1. order the display list primarily by sort-category (as 1 & 2 above),
  2. (within same sort-category) order secondarily by similar material and thus shader program,
  3. (within same material-bucket) order tertiarily by similar mesh / vertex data.

And then of course render everything.

This way if we have same sort-category, same material, and same mesh on each of two objects, glDrawInstanced() becomes a viable option to combine those two objects into a single draw call, and even if not, we've (hopefully) minimised the number of context changes that need occur.

Does the proposed render order 1-2-3 sound right? If not, explain differently, and justify.

\$\endgroup\$
  • \$\begingroup\$ Seems mostly good. Just one thing - sort solid objects front-to-back. Saves on pixel shading/fill rate. \$\endgroup\$ – snake5 Oct 16 '15 at 18:26
  • \$\begingroup\$ @snake5 - thanks and yes - I forgot this detail - agreed about rejecting deeper fragments as early as possible by rendering opaques front to back. \$\endgroup\$ – Engineer Oct 16 '15 at 18:28
  • \$\begingroup\$ This looks consistent with game engines I've worked with. Are you finding any bottlenecks or problems with this approach? \$\endgroup\$ – DMGregory Oct 17 '15 at 2:53
  • \$\begingroup\$ @DMGregory OK good; and no - I'm checking to see how others would address this before I refactor this aspect. Think I'm going to carry on with this today though and see how it goes; further comments & answers still welcome though, particularly if to the contrary of what's been outlined above. \$\endgroup\$ – Engineer Oct 17 '15 at 10:02
  • \$\begingroup\$ once upon a time i found that doing nth element by screenspace size rather than a proper sort front-to-back was beneficial for solid, non transparent objects. i didn't really understand (it seems when thinking about it that front-to-back should give maximum effect from early z-culling) but measuring it proved that it was a valid approach. i'd recommend to try this and measure it and see if its faster... it might not be, but if it is you get a win. :) \$\endgroup\$ – jheriko Nov 6 '15 at 0:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.