0
\$\begingroup\$

I'm attempting to check which object the user is hovering over. While everything seems to be just how I'd think it should be, I'm not able to get the correct color due to the second time I draw (without picking colors). Here is my rendering code:

public void render() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    camera.applyTranslations();

    scene.pick();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    camera.applyTranslations();

    scene.render();
}

And here is what gets called on each block/tile on "scene.pick()":

public void pick() {
    glColor3ub((byte) pickingColor.x, (byte) pickingColor.y, (byte) pickingColor.z);
    draw();

    glReadBuffer(GL_FRONT);
    ByteBuffer buffer = BufferUtils.createByteBuffer(4);
    glReadPixels(Mouse.getX(), Mouse.getY(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    int r = buffer.get(0) & 0xFF;
    int g = buffer.get(1) & 0xFF;
    int b = buffer.get(2) & 0xFF;

    if(r == pickingColor.x && g == pickingColor.y && b == pickingColor.z) {
        hovered = true;
    } else {
        hovered = false;
    }
}

I believe the problem is that in the method of each tile/block called by scene.pick(), it is reading the color from the regular drawing state, after that method is called somehow. I believe this because when I remove the "glReadBuffer(GL_FRONT)" line from the pick method, it seems to almost fix it, but then it will also select blocks behind the one you are hovering as it is not only looking at the front.

If you have any ideas of what to do, please be sure to reply!/

EDIT: Adding scene.render(), tile.render(), and tile.draw()

scene.render:

public void render() {
    for(int x = 0; x < tiles.length; x++) {
        for(int z = 0; z < tiles.length; z++) {
            tiles[x][z].render();
        }
    }
}

tile.render:

public void render() {
    glColor3f(color.x, color.y, color.z);
    draw();
    if(hovered) {
        glColor3f(1, 1, 1);
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        draw();
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
}

tile.draw:

public void draw() {
    float x = position.x, y = position.y, z = position.z;

    //Top
    glBegin(GL_QUADS);
    glVertex3f(x, y + size, z);
    glVertex3f(x + size, y + size, z);
    glVertex3f(x + size, y + size, z + size);
    glVertex3f(x, y + size, z + size);
    glEnd();

    //Left
    glBegin(GL_QUADS);
    glVertex3f(x, y, z);
    glVertex3f(x + size, y, z);
    glVertex3f(x + size, y + size, z);
    glVertex3f(x, y + size, z);
    glEnd();

    //Right
    glBegin(GL_QUADS);
    glVertex3f(x + size, y, z);
    glVertex3f(x + size, y + size, z);
    glVertex3f(x + size, y + size, z + size);
    glVertex3f(x + size, y, z + size);
    glEnd();

}

(The game is like an isometric game. That's why I only draw 3 faces.)

\$\endgroup\$
6
  • \$\begingroup\$ whats getting called in scene.render()? \$\endgroup\$ Commented Oct 23, 2012 at 23:53
  • \$\begingroup\$ Here, I'll add those too. \$\endgroup\$ Commented Oct 23, 2012 at 23:57
  • \$\begingroup\$ So, hovered is a property of scene, which gets set in scene.pick(), but it gets referenced in each tile.render() call? That seems not right. \$\endgroup\$ Commented Oct 24, 2012 at 1:40
  • 1
    \$\begingroup\$ @TomJohnson The reason I bring it up is that it is used in your tile render, but if it is improperly assigned, perhaps that is part of your problem. You have a variable that is mysteriously not reading like it is supposed to. Perhaps it's the variable that is weirdly used like a global value. \$\endgroup\$ Commented Oct 26, 2012 at 1:51
  • 1
    \$\begingroup\$ The boolean "hovered" is in the tile class, if that is what you had just edited your question to mean. \$\endgroup\$ Commented Oct 27, 2012 at 23:40

1 Answer 1

2
\$\begingroup\$

It is hard to say exactly what is broken, but I can make a few suggestions.

  1. Generally, the front buffer is what is currently shown, and drawing calls that are being processed are drawn to the back buffer. Once the entire scene is rendered, the back buffer is copied to the front buffer. Therefore I think that you should read from the back buffer, because the front buffer will always contain the final scene, where you have drawn over the colors you want to pick from. (i.e. change your call for glReadBuffer(GL_FRONT) to glReadBuffer(GL_BACK)).

  2. Antialiasing (multisampling and supersampling) and transparency must be disabled for color picking to work. The colors you are picking from encode object IDs, and it does not make sense to blend IDs.

  3. Make sure that the drawing calls are flushed before reading. This may be implied by the pixel reading commands, and may not. It may be good to add an explicit flush command to make sure for debugging at least.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .