Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on a 3d particle emitter. It's going pretty good but I'm still having a problem with triangle sorting.

particle overlap1 particle overlap2

As you can see in the photos, there are some particles that are not blending properly presumably because of sorting. I do sort my quads before I draw them back to front. And they are all being drawn in a single glDrawElements(GL_TRIANGLES... call.

Blending is on & depth buffer is on. Depth buffer has to be on because of the other 3d objects in the scene that are sometimes in front and sometimes behind the particles.

When they're moving in a z space they're sorting better and you don't see it as much:

better particle overlap

I'm using a sort with the following compare:

int compare (const void *a, const void *b) {
   Particle *ia = (Particle*)a;
   Particle *ib = (Particle*)b;

   float t = ib->distanceToCamera - ia->distanceToCamera;
   if (t<0) {
       return -1;
   }
   return (t>0);

}

But I think there are times when some particles have the same z and then they're not blending nicely.

One thought was to somehow force them to not be the same z. But with them moving on their own I'm not sure about that.

QUESTION - if overlapping triangles are close in z space but not equal, and still drawn back to front within the draw command, could they still overlap like this?

ANSWER - I set a break point and printed out all my structures to find that there are a ton of quads in the same z. In groups.

Using the advice from the checked answer I was able to fix it. By making sure to render the solids first and the particles last I don't need to worry about writing to the depth buffer while rendering the particles. In my game they're all like gases, smoke and air. So they all need to blend with each other and on to things deeper in the scene than them. When I start to render the particles I set:

glDepthFunc(GL_LEQUAL);
glDepthMask(GL_FALSE);

And when I'm done rendering them I return it to:

glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);

And look at the result:

Proper blending

What I believe was happening was that as particle triangles were drawn if they were on the same plane they were writing to the depth buffer and then the next one on that z if larger would get masked. By turning off depth mask it doesn't write to the mask as it's drawing the particles so they're not masking each other any more. Since I draw them last they don't need to mask other things.

UPDATE: Another benefit I just figured out. Now I don't have to sort the particles at all. The sort was only to make them draw properly with the depth test on. And that's no longer needed. So I have that savings as well.

share|improve this question
    
An interesting coincidence/digression: Real rockets can over- or under-expand the exiting flow resulting in an interesting visual effect known as mach diamonds. The visible breaks in your 1st two screenshots look somewhat similar to the sharp transitions in photos of mach diamonds. –  NauticalMile Feb 22 at 18:25
    
In the above particle system, when the speed of the particles doesn't vary enough and the birth position doesn't vary enough along the axis of the emitter vector it has been producing that effect. I assume because of a syncopation to the particles. It's been a lot worse than any of these shots actually. It's actually a problem I was trying to solve. But I'm on a deadline and might have to leave it. –  badweasel Feb 24 at 5:25
add comment

1 Answer

up vote 4 down vote accepted

The general rule of thumb when drawing alpha polys is:

1 - Draw all solid polys first.

2 - Sort back to front if you can. The main reason for this is to ensure that the final colour produced by the blending equation is consistent frame to frame. I often don't bother with this step unless it is something provided by the engine and I can justify the extra cost with my own eyes.

I don't think that this is the meat of the solution to your problem in this particular case as it looks like you have polys that are intersecting each other and in this case there is really no perfect way of sorting them bar sorting the individual fragments in a pixel shader or using some other order independent transparency technique (but that is usually massive overkill).

3 - Set the ztest renderstate to less equal or less

4 - Don't write to the z buffer by setting the zwriteenable renderstate to false

I suspect it is this last step that you are missing. You mention needing to have the z buffer turned on so that the alpha polys don't sort incorrectly with the solid but it isn't quite that simple.

You are able to control reading from and writing to the z buffer separately from each other, and in this case you want to read i.e. do the z test so that your polys sort correctly with the existing contents of the z buffer; but you don't want to write. Not writing to the z buffer will result in the next alpha poly essentially ignoring the previous one and you should see the seams disappear.

The downside of this approach is that the colour blending equation now produces slightly incorrect results for some fragments depending on the particular situation but there isn't a straightforward solution to this and generally the results are good enough.

share|improve this answer
    
I am doing 1 and 2. My game could mostly be done with depth buffer off except for these particles which some will be a smoke effect that the ship flies through. And the exhaust particles also need it. I don't understand 3 and 4. I'm in ES 2. I've never heard of those states. –  badweasel Feb 18 at 4:25
    
Well on 2 I'm only sorting the particles but those are what I'm having a problem with. Is there a difference (in terms of depth buffering and blending) between drawing the particle quads one at a time (calling glDrawElements 100 times) and drawing them with a single glDrawElements command? –  badweasel Feb 18 at 4:28
    
I'm not super familiar with any of the variants of GL so I looked this up and my impression is that the GL API obfuscates this a little, well at least IMO with my DX background :) glEnable/Disable(GL_DEPTH_TEST) seems to turn on/off both z testing and z writing. It looks like glDepthMask(false); will turn off just z write. –  Claude Feb 18 at 4:44
    
There shouldn't be a difference between drawing the quads one by one and drawing them as a single draw call. The root of the problem is that some of your fragments are failing the z test when they should be contributing some colour to the scene. –  Claude Feb 18 at 4:50
    
thanks. I did find the glDepthFunc(GL_LEQUAL); which might have helped. I also just printed out all my structures to see and found that many groups of them are on equal z's. Seems if equal though that they should just blend together. It's only if they're behind another structure that I want the fragments masked. I'll also look in to that glDepthMask thing. –  badweasel Feb 18 at 5:02
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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