0
\$\begingroup\$

Sorting transparent objects is a well-known problem. If you send a bunch of transparent polygons (e. g. leaves and branches on a tree) into the GPU and render them with alpha blending enabled, the GPU will sort the polygons randomly.

But what I noticed is that although they get sorted randomly, the order of rendering is always the same. If it wasn't the leaves would flicker as their colors change, depending on which layer they are on.

How can I control which polygons get rendered when? Maybe their order depends on the index buffer?

[EDIT] To clarify things: I know that different Draw() calls execute precisely in the order they were issued. I am trying to figure out how to manipulate the polygon order inside a single Draw() call. If a tree has a hundred polygons it is a waste do draw evey single one separately and a pain in the artists'... behind. So what I need is to influence the order of rendering for a bunch of polygons in a single pair vertex and index buffers.

Yes and I am working with XNA 4.0.

\$\endgroup\$
  • \$\begingroup\$ "Sorted randomly" makes me smile. You cannot sort something without rules, at which point it is not really what you would call "random" anymore. Not that it ever was, the GPU is required to merge the final output in an order consistent with the input (FIFO). Some GPUs do fancy things under the hood that involve exploiting characteristics of drawn geometry (e.g. PowerVR's deferred tile renderer or Hierarchical Z-Buffering in general) but that really only works for opaque geometry and it does not affect anything that you can realistically measure other than performance. \$\endgroup\$ – Andon M. Coleman Apr 24 '14 at 1:27
  • \$\begingroup\$ Well, Andon, I did not know that :). As simple as that. I thought parallel computations result in a random outcome :). But, could you expand upon the "PowerVR deferred tile renderer" part? \$\endgroup\$ – cubrman Apr 24 '14 at 5:13
  • \$\begingroup\$ I would suggest you look up TBDR, it is too much work to explain in comments ;) \$\endgroup\$ – Andon M. Coleman Apr 24 '14 at 5:21
3
\$\begingroup\$

Your premise is incorrect.

If you send a bunch of transparent polygons (or anything else) to the GPU to be rendered, the GPU will draw them in precisely the order you defined them -- it will not sort them at all.

The way you control which polygons get rendered first is to send them to the GPU first; either by putting them first in the index buffer (if you're using one), or by putting them earlier in the vertex buffer (if you're using one), or putting them in an earlier draw operation.

\$\endgroup\$
  • \$\begingroup\$ So if I am sending N polygons to the GPU in a SINGLE Draw() call they will get rendered in the order of them standing in the vertex/index buffer? I did not know that. I totally thought that every vertex is processed in parallel as well as every rasterized pixel (after ALL the vertex shaders were done). Where can I read about it in detail? \$\endgroup\$ – cubrman Apr 23 '14 at 10:03
  • 1
    \$\begingroup\$ @cubrman The vertices, pixels, and fragments do get processed in parallel, but only insofar as the results are exactly the same as if they'd been processed one after another. There isn't really any documentation about this (that I'm aware of), since each GPU manufacturer is likely to do it differently. The important point is that from our point of view as graphics coders, things behave as if they rendered from start to end, as you provided them. (even if that's not precisely what actually happens under the hood) \$\endgroup\$ – Trevor Powell Apr 23 '14 at 12:37
  • \$\begingroup\$ Right, so the device might choose to do it completely differently to optimize your call. One thing I wondered was that if what you say is true, then why does Draw() calls with the clip(-1) function in the pixel shader and opaque blending end up much more expensive than the same opaque calls without it. Now I see that the GPU might choose not to process every single polygon/pixel, but if it has no choice but to render them all, it will obay the vertex/index buffer order when outputing the colors. That is a very important info for me, thank you very much! \$\endgroup\$ – cubrman Apr 23 '14 at 12:51
  • \$\begingroup\$ Yes, with alpha blending disabled, HLSL's clip() function (like GLSL's discard statement) allows you to return an empty bit of data which causes the GPU to suddenly realise that it needs to rasterise triangles which it thought were completely occluded. Depending on the driver, you might incur this cost just on pixels which actually get clipped, or for absolutely everything drawn using a shader which contains these instructions (even if the clip doesn't actually happen). You really can't rely on how the driver's going to handle these things, so performance tuning can be very challenging. \$\endgroup\$ – Trevor Powell Apr 23 '14 at 13:10
  • \$\begingroup\$ I even noticed that just setting alpha value of the pixel to 0 with alpha blending enabled is faster than using clip. Clip is indeed a very costly function. Also, the speed difference you mentioned is, in my opinion, somehow related to the way the GPU handles conditional logic in shaders. I use a conditional loop in my shader, which is a heavy blow for old GPU and a walk in the park for the new ones. \$\endgroup\$ – cubrman Apr 23 '14 at 13:18
1
\$\begingroup\$

The order in which they are drawn is deterministic. The GPU will not randomly decide which polygon to draw. The order is controlled by the order you supply the draw calls in and the order of the indices in the index buffer.

Often you will want to manually sort your polygons and then send them as a batch to the GPU. I do not know which framework you're using so unfortunately I cannot give you any more tips there. But I usually add a parameter to my draw calls that I later use to sort them. Though I've never had to sort individual polygons in a model before.

You can also separate the model into two. One with the entire tree excluding the leaves, and one with only the leaves and then draw them separately. The extra benefit of this is that you can use a different shader for the leaves. For example you can use this to tint the leaves depending on seasons.

\$\endgroup\$
  • \$\begingroup\$ I edited the question \$\endgroup\$ – cubrman Apr 23 '14 at 10:00
  • \$\begingroup\$ Naturally I will use different shaders for the trunk and leaves. The trunk will get rendered as an opaque object, while the leaves (which is the main point of the question) must be sorted properly, when rendered in a single Draw() call with a different (translusent) shader. \$\endgroup\$ – cubrman Apr 23 '14 at 10:06

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.