3
votes

I have a shader that draws particles with solid colors. I would like to enable the shader to sample an FBO texture so that each particle can act upon the color "behind" it. Seems like it should be pretty simple, but no.

I've simplified the code such that I would expect my FBO to be drawn on the face of every particle, scaled down. Ugly, but it would at least prove that my particles can sample the texture. Instead, each particle is just a solid color. I'm using OpenFrameworks, so there a few abstractions. I have verified that tex.bind() binds to the first texture location, and I'm able to apply shaders to the FBO without GL_POINTS.

Here's where I setup my shader, draw the FBO, and render the particles:

void Particles::draw(ofxFBOTexture &tex){
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        ofEnableSmoothing();
        glEnable(GL_POINT_SPRITE_ARB);
        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
        glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE, GL_TRUE);
                shader.begin();
                        shader.setUniform("winWidth", (float) width);
                        shader.setUniform("winHeight", (float) height);
                        tex.draw(0,0); // I've tried tex.bind() here too    

                        for(int i = 0; i < lastDead; i++){
                                allParticles[i]->draw(this->shader);
                        }

                shader.end();
        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
        glDisable(GL_POINT_SPRITE_ARB);
        ofDisableSmoothing();
        glDisable(GL_BLEND);
}
// <snip>
void Particle::draw(ofxShader &shader){
        if(dead) return;

        // this must go outside glBegin
        shader.setAttribute("size", size);
        shader.setAttribute("velocity", xVel, yVel, 0.0);

        glBegin(GL_POINTS);
                glColor4f(r, g, b, multiplier * 0.8);
                glVertex3f(x, y, 0);
        glEnd();
}

Here's my vertex shader:

#version 120
attribute float size;
attribute vec3 velocity;
varying vec3 vel;
uniform float winWidth;
uniform float winHeight;

void main() {
        gl_PointSize = size;
        gl_FrontColor = gl_Color;

        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
        gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

        vel = velocity;
}

... and the relevant excerpt from my fragment shader, simplified for debugging:

#version 120
#extension GL_ARB_texture_rectangle : enable
varying vec3 vel;
uniform sampler2DRect tex;
uniform float winWidth;
uniform float winHeight;

void main() {
        vec4 texColor = texture2DRect(tex, gl_TexCoord[0].st);
        gl_FragColor = texColor;
}
1

1 Answers

3
votes

Instead of gl_TexCoord[0].st you need gl_PointCoord.st.