C++ glReadPixels返回不正确的值

C++ glReadPixels返回不正确的值,c++,opengl,C++,Opengl,我试图通过opengl教程实现拾取,我有一个6000个顶点的网格,我希望拾取特定的顶点;我选择在每个顶点重新绘制唯一颜色的框,在该点上点击鼠标读取像素,这将返回到最近顶点的ID。背景被渲染为白色,因此如果我错过,我将一无所获 然而,我有一个问题,它只工作的大部分时间;有一些区域,如果我在那里单击,我会返回白色,即使它显然是一个顶点,并且在渲染彩色场景时,在我单击的点上明显有一个redish框 然后,在网格附近的左下角有一些白色区域,在远离网格的某个随机点上,返回一个命中 我完全不明白为什么会发生

我试图通过opengl教程实现拾取,我有一个6000个顶点的网格,我希望拾取特定的顶点;我选择在每个顶点重新绘制唯一颜色的框,在该点上点击鼠标读取像素,这将返回到最近顶点的ID。背景被渲染为白色,因此如果我错过,我将一无所获

然而,我有一个问题,它只工作的大部分时间;有一些区域,如果我在那里单击,我会返回白色,即使它显然是一个顶点,并且在渲染彩色场景时,在我单击的点上明显有一个redish框

然后,在网格附近的左下角有一些白色区域,在远离网格的某个随机点上,返回一个命中

我完全不明白为什么会发生这种情况,它应该会起作用

void Display() {
Controls->setVector(indexed_vertices);


if (Controls->getPicking()) {
    // Clear the screen in white
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    for ( int i=0; i< indexed_vertices.size(); i++) {
        // use shaders
        glUseProgram(pickingProgramID);
        // Get a handle for our "MVP" uniform
        GLuint PickingMatrixID = glGetUniformLocation(pickingProgramID, "MVP");

        glm::mat4 RotationMatrix = glm::toMat4(orientations);
        glm::mat4 btTranslationMatrix = glm::translate(glm::mat4(1.0f), indexed_vertices[i]);
        glm::mat4 myModelMatrix = ModelMatrix * Controls->getTranslationMatrix() * Controls->getRotationMatrix() * btTranslationMatrix;
        MVP = ProjectionMatrix * ViewMatrix * myModelMatrix;
        Controls->setCntrlsViewMatrix(ViewMatrix);
        Controls->setCntrlsProjectionMatrix(ProjectionMatrix);

        glUniformMatrix4fv(PickingMatrixID, 1, GL_FALSE, &MVP[0][0]);


        // Convert "i", the integer mesh ID, into an RGB color
        int r = (i & 0x000000FF) >>  0;
        int g = (i & 0x0000FF00) >>  8;
        int b = (i & 0x00FF0000) >> 16;

        // OpenGL expects colors to be in [0,1], so divide by 255.
        glUniform4f(pickingColorID, r/255.0f, g/255.0f, b/255.0f, 1.0f);

        // 1rst attribute buffer : vertices
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, gvertexbuffer);
        glVertexAttribPointer(
            0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
            3,                  // size
            GL_FLOAT,           // type
            GL_FALSE,           // normalized?
            0,                  // stride
            (void*)0            // array buffer offset
        );

        // Index buffer
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

        // Draw the triangles !
        glDrawElements(
            GL_TRIANGLES,      // mode
            indices.size(),    // count
            GL_UNSIGNED_SHORT,   // type
            (void*)0           // element array buffer offset
        );
        // OpenGL expects colors to be in [0,1], so divide by 255.

    }
    glDisableVertexAttribArray(0);

    glFlush();
    glFinish(); 


    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    // Read the pixel at the center of the screen.
    // You can also use glfwGetMousePos().
    // Ultra-mega-over slow too, even for 1 pixel, 
    // because the framebuffer is on the GPU.
    unsigned char data[4];
    glReadPixels(Controls->get_mx_cur(), Controls->get_my_cur(),1,1, GL_RGBA, GL_UNSIGNED_BYTE, data);
    std::cout << "MX: " << Controls->get_mx_cur() << " MY: " << Controls->get_my_cur() << std::endl;

    // Convert the color back to an integer ID
    int pickedID = 
        data[0] + 
        data[1] * 256 +
        data[2] * 256*256;

    //std::cout << std::hex << pickedID << std::dec<<std::endl;
    if (pickedID == 0x00ffffff) { // Full white, must be the background !
        printf("Miss\n");
    } 
    else {
        std::cout << "mesh " << pickedID << std::endl;
    }

    // Uncomment these lines to see the picking shader in effect
    glutSwapBuffers();
    skip = true;
    Controls->setPicking(false);
}
if (!skip) {
// White background
glClearColor(0.2f, 0.25f, 0.5f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);

glUseProgram(ShaderIDs[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureID, 0);


glm::mat4 myModelMatrix = ModelMatrix * Controls->getTranslationMatrix() * Controls->getRotationMatrix();
MVP = ProjectionMatrix * ViewMatrix * myModelMatrix;

// The inverse transpose of the View Model Matrix will re-normalize the normals if there's
// been any scaling. Otherwise you don't need it.
glm::mat3 NormalMatrix = glm::mat3( glm::transpose(glm::inverse(ViewMatrix * myModelMatrix)));

Controls->setCntrlsViewMatrix(ViewMatrix);
Controls->setCntrlsProjectionMatrix(ProjectionMatrix);

glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix[0][0]);
    // Notice we're passing a 3 by 3 matrix here.
glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);

