Sampling two textures at random fails for point sprites

I’m trying to render two different textures, say, a star and a snowflake, to random points (point spites, where gl_PointSize is 20 - set in my vertex shader).

What I expect is simple: I have two points, A and B. Using some form of randomness, I want point A to be rendered as a star, and point B to be a snowflake.

As I understand, there’s a variable called gl_PrimitiveID, which is provided to the fragment shader per primitive (in my case, a point). It would be different for every point. I should be able to use something as simple as a mod operation to decide which texture to use. Furthermore, I understand that the fragment shader is called multiple times per vertex, however, ideally each call to the fragment shader will have the same gl_PrimitiveID for one point sprite.

However, what renders on the screen is a square, instead of either of the textures. However, if I use just one texture, it works very well.

Here’s how I’m binding the two textures:

    int locTex0 = shader.getUniformLocation("tex0");
    int locTex1 = shader.getUniformLocation("tex1");
    textures[0].bind(locTex0);
    textures[1].bind(locTex1);
    vboMesh.draw(ofPolyRenderMode::OF_MESH_POINTS);
    textures[0].unbind();
    textures[1].unbind();

In my fragment shader:

#version 400
uniform sampler2D tex0;
uniform sampler2D tex1;

out vec4 fragColour;

void main() {
    // Neon
    float r = 0.145, g =0.764, b=0.988;

    if (mod(gl_PrimitiveID, 2) == 0) {
        vec4 textureColour = texture(tex0, gl_PointCoord);
        fragColour = vec4(r, g, b, textureColour.a);
    } else {
        vec4 textureColour = texture(tex1, gl_PointCoord);
        fragColour = vec4(r, g, b, textureColour.a);
    }
}

If I use the same texture in both the conditional blocks (either tex0 or tex1), then the appropriate texture is rendered.

I’m unable to get it to render two different textures.

Any idea what I’m missing?

Try to load the textures on setup() then:

void ofApp::draw() {

ofEnablePointSprites();
shader.begin();
shader.setUniformTexture("tex0", texture0.getTexture(), 0);
shader.setUniformTexture("tex1", texture1.getTexture(), 1);
//vboMesh.draw(ofPolyRenderMode::OF_MESH_POINTS);
vboMesh.draw(GL_POINTS,0,2);
shader.end();

}

PS: Don’t forget to ofDisableArbTex(); on top of setup() .

Hey @Dorald, I don’t think texture loading is a problem, as I can independently use both textures (either show all stars, or all snowflakes).

I think the problem is how the fragment shader runs for a given point sprite.

I tried to change the colour, instead of the texture. This works! Now I have either stars or snowflakes, in different colours. I can’t have both though, stars and snowflakes together on the screen.

This means that the logic based on gl_PrimitiveID is right, but when the fragment shader samples two textures randomly, it renders a plain square.

What could possibly be wrong?

Here’s my updated fragment shader code:

#version 400
uniform sampler2D tex0;
uniform sampler2D tex1;

out vec4 fragColour;

void main() {
    // Neon
//    float r = 0.145, g =0.764, b=0.988;

    float r = 0, g = 0, b = 0;

    if (mod(gl_PrimitiveID, 2) == 0) {
        r = 1;
    } else {
        b = 1;
    }

//    if (mod(gl_PrimitiveID, 2) == 0) {
        vec4 textureColour = texture(tex0, gl_PointCoord);
        fragColour = vec4(r, g, b, textureColour.a);
//    } else {
//        vec4 textureColour = texture(tex1, gl_PointCoord);
//        fragColour = vec4(r, g, b, textureColour.a);
//    }
}

Is the fragment shader allowed to sample only one texture throughout?

i think the problem is how you are binding the textures, you should use:

shader.setUniformTexture("tex0", textures[0], 0);
shader.setUniformTexture("tex0", textures[0], 1);
vboMesh.draw(ofPolyRenderMode::OF_MESH_POINTS);

Thanks @arturo! That worked very well!