c++openglglfwmouse-picking

glReadPixels() is not accurate


I want to do mouse picking based on colors. Here is my code:

bool Geometry::IsObjectClicked(int x, int y, float color[4])
{
   glFlush();
   glFinish();
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   struct { GLubyte red, green, blue; } pixel;
   glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pixel);
   float clickedColor[3];
   clickedColor[0] = (float)((float)pixel.red / 255);
   clickedColor[1] = (float)((float)pixel.green / 255);
   clickedColor[2] = (float)((float)pixel.blue / 255);
   if (clickedColor[0] == color[0] && clickedColor[1] == color[1] && clickedColor[2] == color[2])
   {
       return true;
   }
   return false;
}

I have triangles with different colors. It gives me the correct behaviour when I click on the center of the triangle, but when I click elsewhere in the triangle, it doesn't recognize that pixel as the color. Sometimes it doesn't even recognize some extreme colors with not straightforward code like rgb(255, 0, 0). I thought that maybe my x and y coordinates not correct but I think glfwGetCursorPos() works fine.


Solution

  • The first commenter was right, you have to change y to height-y. As for the color comparison, I noticed that there is a slight difference between the two colors which makes the comparison false. So I added a 0.01f tolerance:

    if ((clickedColor[0] == color[0] || abs(clickedColor[0]-color[0]) < 0.01f) && (clickedColor[1] == color[1] || abs(clickedColor[1] - color[1]) < 0.01f) && (clickedColor[2] == color[2] || abs(clickedColor[2] - color[2]) < 0.01f))
    {
        return true;
    }