0

What is the best way to render a mixture point sprites and 3D objects?

Say for example, I wanted to model "space dust" particles as point sprites. In space I could have large asteroid objects (cubes for simplicity) and the space dust particles could be in front of or behind the asteroid cubes.

I am stuck with 2 scenarios:

  1. I render the space dust point sprites first, use gl_DepthMask(GL_TRUE) and then render the asteroid cubes (space dust is always behind the asteroids)
  2. I render the asteroid cubes first, use gl_DepthMask(GL_FALSE), render the space dust point sprites and set gl_DepthMask(GL_TRUE) (space dust always appears in front of the asteroids)

I am currently using a single particle emitter vertex shader that draws a load of particles with gl_DrawArrays() at random (x,y,z) positions.

How can I render a load of particles so that they will appear both in front of and behind the asteroid cubes?

If my particles were individual quads then I could sort the order of Z rendering but I have no idea how to achieve this behaviour using gl_DrawArrays(), GL_POINTs and my vertex shader.

Should I perhaps be splitting up the particles into sets of arrays - for example would I have to do something like this:

  1. draw an array of particles that are behind all asteroids
  2. draw asteroid furthest away
  3. draw another array of particles that appear in front of the above asteroid but behind the next closest asteroid
  4. draw front-most asteroid

If I have a lot of asteroids, wouldn't this be terribly inefficient?

Surely OpenGL has a better way of achieving this than what I am suggesting above?

Update: Trying Thomas' suggestion:

My cube and particles are rendered with the following blend/depth calls:

  // First render opaque object(s)
  glEnable( GL_DEPTH_TEST );
  glDepthMask( true );
  g_ObjCube1.Render();

  // Now render sprites with particle emitter - sprites should appear
  // behind and in front of above cube
  glEnable( GL_POINT_SPRITE );

  // Stop overlapping particles from interfering with each other
  //glDisable( GL_DEPTH_TEST );  <- NO! Must leave depth test enabled
  glDepthMask( false );

  glEnable( GL_BLEND );
  //glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  glBlendFunc( GL_SRC_ALPHA, GL_ONE );    // Doing the same as above
  glBlendEquation( GL_FUNC_ADD );
...
  glDrawArrays( GL_POINTS, 0, NUM_PARTICLES );
...
  glDepthMask( true );
SparkyNZ
  • 6,266
  • 7
  • 39
  • 80

1 Answers1

1

I'm assuming that your particles have some transparency, otherwise there wouldn't be a problem.

And then the answer is the same as for all transparent objects. First render opaque objects (asteroids) first (with depth buffering, in any order). Then render all transparent objects in back-to-front order. This ordering will (as far as I'm aware) need to be done on the CPU.

Alternatively, depending on what effect you're aiming for, you could use additive blending for the particles (glBlendFunc(GL_SRC_ALPHA, GL_ONE)). Then rendering order doesn't matter, because addition is commutative. Be sure to disable depth writing for this one.

As another alternative, using alpha testing (true/false) instead of alpha blending would let you render your particles in any order. Fully transparent pixels don't get written to the depth buffer in this case. When using this technique, you cannot have partially transparent areas though.

This article is a great reference.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • Yes, the particles do have transparency. I'm actually rendering small rounded blobs. I'm really trying to learn how do implement particles in conjunction with other solid objects. If I had comet for example, this would consist of an "asteroid" followed by a tail or particles. If this comet was passing through a stream of asteroids then I'd need to render the comet's tail in front of some asteroids and behind others. If there are thousands of particles making up a gaseous tail, would this really be done on the CPU? Sorry I'm a beginner with all of this. – SparkyNZ Apr 13 '18 at 10:06
  • 1
    Check out https://answers.unity.com/questions/20984/depth-sorting-of-billboard-particles-how-can-i-do.html for example. It's not specific to Unity. Also https://www.gamedev.net/forums/topic/105936-particle-depth-sorting/ and https://blogs.msdn.microsoft.com/shawnhar/2009/02/18/depth-sorting-alpha-blended-objects/. – Thomas Apr 13 '18 at 10:11
  • 1
    Added another possible approach. – Thomas Apr 13 '18 at 10:13
  • Thanks for the links. I will have to do some more reading. I quickly tried your GL_ONE blend suggestion (see update to question) but I'm still getting the same results. At the moment all point sprites are rendering on top of my opaque objects. – SparkyNZ Apr 13 '18 at 10:33
  • 1
    That shouldn't happen. Did you accidentally disable depth _testing_ instead of depth _writing_? – Thomas Apr 13 '18 at 10:34
  • To disable depth writing, I should use glDepthMask( false )? I am also disabling the depth test too. Maybe I shouldn't be touching the depth test. – SparkyNZ Apr 13 '18 at 10:42
  • Now I have the cube appearing in front of the particles when leaving depth test enabled. I need to confirm if any of the particles are in front of the cube because they're still all behind at the moment. – SparkyNZ Apr 13 '18 at 10:44
  • Woohoooooooo :) – Thomas Apr 13 '18 at 10:47
  • That is way simpler than sorting several thousand particles! :) – SparkyNZ Apr 13 '18 at 10:48