Encoding id picking into a 16b red component texture

So, I am trying to perform picking through id, that is before each drawArray a specific uniform variable will be set and written in the red component

IDs are signed short

But this is not working, and I don’t know why

private void initRenderingTargets(GL3 gl3, int width, int height) {

        textures = new int[2];
        fbo = new int[1];

        gl3.glGenTextures(2, textures, 0);
        gl3.glGenFramebuffers(1, fbo, 0);
        /**
         * Depth.
         */
        gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, textures[depth]);

        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_WRAP_S, GL3.GL_CLAMP_TO_EDGE);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_WRAP_T, GL3.GL_CLAMP_TO_EDGE);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_NEAREST);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_NEAREST);

        gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_DEPTH_COMPONENT32F, width, height, 0, GL3.GL_DEPTH_COMPONENT, GL3.GL_FLOAT, null);
        /**
         * IDs.
         */
        gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, textures[id]);

        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_WRAP_S, GL3.GL_CLAMP_TO_EDGE);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_WRAP_T, GL3.GL_CLAMP_TO_EDGE);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_NEAREST);
        gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_NEAREST);

        gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_R16I, width, height, 0, GL3.GL_RED_INTEGER, GL3.GL_SHORT, null);
        /**
         * FBO.
         */
        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, fbo[0]);
        gl3.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_DEPTH_ATTACHMENT, GL3.GL_TEXTURE_RECTANGLE, textures[depth], 0);
        gl3.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_COLOR_ATTACHMENT0, GL3.GL_TEXTURE_RECTANGLE, textures[id], 0);

        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0);
    }

 public void pick(GL3 gl3) {
        System.out.println("pick");

        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, fbo[0]);
        Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
        gl3.glClearColor(clear.x, clear.y, clear.z, clear.w);
        gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
        gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
        {
            pickModel.bind(gl3);
            {
                for (EC_Mesh mesh : EC_GUI.main.getList().getMeshes()) {
                    System.out.println("id " + mesh.getId());
                    gl3.glUniform1i(pickModel.getIdUL(), (int) mesh.getId());
//                    gl3.glUniform1i(pickModel.getIdUL(), 1);

                    mesh.render(gl3);
                }
            }
            pickModel.unbind(gl3);
        }
        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0);
    }

    public void read(GL3 gl3) {

        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, fbo[0]);
        {
            gl3.glReadBuffer(GL3.GL_COLOR_ATTACHMENT0);
            
            FloatBuffer pixel = FloatBuffer.allocate(4);
            ShortBuffer p = ShortBuffer.allocate(2);
            Vec2i point = EC_GUI.main.getGlViewer().getViewPole().getStartingPoint();
            
            gl3.glReadPixels(point.x, point.y, 1, 1, GL3.GL_RED_INTEGER, GL3.GL_SHORT, p);
            
            System.out.println("pixel id "+p.get(0));
            System.out.println("pixel id "+(short)p.get(0));
        }
        gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0);
    }

Important lines

    gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_R16I, width, height, 0, GL3.GL_RED_INTEGER, GL3.GL_SHORT, null);

and

        gl3.glReadPixels(point.x, point.y, 1, 1, GL3.GL_RED_INTEGER, GL3.GL_SHORT, p);

VS:

#version 330

layout (location = 0) in vec3 position;

uniform mat4 modelToWorldMatrix;

layout(std140) uniform GlobalMatrices {
    mat4 worldToCameraMatrix;
    mat4 cameraToClipMatrix;
};

void main() {

    gl_Position = cameraToClipMatrix * (worldToCameraMatrix * vec4(position, 1.0));
}

FS:

#version 330

uniform int id;

out vec4 outputColor;

void main() {

    outputColor = vec4(id, 0, 0, 1);
}

Im reading always the same value (32767)

What is wrong, guys?

You fragment shader says your are writing to a floating point texture (vec4) but you texture is integer. AFAIK the result is undefined. Try ivec4

Thanks tonyo, I tried that but unfortunately it returns still the same wrong value

What colour are you using to clear? Try reading back the whole buffer and looking at what is in it both before and after your mesh render. Why are use using GL_TEXTURE_RECTANGLE and not GL_TEXTURE_2D?

