Can't apply shader to an ofFbo, the result is just blank

Here’s my setup. I first run a compute shader and a render shader on a bunch of particles and render them to an ofFbo, and it works just fine. I can draw the texture and the result is clearly there.

But the problem arises when I want to apply a simple (horizontal) blur shader to the fbo I got in the previous step.

Here’s how I do it (I omitted some details):

void ofApp::setup() {

	particles.setup(10000); // all the shader stuff regarding particles is inside the particles object
	blurShader.load("shaders/blur.vert", "shaders/blur.frag"); // the shader that's causing me problems

	layer.allocate(ofGetWidth(), ofGetHeight());
}

void ofApp::draw() {
	layer.begin();
	ofBackgroundGradient(ofColor(0, 0, 255), ofColor(70, 100, 255));
	particles.draw();
	layer.end(); // this works fine. If I draw this it look good

	blurShader.begin(); // problem begins
	blurShader.setUniform1f("blurAmnt", 6.);
	layer.draw(0, 0);
	blurShader.end();
}

If I remove the “blurShader” lines it works perfectly, but if I want to apply the shader the result all blank.
The blur shader program (vert/frag) I got from the examples and they look like this:

blur.vert

#version 150

// these are for the programmable pipeline system
uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;

in vec4 position;
in vec2 texcoord;
in vec4 normal;
in vec4 color;

out vec2 texCoordVarying;

void main()
{
    #ifdef INTEL_CARD
    color = vec4(1.0); // for intel HD cards
    normal = vec4(1.0); // for intel HD cards
    #endif

    texCoordVarying = texcoord;
	gl_Position = modelViewProjectionMatrix * position;
}

blur.frag

#version 150

uniform sampler2DRect tex0;
uniform float blurAmnt;

in vec2 texCoordVarying;
out vec4 outputColor;

// Gaussian weights from http://dev.theomader.com/gaussian-kernel-calculator/

void main()
{

    vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
	
	color += 0.000229 * texture(tex0, texCoordVarying + vec2(blurAmnt * -4.0, 0.0));
	color += 0.005977 * texture(tex0, texCoordVarying + vec2(blurAmnt * -3.0, 0.0));
	color += 0.060598 * texture(tex0, texCoordVarying + vec2(blurAmnt * -2.0, 0.0));
	color += 0.241732 * texture(tex0, texCoordVarying + vec2(blurAmnt * -1.0, 0.0));
    
	color += 0.382928 * texture(tex0, texCoordVarying + vec2(0.0, 0));
	
	color += 0.241732 * texture(tex0, texCoordVarying + vec2(blurAmnt * 1.0, 0.0));
	color += 0.060598 * texture(tex0, texCoordVarying + vec2(blurAmnt * 2.0, 0.0));
	color += 0.005977 * texture(tex0, texCoordVarying + vec2(blurAmnt * 3.0, 0.0));
	color += 0.000229 * texture(tex0, texCoordVarying + vec2(blurAmnt * 4.0, 0.0));
    
    outputColor = color;
}

I think the problem might be the fact that I call these lines in the particles draw program

ofEnablePointSprites();
ofDisableArbTex();
ofEnableAlphaBlending();

and I tried disabling/enabling all kinds of things, changed the opengl settings int main.cpp, etc., but nothing seems to work, and I can’t figure out what’s exactly the problem.

Thanks in advance for any help.

Have you tried to change your draw code like this:

    layer.begin();
    blurShader.begin();
    ...
    ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight());
    blurShader.end();
    layer.end();
   layer.draw(0,0);

That doesn’t seem to help unfortunately.

From a quick glance, it looks like your shader needs at least OpenGL 3.0. Are you sure you’re App is not running on OpenGL 2.1 (which is the default i think).

Also, any errors in the console when the shader is being loaded/compiled?

Right, you might want to try something like :

ofGLWindowSettings settings;
settings.setGLVersion(3,2);
ofCreateWindow(settings);

in the main, before ofRunApp.

Yes definitely check main.cpp like DarkSalmon and marco_v suggest; I forget to do this all the time until a dark screen reminds me about it. Also I like to do all of the updating of the ofFbo (drawing, shaders, multiple passes, etc) in ofApp::update(), and then just draw the fully updated ofFbo in ofApp::draw().

