Use buffer from compute shader in vertex shader

Hello,
I’m trying to improve the performances of my particle system by doing the calculation of particles movement in a compute shader. So I created a computeShader class which is basically a modified version of the ofShader class to load the compute shader. This part is ok.
I have a buffer in the compute shader to contain the positions of my particles.
Now I’d like to access this buffer in my vertex shader to render the particles.
I have seen 2 examples on the internet that I tried to reproduce but it doesn’t work.

Here is my ofApp.h:

#pragma once

#include "ofMain.h"

#include "computeShader.h"

struct Particle{
    ofVec4f currPos;    
};

class ofApp : public ofBaseApp{

    int n;

    computeShader compShader;
    ofShader renderShader;

    GLuint particlesBufferID;

    public:
        void setup();
        void update();
        void draw();    
};

ofApp.cpp:

#include "ofApp.h"

void ofApp::setup(){
    n = 500;

    compShader.load("shaders/particle.compute");
    renderShader.load("shaders/particle.vert", "shaders/particle.frag");

    glGenBuffers(1, &particlesBufferID);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, particlesBufferID);
    glBufferData(GL_SHADER_STORAGE_BUFFER, n*sizeof(Particle), NULL ,GL_STATIC_DRAW);

    if(glGetError() != GL_NO_ERROR){
        ofLogError() << "Could not generate or bind shader storage buffer for particles";
    }
    
    struct Particle* particles;
    
    try{
        particles = (struct Particle*) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, n*sizeof(Particle), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
    }
    catch(std::runtime_error e){
        ofLogError() << e.what();
    }
    if(glGetError() != GL_NO_ERROR || particles == NULL){
        ofLogError() << "Could not map the shader storage buffer for particles";
    }

    for(int i = 0; i < n; ++i){
        particles[i].currPos.x = i*10.0;
        particles[i].currPos.y = i*10.0;
        particles[i].currPos.z = 0.0;
        particles[i].currPos.w = 1.0;
    }
    
    if(glUnmapBuffer(GL_SHADER_STORAGE_BUFFER) == GL_FALSE){
        ofLogError() << "Could not unmap the shader storage buffer for particles";
    }
}

void ofApp::update(){

}

void ofApp::draw(){
    ofBackground(ofColor::black);

    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, particlesBufferID);
    
    compShader.begin();
        glDispatchCompute(1, 1, 1);
        glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
    compShader.end();

    renderShader.begin();
        glBindBuffer(GL_ARRAY_BUFFER, particlesBufferID);
        glVertexPointer( 4, GL_FLOAT, 0, (void *)0 );
        glEnableClientState( GL_VERTEX_ARRAY );
        glDrawArrays( GL_POINTS, 0, n );
        glDisableClientState( GL_VERTEX_ARRAY );
        glBindBuffer( GL_ARRAY_BUFFER, 0 );
    renderShader.end();
}

particle.compute:

#version 430
#extension GL_ARB_compute_shader : enable
#extension GL_ARB_shader_storage_buffer_object : enable

struct Particle{
    vec4 currPos;
};

layout(std140, binding=4) buffer particles{
    Particle p[];
};

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

void main(){
}

particle.vert:

#version 430

in vec4 pos;

void main(void){
    gl_Position = pos;
}

particle.frag:

#version 430

out vec4 outputColor;

void main(){
    outputColor = vec4(1.0, 1.0, 1.0, 1.0);
}

What am I missing?

what version of openframeworks are you using? compute shaders won’t work in any of the official versions, they should with master as long as you use a version of opengl that has support for computer shaders using:

ofSetOpenGLVersion(4,4)

for example before calling ofSetupOpenGL

Ok I wasn’t using the right version of OpenGL, thank you. But it still doesn’t work, and I don’t really know how to debug this.

also in openGL 3+ you can’t send vertices like that, you need to create a VAO and bind the particle buffer to a certain shader attribute, pos in your case, something like:

in setup:

glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
glBindBuffer(GL_ARRAY_BUFFER,particlesBufferID);
glEnableVertexAttribArray(renderShader.getAttributeLocation("pos"));
glVertexAttribPointer(renderShader.getAttributeLocation("pos"), 4, GL_FLOAT, GL_FALSE, sizeof(Particle), 0);
glBindVertexArray(0);

and then in draw:

renderShader.begin();
glBindVertexArray(vaoID);
glDrawArrays(GL_POINTS,0,particles.size());
renderShader.end();
1 Like

Great, it works perfectly!
Thanks a lot!