5

I'm working on a particle system using the compute shader right now. I put all my particles in a shader-storage-buffer. A particle contains two vertices, the current position and the previous position.

struct Particle{
    glm::vec4   _currPosition;
    glm::vec4   _prevPosition;
};

After I dispatch my compute shader I want to draw all the particles directly from the shader-storage-buffer. So this is what I do:

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBufferID);
_shaderManager->useProgram("computeProg");
glDispatchCompute((_numParticles/WORK_GROUP_SIZE)+1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
_shaderManager->useProgram("shaderProg");
glBindBuffer(GL_ARRAY_BUFFER, shaderStorageBufferID);
glVertexPointer(4,GL_FLOAT, sizeof(glm::vec4), (GLvoid*)0);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, _numParticles);
glDisableClientState(GL_VERTEX_ARRAY);

The problem is that I see _numParticles on the screen but one half is rendered with the _prevPosition attribute of my particle structure. That means one particle is interpreted as two vertices which are drawn on the screen. But I want him to skip the _prevPosition attribute in every particle structure. Where's my mistake?

Maybe the way I initialize my shader-storage-buffer is important:

GLuint shaderStorageBufferID;

glGenBuffers(1, &shaderStorageBufferID);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBufferID);
glBufferData(GL_SHADER_STORAGE_BUFFER, numParticles*sizeof(Particle), NULL ,GL_STATIC_DRAW);
struct Particle* particles = (struct Particle*) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, numParticles*sizeof(Particle), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
for(int i = 0; i < numParticles; ++i){
    particles[i]._currPosition = glm::vec4(i, 0, 0.0, 1.0f);
    particles[i]._prevPosition = glm::vec4(i, 0, 1.0, 1.0f);
}
Stan
  • 721
  • 10
  • 24
  • Your code is an astonishing collection of modern OpenGL and legacy OpenGL. How is it that you're advanced enough to use compute shaders and have some understanding of memory sync issues (you're still using the wrong barrier, BTW. Just because your code happens to function doesn't mean that it's guaranteed to do so), yet you use an outdated function like `glVertexPointer`? – Nicol Bolas Oct 05 '12 at 20:28
  • I worked a little bit with DirectX 11 in the past and programmed a particle system which also used the compute shader there. But now I want to switch to OpenGL. So this is my first project with this API which I just started last week. Therefore I still have to learn many things. :) Since there is no really useful documentation or useful tutorial which covers every detail about the compute shader I used this example and there glVertexPointer has been used. http://education.siggraph.org/media/conference/S2012_Materials/ComputeShader_6pp.pdf – Stan Oct 05 '12 at 21:33

1 Answers1

8

Your Particle struct contains two vec4's. Your compute shader writes two vec4s per array element.

Yet this line:

glVertexPointer(4,GL_FLOAT, sizeof(glm::vec4), (GLvoid*)0);

Tells OpenGL that you're passing an array of vec4s. You're not. You're passing an array, where every element is two vec4s. And you want to skip the second one.

So tell OpenGL that, by providing a proper stride:

glVertexPointer(4, GL_FLOAT, sizeof(Particle), (GLvoid*)0);

Oh, and BTW: you're still using the wrong barrier. Just because your code happens to function doesn't mean that it's guaranteed. Unsynchronized load/store operations can be tricky unless you're doing everything correctly.

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Oh my dear! I think I should take more breaks! Thank you, everything is working fine now. Sorry for bothering you with such a banality. – Stan Oct 05 '12 at 21:37