glReadPixels返回不正确的值

时间:2014-04-26 19:08:23

标签: c++ opengl

我正在尝试通过以下opengl教程实现拾取,我有一个带有6000个顶点的网格,我希望选择特定的;我选择通过在每个顶点处重新设置唯一颜色的框来做,在那个点上读取鼠标点击的像素,这应该返回给我最近顶点的ID。背景呈现为白色,所以如果我想念我什么也得不到。

但是我有一个问题,它只在大部分时间有效;有一些区域,如果我点击那里我得到白色返回,即使它明显是一个顶点,并且当渲染彩色场景时,我点击的位置显然有一个红色框。

然后在网格附近有白色区域,在左下方并且在远离它的一些随机点处,给我一个命中。

我完全不明白为什么会这样,它应该有用。

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();
}

}

1 个答案:

答案 0 :(得分:3)

问题是双重的:返回的疯狂数字是由于在我想要特定的颜色值时启用了不正确的多重采样(如何吃蛋糕和吃它可能需要一些工作但是现在我不在乎) ,其次是因为glReadPixels()反转了Y轴,需要为Y值做高度 - Current_Mouse_Position。

也许glPoints会更快地做我正在做的事情,我需要调查它。