使用glRenderMode(GL_SELECT)和glReadPixels选择OpenGL

时间:2015-06-23 11:32:20

标签: opengl glu picking mouse-picking

我试图在opengl中进行选择,但它无法正常工作。 我从.obj文件(v,vn,f,o和这样的索引)中绘制我收到的对象。每个对象都来自" groups"每组都是GL_POLYGON组。 这是绘图功能:

void draw(GLenum mode) {
    glBegin(GL_LINES);
    glColor3f(1, 0, 0);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(100.0, 0.0, 0.0);

    glColor3f(0, 0, 1);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(0.0, 100.0, 0.0);

    glColor3f(0, 1, 0);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(0.0, 0.0, 100.0);
    glEnd();

    glColor4f(1.0, 1.0, 1.0, 1.0);

    if (changeFOV) {
        fovAngle += fovScale;
        changeFOV = false;
        setTransformations();
    }
    for (unsigned int i = 0; i < objects.size(); i++) {
        objectItem currObject = objects[i];
        for (unsigned int j = 0; j < currObject.getGroups().size(); j++) {
            group currGroup = currObject.getGroups().at(j);
            for (unsigned int k = 0; k < currGroup.getFs().size(); k++) {
                if (mode == GL_SELECT)
                    glPushName(currGroup.getName());
                glPushMatrix();
                vector<pair<int, int> > currF = currGroup.getFs()[k];
                glBegin(GL_POLYGON);
                for (unsigned int kk = 0; kk < currF.size(); kk++) {
                    Vector3f currVertex = vertexes.at(
                            (currF.at(kk).first - 1 >= 0) ?
                                    currF.at(kk).first - 1 : 0);

                    Vector3f currNormal = vertexesNormal.at(
                            (currF.at(kk).second - 1 >= 0) ?
                                    currF.at(kk).second - 1 : 0);

                    glNormal3f(currNormal.x, currNormal.y, currNormal.z);
                    glVertex3f(currVertex.x / 1, currVertex.y / 1,
                            currVertex.z / 1);
                }
                glEnd();
                glPopMatrix();
            }
        }
    }
}

绘图工作正常,我在屏幕上看到了对象。

这是所有拣货程序

/*      PICKING     */
void processHits(GLint hits, GLuint *buffer) {
    float z1, z2;
    for (int i = 0; buffer[i] > 0; i += 5) {
        z1 = buffer[i + 1] / 4294967295.0;
        z2 = buffer[i + 2] / 4294967295.0;
        printf("z1 = %f ,z2 = %f zValue = %f\n", z1, z2, zValue[0]);
        if ((zValue[0] <= z1 + 0.0001 && zValue[0] >= z2 - 0.0001)
                || (zValue[0] >= z1 - 0.0001 && zValue[0] <= z2 + 0.0001)) { //try to locate which name is correlated with the pressed pixel according to z value
            ii = buffer[i + 3];
            jj = buffer[i + 4];
        }

    }
}

void startPicking(GLuint *selectionBuf) {
    glSelectBuffer(bufSize, selectionBuf); //declare buffer for input in selection mode
    glRenderMode(GL_SELECT); //change to selecting mode
    glInitNames();          //initialize names stack
    glPushName(-1);         //push name
}

void pick(int button, int x, int y) {
    //use selection mode to pick
    glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_FLOAT, pix);
    //printf("depth = %f, x = %d, y = %d\n",pixels[(viewport[3]-y)*512+x],x,viewport[3]-y);
    glMatrixMode(GL_PROJECTION);
    glReadPixels((GLdouble) x, (GLdouble) viewport[3] - y, 2, 2,
            GL_DEPTH_COMPONENT, GL_FLOAT, zValue);
    glPushMatrix(); //saves current projection matrix
    startPicking(selectionBuf); //preper selection mode
    glLoadIdentity();
    gluPickMatrix((GLdouble) x, (GLdouble) viewport[3] - y, 1, 1, viewport); //change matrices so only the area of the picking pixel can be seen.
    gluPerspective(fovAngle, 1, near, far); //return to perspective state
    glMatrixMode(GL_MODELVIEW);
    draw(GL_SELECT); //draws board on background
    hits = glRenderMode(GL_RENDER); //gets hits number
    glMatrixMode(GL_PROJECTION);
    glPopMatrix(); //restores projection matrix
    glMatrixMode(GL_MODELVIEW);
    processHits(hits, selectionBuf); //check hits
    if(hits > 0)
        printf("touched: %d\n",selectionBuf[3]);
    //printf("depth %f hits: %d\n\n",pixels[(viewport[3]-y)*512+x], hits);
    if (zValue[0] < 1.0) {
        isPick = true;
        xx = x;
        yy = y;
        if (button == GLUT_RIGHT_BUTTON)
            zMove = true;
        else
            zMove = false;
    }
}

单击鼠标时调用pick函数(使用opengl鼠标功能)。 我收到的错误是,点击某个对象时似乎没有任何对象被击中。

我正在使用Ubuntu 14.04 LTS和Opengl 3.0

我不知道如何询问或具体询问,如果您发现错误,我会很感激代码的一些输入。

1 个答案:

答案 0 :(得分:0)

您似乎错过了使用glPopName()

选择缓冲区中使用的GLNames被压入堆栈。因此,除非你调用glPopName(),否则堆栈永远不会解开。其工作方式类似于调用glPushMatrix()和glPopMatrix()。

通常这就是代码流的样子。

//Push the name of the primitives on top of selection stack
glPushName(...)
  //Set Transformations / Draw the primitives
  ..
  ..
//Pop the name (Clear the stack for pushing another name)
glPopName();