// VBO buffer: vertices
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
    0,                  // attribute
    3,                  // size
    GL_FLOAT,           // type
    GL_FALSE,           // normalized?
    0,                  // stride
    (void*)0            // array buffer offset
    );

// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
    1,                                // attribute
    2,                                // size
    GL_FLOAT,                         // type
    GL_FALSE,                         // normalized?
    0,                                // stride
    (void*)0                          // array buffer offset
    );

// 2rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
    2,                                // attribute
    3,                                // size
    GL_FLOAT,                         // type
    GL_FALSE,                         // normalized?
    0,                                // stride
    (void*)0                          // array buffer offset
    );

// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

if ( Controls->getRenderingMode() == 0 ) {
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    //glDisable(GL_POLYGON_OFFSET_FILL);
} 
else if (Controls->getRenderingMode() == 1 ) {

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glDisable(GL_CULL_FACE);
    //glDisable(GL_POLYGON_OFFSET_FILL);
    glUseProgram(ShaderIDs[1]);
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
    glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix[0][0]);
        // Notice we're passing a 3 by 3 matrix here.
    glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
    glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
    glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);
} 
else if (Controls->getRenderingMode() == 2 ) {
    glUseProgram(ShaderIDs[1]);
    // 
    glm::mat4 MyOffsetMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(1.025,1.025,1.025));
    MyOffsetMatrix = glm::mat4(1.0f);
    glm::mat4 myModelMatrix2 = ModelMatrix * Controls->getTranslationMatrix() * 
        Controls->getRotationMatrix()*MyOffsetMatrix;
    glm::mat3 NormalMatrix2 = glm::mat3( glm::transpose(glm::inverse(ViewMatrix * 
        myModelMatrix2)));

    glm::mat4 MVP2 = ProjectionMatrix * ViewMatrix * myModelMatrix2;

    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP2[0][0]);
    glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
    glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix2[0][0]);
        // Notice we're passing a 3 by 3 matrix here.
    glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix2[0][0]);
    glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
    glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);


    // The rest is exactly the same as the first object

    // 1rst attribute buffer : vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    // 2nd attribute buffer : UVs
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

    // 3rd attribute buffer : normals
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    // Index buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glDisable(GL_CULL_FACE);
    glEnable(GL_POLYGON_OFFSET_FILL);
    // Draw the triangles !
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void*)0);

    glEnable(GL_POLYGON_OFFSET_FILL);
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glPolygonOffset(2.0f, 2.0f);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    //glDisable(GL_POLYGON_OFFSET_FILL);

    glUseProgram(ShaderIDs[0]);
}
//glUseProgram(ShaderIDs[1]);
// Draw the triangles !
glDrawElements(
    GL_TRIANGLES,      // mode
    indices.size(),    // count
    GL_UNSIGNED_SHORT,   // type
    (void*)0           // element array buffer offset
    );

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glutSwapBuffers();
}
void Display(){
控件->设置向量(索引的顶点);
如果(控制->获取拾取()){
//清除白色屏幕
glClearColor(1.0f、1.0f、1.0f、1.0f);
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
对于(int i=0;igetTranslationMatrix()*控件->getRotationMatrix()*btTranslationMatrix;
MVP=ProjectionMatrix*ViewMatrix*myModelMatrix;
控件->设置CNTRLSVIEWMATRIX(ViewMatrix);
控件->设置CntrLSProjectionMatrix(ProjectionMatrix);
glUniformMatrix4fv(PickingMatrixID,1,GL_FALSE,&MVP[0][0]);
//将整数网格ID“i”转换为RGB颜色
int r=(i&0x000000FF)>>0;
int g=(i&0x0000FF00)>>8;
intb=(i&0x00FF0000)>>16;
//OpenGL希望颜色为[0,1],所以除以255。
glUniform4f(pickingColorID,r/255.0f,g/255.0f,b/255.0f,1.0f);
//1rst属性缓冲区:顶点
GlenableVertexAttributeArray(0);
glBindBuffer(GL_数组_BUFFER,gvertexbuffer);
glvertexattributepointer(
0,//属性。0没有特定原因,但必须与着色器中的布局匹配。
3,//大小
GL\u FLOAT,//类型
GL_FALSE,//标准化?
0,//步幅
(void*)0//数组缓冲区偏移量
);
//索引缓冲区
glBindBuffer(GL_元素_数组_缓冲区,elementbuffer);
//画三角形!
微量元素(
GL_三角形,//模式
index.size(),//计数
GL\u UNSIGNED\u SHORT,//类型
(void*)0//元素数组缓冲区偏移量
);
//OpenGL希望颜色为[0,1],所以除以255。
}
glDisableVertexAttributeArray(0);
glFlush();
glFinish();
glPixelStorei(GLU解包对齐,1);
//读取屏幕中央的像素。
//您还可以使用glfwGetMousePos()。
//超百万太慢了,即使是1像素,
//因为帧缓冲区在GPU上。
无符号字符数据[4];
glReadPixels(控件->获取\u mx\u cur(),控件->获取\u我的\u cur(),1,1,GL\u RGBA,GL\u无符号\u字节,数据);

std::cout问题有两个方面:返回的疯狂数字是由于在我想要特定颜色值时启用了不正确的多重采样(如何吃蛋糕可能需要一些工作,但现在我不在乎),其次是因为glReadPixels()反转Y轴,需要对Y值执行高度-当前鼠标位置


也许glPoints会更快地完成我正在做的事情,我需要研究它。

您是否已经检查过它是否可能是y反转问题?窗口系统使用的坐标系,即鼠标坐标系,通常与OpenGL坐标系的y方向相反。[编辑:这是对之前评论的回应。]不确定我们是否在谈论同一件事。如果y反转有问题,您必须将第二个参数更改为
glReadPixels
WindowHeight-Controls->get_my_cur()
,其中
WindowHeight
是窗口的当前高度(以像素为单位)。@RaenirSalazar:如果使用多重采样,您将得到“疯狂”值。我真诚地怀疑这是您的问题,但任何时候光栅化使用插值,这种技术都不会正常工作。这可能意味着在顶点之间插值颜色(也不是问题,因为您使用制服传递颜色)平均采样颜色以防混叠。例如,当你用这种方式旋转RGBA像素时,有时需要考虑字节顺序。这个问题是否发生在ID为255的任何对象上?哦,真的吗?是的,在使用该技术之前,你确实需要禁用多采样光栅化。幸运的是,如果你有多采样帧缓冲区Y,您不必绘制到不同的缓冲区,您可以使用
glDisable(GL\u MULTISAMPLE)
将其打开/关闭。我刚刚重新阅读了您的问题…似乎您正在尝试绘制一些正方形(或立方体,不确定)以你的对象的顶点为中心,那些是你正在着色和尝试挑选的东西。你可能会考虑使用<代码> GLYPosits <代码>,这样你就不太可能碰到它们的子像素问题。当然,如果你使用多样本光栅化,你仍然需要禁用它们,或者它们会变成平滑的CIR。不是扁平的正方形而是圆形的。