Using a toy compute shader to generate points

I’m working on my very first compute shader and I want to use it generate points as part of a larger project but I seem to be missing something.

How do I make everything play nice?

This is my compute shader code (after specifying version 450):

struct point {
    vec3 p;
    float padding;
    vec4 c;
};

layout(std140, binding=4) buffer particlebuffer{
      point pt[];
};

void main() {
     int index = int(gl_GlobalInvocationID);
     pt[index].p = vec3(index/50,index/50,index/50);
     pt[index].c = vec4(1.0, 0.0, 0.0, 1.0);
}

I read somewhere that the compute shader works best with structs that contain padding.)

I also have a vertex and fragment shader that I have tested on actual points, called shaderProgram. I know that shaderProgram works well with my mvp matrix.

Here’s my vertex shader:

uniform mat4 mvp;

layout (location = 0) in vec3 position;

in vec4 color;
out vec4 vertcolor;

void main()
{
    gl_Position = mvp * vec4(position, 1.0f);
    endcolor = color;
}

And here’s my frag shader:

    in vec4 vertcolor;
    out vec4 finalcolor;
    void main()
    {
        finalcolor = vertcolor;
    }

My shaders compile with no issues. After reading this post on using compute shader buffer data in vertex shader, I wrote the following code to initialize a GL_SHADER_STORAGE_BUFFER to hold the generated points, as well as a VAO to receive these points:

glGenBuffers(1, &particlebuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, particlebuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * numparticles, &particlebuffer, GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, particlebuffer);

glUseProgram(compShaderProgram);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);

glUseProgram(shaderProgram);
glGenVertexArrays(1, &computeVAO);
glBindBuffer(GL_ARRAY_BUFFER, particlebuffer)

positionLoc = glGetUniformLocation(shaderProgram, "position");
glEnableVertexAttribArray(positionLoc);
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0);

colorLoc = glGetUniformLocation(shaderProgram, "color");
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (GLvoid *)16);

glBindVertexArray(0);

And then I have this in my draw loop:

glUseProgram(shaderProgram);
glBindVertexArray(computeVAO);
glDrawArrays(GL_POINTS, 0, numparticles);
glBindVertexArray(0);

I’m fairly new to OpenGL - any help and/or suggestions would be greatly appreciated

Hey @jacques,

I’m not sure what’s wrong with your code. Are you calling glDispatchCompute (https://www.opengl.org/wiki/Compute_Shader#Dispatch) to run your compute shader? You should probably set a local size in shader if you want to see the benefits of using a compute shader.
Also I don’t think you need to make the buffers using the gl API directly, as oF 0.9.0 introduced a ofBufferObject that lets you do just that.

This is in the examples of the oF repo:

https://github.com/openframeworks/openFrameworks/tree/master/examples/gl/computeShaderParticlesExample

You can also look at that one, which is a bit simpler:

https://github.com/elaye/particleSystemCS

Good luck!

Hi @Elaye,

Thanks for getting back to me!

So I set a local size in my compurte shader before my main loop:
layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in;

And after reading this response, I adjusted my point struct and made according adjustments in my frag and vert shaders:
struct point {
vec4 p;
vec4 c;
};

But still no points!

Is there anything that I should change? And is my glDispatchCompute set correctly? Currently, it’s at (1,1,1) and I’ve tried other combinations as well.

Could it be something wrong with my glVertexAttribPointer functions?

Hi everyone, I think I figured it out:

No separate VAO was required for me to draw my points - all I needed to do was this in my draw loop:

// use the compute shader
glUseProgram(compShaderProgram);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, particlebuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * numparticles, &particlebuffer, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, particlebuffer);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);

// use the vertex and fragment shaders
glUseProgram(shaderProgram);
GLuint positionLoc = glGetAttribLocation(shaderProgram, "position");
glBindBuffer(GL_ARRAY_BUFFER, particlebuffer);
glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0);
glEnableVertexAttribArray(positionLoc);
glDrawArrays(GL_POINTS, 0, 1024);
    
// unbind everything
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);	`

And then I also had to change my compute shader’s main loop to this:

layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in;
void main () {
int x_index = int(gl_GlobalInvocationID.x);
int y_index = int(gl_GlobalInvocationID.y);

// do work on each pt
pt[x_index].p = vec4(x_index/1000.0, y_index/1000.0, 1.0, 1.0);
pt[x_index].c = vec4(1., 0., 0., 1.);
}

I do still have a question though: within my compute shader I am able to get and use values from gl_GlobalInvocationID.x but am unable to get non-zero values from gl_GlobalInvocationID.y so I was wondering if anyone had any experience with dealing with this problem. When I change the local_size_x and local_size_y I get all sorts of weird values. I’m trying to create a grid of points but I get nothing but a straight line on the x-axis!

figured it out:

int index = x_index + (32 * y_index);
pt[index].p = vec4(x_index/1000. - .5, y_index / 1000. - .5, 1.0, 1.0);
pt[index].c = vec4(1., 0., 0., 1.);

Wooohooo!