Also can the ofDisableArbTex() call be omitted? You are using a sampler2DRect in the shader, and so you’ll want arbitrary texture sizes. ofDisableArbTex() pairs nicely with the sampler2D type, and also sends normalized texcoord to the vertex shader if I remember right. So, if you do need to call it, then don’t forget to ofEnableArbTex() before the ofFbo runs thru the shader.

@DarkSalmon

I tried that, and that seems to solve the problem with the blur shader, but then my particles dissapear, none of them are visible…
I now also tried version 4.6 (since it seems that’s what I have installed), and it produces the same results. I can see the blur shader working, but the particles are missing… How come they were rendering properly before? What could be an explanation?

Here’s my particles shader setup code:

	ofEnableAlphaBlending();
	ofEnablePointSprites();
	ofDisableArbTex();

	ofLoadImage(imgTexture, "cursor.png");
	particlesBuffer.allocate(particles, GL_DYNAMIC_DRAW);
	vbo.setVertexBuffer(particlesBuffer, 4, sizeof(Particle));
	particlesBuffer.bindBase(GL_SHADER_STORAGE_BUFFER, 0);
	computeShader.setupShaderFromFile(GL_COMPUTE_SHADER, "shaders/cursor.comp");
	computeShader.linkProgram();

	renderShader.load("shaders/cursor.vert", "shaders/cursor.frag");

and the shaders

// cursor.frag
uniform sampler2D texture0;

void main () {
    vec2 xy = gl_TexCoord[0].st;
    xy = vec2(xy.x, 1. - xy.y);
    vec4 color = texture2D(texture0, xy);
    gl_FragColor = vec4(color);
}

// cursor.vert
void main() {
    gl_Position   = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_PointSize  = 30.0;
    gl_FrontColor = gl_Color;
}


// cursor.comp
#version 430

#define EPS 0.001

uniform vec2 resolution;
uniform vec2 attractor;
uniform float strength;
uniform float drag;

struct Particle{
	vec4 pos;
	vec4 vel;
	vec4 acc;
};

layout(std430, binding=0) buffer particles{
	Particle p[];
};

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

void main(){
	uint gid = gl_GlobalInvocationID.x;
	.....
	p[gid].pos.xy += p[gid].vel.xy;
}

It all worked fine when I set up OF with ofSetupOpenGL(1024,768,OF_WINDOW); instead of settings.setGLVersion(3,2); (but in that case blur didn’t work properly).

@TimChi

Thanks for the tip about ofFbo’s, this is literally my first day working with OF (being a long time Processing user), it’s just better for shader stuff, but I obviously need to set it up properly first.

ofDisableArbTex() unfortunately needs to stay because that’s the only way I could give the particles their own image texture.

A peek at the gpuParticleSystemExample might be helpful. It uses geometry shaders instead of compute, but it might be somewhat similar (?), at least in concept. There are different strategies for using the gpu with a particle system. Some of the other projects in the /examples/gl/ folder (computShaderParticlesExample) might be helpful too. Wish I could be of more help with this!

Ok I think the problem is definitely in the rendering part of the particles. The compute shader works perfectly and if I render them without my shader (with just using ofSetColor() and glPointSize()) I can see the particles. The problem arises when I try to use a custom shader, which looks fine to me…
vert

uniform sampler2D tex0;

void main () {
    vec2 xy = gl_TexCoord[0].st;
    xy = vec2(xy.x, 1. - xy.y);
    vec4 color = texture(tex0, xy);
    
    gl_FragColor = vec4(color);
}

frag

#version 150

uniform mat4 modelViewProjectionMatrix;

in vec4 position;

void main(){
	gl_Position = modelViewProjectionMatrix * position;
	gl_PointSize = 50.0;
}

	ofEnableAlphaBlending();
	ofEnablePointSprites();

	renderShader.begin();
	imgTexture.bind();
	vbo.draw(GL_POINTS, 0, n);
	imgTexture.unbind();
	renderShader.end();

