Vertex Shader Iteration

Started by
11 comments, last by kalle_h 9 years ago

I'm working with OpenGL 3.3 and I got a question about the possibility of updating multiple vertices through the Vertex Shader.
I know you can update a single vertex in a Vertex Shader using transform feedback, but I was wondering could you update multiple vertices at a single time?

Something like:


//Vertex Shader Code
 
in float vertexType;
in vec3 position;
 
out float vertexType;
out vec3 positionOUT;
 
unifomr float modCount;
 
void main()
{
      //Do the following for the next 5 vertex
      if(vertexType == 0)
      {
           vertexTypeOUT = vertexType;
           positionOUT = position;
 
           //Mod the next X number of vertex; X is based on modCount uniform
           for(int i = 0; i < modCount; ++i)
           {
                  //Something like this?
                  vertexTypeOUT[i] = vertexType[i];
                  positionOUT[i] = position[i];
           }
       }
       else
       {
            vertexTypeOUT = vertexType;
            positionOUT = position;
       }
    }
 
}
 
Advertisement

Each vertex shader corresponds to only one vertex. It's not possible to update multiple vertices in a single shader.

What is it you're trying to do exactly?

What is it you're trying to do exactly?

So I'm in the midst of trying to create a particle emitter and it is working (particles update and show up on screen) biggrin.png

It works by using transform feedback, where the each particle (GL_POINTS) is updated through the vertex shader and the results of the update get written to a buffer object. This buffer object is then bound at render time as a Texture Buffer, so I can expand my points into a quads without the use of Geometry Shader.

I now I want to add in the ability to spawn X particles every Y seconds

I was thinking that on the first run of the vertex shader I could run through X number of vertices, reactivate them (basically resetting their life time), and then finish this first run by updating the first vertex. After (next and subsequent runs) I could continue on like normal and just update the particle

Could you do something like that with a Compute Shader?

Could you do something like that with a Compute Shader?

I don't think I can use a Compute Shader here, because I need to target OpenGL 3.3

So is there absolutely no way I can do this?

Does your target support OpenCL?

https://software.intel.com/en-us/articles/opencl-and-opengl-interoperability-tutorial?language=it

I would really like to stick to OpenGL only

I have been thinking of ways that I could achieve what I'm trying to do and I wanted to know everyone's thoughts on them

Now, I'm strictly talking about the update side of things here as the rendering part is taken care of.

Conditions

1. Ability to generate X particles every Y seconds

2. Lots and lots of particles. Have as many as I can

3. Particles have textures and attributes like position, lifetime, size, etc

Idea 1

Use a pass through Vertex Shader with a Geometry Shader. Where the Geometry Shader takes in GL_POINTS and spits back out GL_POINTS. In this case the Geometry Shader would be the one responsible for updating the particles. (Might be faster to update in Vertex Shader and then check if I need to discard in the Geometry Shader. Thoughts?) In addition it only generates new particles through the EmitVertex and EndPrimative calls when the generation time has been hit

Pros:

Should be able to allow me to do what I want

Particles "die" and "are created" on the fly

Cons:

Have to use a Geometry shader sad.png

Only can emit out MAX_GEOMETRY_OUTPUT_VERTICES (For me this is 1024, lowest it must be is 32)

[Might be able to get past above. Could do multiple updates. If I need to use more than the MAX_GEOMETRY_OUTPUT_VERTICES just write into another part of the buffer or a different buffer all together]

Idea 2

Create all the particles that I would ever need and keep a copy of my particles on the CPU side.

When it comes time to "generate" particles, check which particles are "dead" and reset there lifetime using glBufferSubData on the whole buffer (since I dont think multiple glBufferSubData for "dead" particles only would be good). Then afterwards, my buffer gets sent to the Vertex Shader where they get updated. After the update in the Vertex Shader, I save the results back into my CPU's particle copy

Pros:

Should be able to allow me to do what I want

Should be able to have as many particles as my hardware can handle

Cons:

Might be super slow since I'm pretty sure I need to read back / save the transform feedback buffer

The more particles I have the slower it gets

Idea 3

Keep everything as it is and have a global counter to reset the lifetimes of dead particles. When the Vertex Shader runs, check if the "generate particles" flag has been set to true. If so, then revive the particles that are dead and repeat this until counter has met the "number to revive count". Continue on updating the particles

Pros:

Should be able to allow me to do what I want

Should be able to have as many particles as my hardware can handle

Cons:

I don't think this (a global counter) is possible with the current version of OpenGL I am targeting?

Why not move the updating code to a fragment shader which renders to a texture, then use vertex texture fetch for the positions.
Then next frame you bind the previous frame's particle framebuffer as a texture and render the data to a second framebuffer, then use vertex texture fetch and draw,
then next frame bind second framebuffer as the texture and use the first as the render target and repeat. Basically, ping-pong the particle data between the two framebuffers.

This post describes what I mean in detail, as you can see, the performance isn't too bad either http://www.hackbarth-gfx.com/2013/03/17/making-of-1-million-particles/

Might be super slow since I'm pretty sure I need to read back / save the transform feedback buffer

The more particles I have the slower it gets

if you create particle's vertex buffer as not static (dynamic), it will couse it to render not that fast, but per frame updates to it (not realocating its size of course), should come totaly acceptable. Try it out, it is no big hit at all to render a dynamic render buffer, and batched subdata calls to it are of no big issue as well.

a hint:

update the buffer while it is still yet bound after the draw call that has used it (being a frame back thus), move on next gpu issue

if you create particle's vertex buffer as not static (dynamic), it will couse it to render not that fast, but per frame updates to it (not realocating its size of course), should come totaly acceptable. Try it out, it is no big hit at all to render a dynamic render buffer, and batched subdata calls to it are of no big issue as well.
a hint:
update the buffer while it is still yet bound after the draw call that has used it (being a frame back thus), move on next gpu issue

I went back and tried this out (the idea you were referencing) and its super slow

I did a minor test with 10k particles (each particle has 6 attribute each) and its the actual particle update portion that makes the hit to performance. Having to read back from the GPU every frame to keep particles in sync is really rough. At best, on a good, run I'd get a DT of 0.00105 (~950 FPS)

I changed it up to use a pass through Geometry Shader along with a bind to the previous TBO used (done to get psudo random values to use when particles are to be revived) and the performance sky rocketed! I was getting a DT of 0.000606 (~1650 FPS)

This topic is closed to new replies.

Advertisement