The clear is also wrong. It is undefined to use glClearColor on integer framebuffers. Use glClearBufferiv instead (or glClearColorIiEXT, back in GL2.)

Exacty white, (1,1,1,1). Yeah, I can try to look inside it, once retrieved which is the fastest way to look at it?

If I have to be honest I don’t know why I am using GL_TEXTURE_RECTANGLE, I guess a relict of the past… Why should I use GL_TEXTURE_2D?

Ok, so rendering like this

gl3.glClearBufferiv(GL3.GL_COLOR, GL3.GL_COLOR_ATTACHMENT0, new int{1, 0, 0, 0}, 0);
gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);

Reading

ShortBuffer p = ShortBuffer.allocate(2);

        Vec2i point = EC_GUI.main.getGlViewer().getViewPole().getStartingPoint();
        int realY = EC_GUI.main.getGlViewer().getGlWindow().getHeight() - point.y - 1;
        gl3.glReadPixels(point.x, realY, 1, 1, GL3.GL_RED_INTEGER, GL3.GL_SHORT, p);
        EC_GUI.main.getGlViewer().getList().selectionById((short) p.get(0));
        System.out.println("pixel id "+p.get(0));

Init

     gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_R16I, width, height, 0, GL3.GL_RED_INTEGER, GL3.GL_SHORT, null);

FS

#version 330

uniform int id;

out vec4 outputColor;

void main() {

outputColor = ivec4(id, 0, 0, 1);
//outputColor = vec4(3, id, 2, 1);

}

I get error 1281, INVALID_VALUE (not in the init, but after the rendering+pick)

The rendering was wrong, I read that the second parameter in glClearBufferiv should be the i-th buffer specified by glDrawBuffer(s)

so this is the new rendering

gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
// Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
// gl3.glClearColor(clear.x, clear.y, clear.z, clear.w);
// gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
gl3.glClearBufferiv(GL3.GL_COLOR, 0, new int{0, 0, 0, 0}, 0);

I got it working if I switch to int

init

        gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_R32I, width, height, 0, GL3.GL_RED_INTEGER, GL3.GL_INT, null);

render

            
gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
            gl3.glClearColor(2, clear.y, clear.z, clear.w);
            gl3.glClear(GL3.GL_COLOR_BUFFER_

pick

            gl3.glReadPixels(point.x, realY, 1, 1, GL3.GL_RED_INTEGER, GL3.GL_INT, pixel);


I also changed the FS, although this does not seem to have any effect (vec4 -> ivec4)

    outputColor = ivec4(id, 0, 0, 1);


However I am doing some test to see what is written inside my GL_COLOR_ATTACHMENT0 before I render something (basically I click on empty space, where I am sure nothing has been rendered there)

If I have

            gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            gl3.glClearBufferiv(GL3.GL_COLOR, 0, new int[]{0, 0, 0, 0}, 0);
gl3.glClear(GL3.GL_DEPTH_BUFFER_BIT);

I get

pixel id 0.0

If I have

            gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            gl3.glClearBufferiv(GL3.GL_COLOR, 0, new int[]{1, 0, 0, 0}, 0);
gl3.glClear(GL3.GL_DEPTH_BUFFER_BIT);

I get

pixel id 1.4E-45

If I have

            gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            gl3.glClearBufferiv(GL3.GL_COLOR, 0, new int[]{2, 0, 0, 0}, 0);
gl3.glClear(GL3.GL_DEPTH_BUFFER_BIT);

I get

pixel id 2.8E-45

Instead if I have

gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
            gl3.glClearColor(0, clear.y, clear.z, clear.w);
            gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);

pixel id 0.0

gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
            gl3.glClearColor(1, clear.y, clear.z, clear.w);
            gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);

pixel id 1.0

gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
            Vec4 clear = EC_GUI.main.getGlViewer().getClearColor();
            gl3.glClearColor(2, clear.y, clear.z, clear.w);
            gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);

pixel id 2.0

Wut? Isn’t clearColor supposed to clamp [0,1]? >.>

Ps: changing the other component other than the red one does have no effect as expected.