Yes, a peek a the whole ofApp.h / .cpp would be nice, I suspect it to be a binding issue on texture though. While I usually suspect synchronization issues with CS, data bandwidth is quite low here so that’s probably not it.

As a side note, you can also load your compute shader with loadCompute.

Okay, I’ll clean up the code and push it to github in a moment.

And thanks for the tip!

You might just have forgotten enablePointSprites ?

In the gpuParticleSystemExample, the geometry shader takes vertices (particles), and emits a set of texcoords for each one (6 per vertex), which are then used to draw (or bind) the image for each particle.

Here’s the complete code, I hope someone figures it out :cry:

https://github.com/patakk/Cursors

I think, but I’m not sure, that the problem is with gl_TexCoord[0] and gl_FragCoord. I think these are deprecated in later versions of openGL, and that they’re maybe not as useful with a programmable pipeline. So, your texture can’t properly bind to the particle without texture coordinates.

Yeah, I tried all variations of those variables with different version of GL, but nothing seems to work… and I didn’t forget to enable poitn sprites.

The link is down / private.

Sorry, it’s working now https://github.com/patakk/Cursors

Anyway, the general steps I want to achieve is to:

  1. use a compute shader to control the particle behavior
  2. render particles using an image texture
  3. apply a shader (a filter) to the whole image, like blur/glow/vcr effect/etc.

I can achieve all these steps individually. If I don’t explicitly set the GL version (so, if I use ofSetupOpenGL(1024,768,OF_WINDOW);) the particle physics/rendering works fine, but the postprocessing filter (blur) doesn’t.
If I explictily set the GL version to 4.3 or 4.6, the blur works, and particle physics works, but particle rendering doesn’t.

And I have a question related to all this, what’s the purpose of the #version 150 preprocessing instruction of the shader? What’s the relation between that number and the GL version?

The #version preprocessing line is a way for the GLSL compiler to know which version of the API you are using, it is somewhat related to the OpenGL version.

When you are using the programmable renderer with Ofx (OpenGL version 3.2 or higher) you may want to stick with more modern idioms. Some builting varaibles (like gl_FragColor) will lack so you will need to redefine them for your need. To see the differences between GLSL version you can check docs.gl.

For your issue I think it’s coming from a few things, one of them is the texture coordinates use in the fragment shader. For point sprite you’ll need to use gl_PointCoords scaled with your point size, try this :

// particleManager.cpp
void particleManager::draw() {
	ofEnableAlphaBlending();
	ofEnablePointSprites();

	renderShader.begin();
    renderShader.setUniformTexture( "tex0", imgTexture, 0);
	vbo.draw(GL_POINTS, 0, particleCount);
	renderShader.end();
}
// cusor.vert
#version 150

uniform mat4 modelViewProjectionMatrix;

in vec4 position;
out float vPointSize;

void main(){
	gl_Position = modelViewProjectionMatrix * position;
	gl_PointSize = 60.0;
	vPointSize = gl_PointSize; 
}
// cursor.frag
#version 150

uniform sampler2DRect tex0;

in float vPointSize;
out vec4 vFragColor;

void main () {
    vFragColor = texture( tex0, vPointSize*gl_PointCoord);
}

Edit :
To be clear this is due to the use of GL_TEXTURE_RECTANGLE, you can call ofDisableArbTex() and your fragment shader could work without the pointSize scaling :

#version 150

uniform sampler2D tex0;
out vec4 vFragColor;

void main () {
    vFragColor = texture( tex0, gl_PointCoord);
}
1 Like

Hey thanks so much for posting this! This is really cool! I love the above line in the fragment shader and how gl_PointSize and gl_PointCoord can basically be used in place of per-vertex texture coordinates (I think, if I’m reading it right).

So @DarkSalmon , do you know if some of these internal opengl variables that are deprecated, like gl_FragColor and gl_TexCoord, are still viable in higher versions of opengl, like say 3.3 and higher? My impression is that they’re not, but I haven’t really found a good answer on the internet, and maybe its dependent on the gpu, drivers, etc? I avoid them, because there are other, non-deprecated ways to code the shaders.

OK thanks again and learned a ton from your replies in this thread!