Сбор с помощью glRenderMode

Я пытаюсь выбрать OpenGL, поэтому следил за этим сообщением (Выбор OpenGL в режиме выбора) у которого, кажется, есть рабочее решение, но я не могу заставить свою работу. В моей сцене есть многоугольник с трехмерной текстурой, и я хотел бы знать, когда я нажимаю на него.

Вот мой код:

Метод мыши, запускающий сбор при щелчке правой кнопкой мыши:

void mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button()==Qt::RightButton){
        pickObjects(event->pos().x(),event->pos().y());
    }
}

Метод pickObjects:

#define BUFSIZE 512
void pickObjects(int x, int y)
{
    GLint viewport[4];
    GLint hits;

    GLuint selectBuf[BUFSIZE];
    glSelectBuffer (BUFSIZE, selectBuf);

    glRenderMode (GL_SELECT);

    glMatrixMode (GL_PROJECTION);
    glPushMatrix ();
    glLoadIdentity ();

    glGetIntegerv (GL_VIEWPORT, viewport);

    gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
    gluPerspective(fov, this->width() / this->height(), 0.1, 1000);

    glMatrixMode(GL_MODELVIEW);

    glInitNames();

    makeCustomAnnot(GL_SELECT);

    int hits=0;

    glMatrixMode (GL_PROJECTION);
    glPopMatrix ();

    glMatrixMode(GL_MODELVIEW);

    hits = glRenderMode (GL_RENDER);
    if (hits != 0)
    {
        cout<<"FOUND " << hits << " hit(s)"<<endl; //ALWAYS GIVES 0 HITS
        processHits(hits,selectBuf);
    }

}

Метод processHits:

void processHits(GLint inHits, GLuint buffer[])
{
    unsigned int i, j;
    GLuint names, *ptr, minZ,*ptrNames, numberOfNames;

    ptr = (GLuint *) buffer;
    minZ = 0xffffffff;
    for (i = 0; i < inHits; i++) {
        names = *ptr;
        ptr++;
        if (*ptr < minZ) {
            numberOfNames = names;
            minZ = *ptr;
            ptrNames = ptr+2;
        }
        ptr += names+2;
    }

    cout << "Nearest: ";
    ptr = ptrNames;
    for (j = 0; j < numberOfNames; j++,ptr++) {
        cout<< *ptr ;
    }
}

Метод рисования объекта:

void makeCustomAnnot(GLenum mode){

    glEnable(GL_TEXTURE_2D);
    glColor3f(1,1,1);
    GLuint j=0;

    QImage img("img.jpg");
    img=QGLWidget::convertToGLFormat(img);

    GLuint texturesAnnot[1];
    glBindTexture( GL_TEXTURE_2D, texturesAnnot[0] );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

    if(mode == GL_SELECT){
        glPushName (j);
    }

    glBegin(GL_QUADS);
        glTexCoord2d(0,0);glVertex3d(x4,y4,z4);
        glTexCoord2d(1,0);glVertex3d(x3,y3,z3);
        glTexCoord2d(1,1);glVertex3d(x2,y2,z2);
    glTexCoord2d(0,1);glVertex3d(x1,y1,z1);
    glEnd();

    if(mode == GL_SELECT)
        glPopName ();
    }

    glDisable(GL_TEXTURE_2D);
}

Метод рендеринга:

void render()
{
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0,0,this->width() , this->height());

    gluPerspective(fov, this->width() / this->height(), 0.1, 1000);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glRotatef(xRot / 5.0f, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot / 5.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(zRot / 5.0f, 0.0f, 0.0f, 1.0f);

    glPushMatrix();
        makeCustomAnnot(GL_RENDER);
    glPopMatrix();

    glDisable(GL_DEPTH_TEST);
}

Итак, hits = glRenderMode (GL_RENDER); всегда возвращает 0 совпадений. Что я делаю неправильно?


person SteveTJS    schedule 03.02.2015    source источник
comment
hits = glRenderMode (GL_SELECT); вместо этого нет?   -  person j-p    schedule 03.02.2015
comment
@ j-p Я пробовал, но все равно не работает, думаю, hits = glRenderMode (GL_RENDER); хороший, хотя заманчиво поставить GL_SELECT.   -  person SteveTJS    schedule 04.02.2015
comment
Нет идей? Я просмотрел несколько других сообщений по той же теме, но не могу понять, что делаю не так.   -  person SteveTJS    schedule 16.02.2015


Ответы (1)


Итак, вот что я сделал, чтобы он работал идеально.

Метод processHits:

void processHits(GLint inHits, GLuint buffer[])
{
    unsigned int i, j;
    GLuint names, *ptr, minZ,*ptrNames, numberOfNames;

    ptr = (GLuint *) buffer;
    minZ = 0xffffffff;
    for (i = 0; i < inHits; i++) {
        names = *ptr;
        ptr++;
        if (*ptr < minZ) {
            numberOfNames = names;
            minZ = *ptr;
            ptrNames = ptr+2;
        }
        ptr += names+2;
    }

    cout << "Nearest: ";
    ptr = ptrNames;
    for (j = 0; j < numberOfNames; j++,ptr++) {
        cout<< *ptr ;
    }
}

Метод рисования объекта с помощью создает объекты, которые мне нужно выбрать:

void makeCustomAnnot(GLenum mode){

    glEnable(GL_TEXTURE_2D);
    glColor3f(1,1,1);
    GLuint j=0;

    QImage img("img.jpg");
    img=QGLWidget::convertToGLFormat(img);

    GLuint texturesAnnot[1];
    glBindTexture( GL_TEXTURE_2D, texturesAnnot[0] );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

    if(mode == GL_SELECT)
        glLoadName (j);

    glBegin(GL_QUADS);
        glTexCoord2d(0,0);glVertex3d(x4,y4,z4);
        glTexCoord2d(1,0);glVertex3d(x3,y3,z3);
        glTexCoord2d(1,1);glVertex3d(x2,y2,z2);
    glTexCoord2d(0,1);glVertex3d(x1,y1,z1);
    glEnd();

    glDisable(GL_TEXTURE_2D);
}

Метод pickObjects, идентичный функции рендеринга, но с инструкциями по выбору:

#define BUFSIZE 512
unsigned int selectBuf[BUFSIZE];

void pickObjects(int x, int y)
{
    GLint viewport[4];
    GLint hits;

    glSelectBuffer (BUFSIZE, selectBuf);
    glRenderMode (GL_SELECT);

    glMatrixMode (GL_PROJECTION);
    glPushMatrix ();
    glLoadIdentity ();

    glGetIntegerv (GL_VIEWPORT, viewport);

    gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
    gluPerspective(fov, this->width() / this->height(), 0.1, 1000);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    glRotatef(xRot / 5.0f, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot / 5.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(zRot / 5.0f, 0.0f, 0.0f, 1.0f);

    glRotatef((float)angleV, 1.0f, 0.0f, 0.0f);

    glInitNames();
    glPushName( 10000 );

    glPushMatrix();
        makeCustomAnnot(GL_SELECT);//draw scene in GL_SELECT mode to create the names
    glPopMatrix();

    hits = glRenderMode (GL_RENDER);//get the hits in GL_RENDER mode
    if (hits != 0)
    {
        processHits(hits,selectBuf);
    }

    glPopMatrix();
    glDisable(GL_DEPTH_TEST);
}

Метод рендеринга:

void render()
{
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0,0,this->width() , this->height());

    gluPerspective(fov, this->width() / this->height(), 0.1, 1000);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glRotatef(xRot / 5.0f, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot / 5.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(zRot / 5.0f, 0.0f, 0.0f, 1.0f);

    glRenderMode (GL_RENDER);

    glPushMatrix();
        makeCustomAnnot(GL_RENDER);
    glPopMatrix();

    glDisable(GL_DEPTH_TEST);
}

И, наконец, hits = glRenderMode (GL_RENDER); в методе pickObjects, а затем метод processHits возвращает именно выбранный объект.

person SteveTJS    schedule 27.02.2015
comment
@ j-p Может быть, но почему против проголосовали за ответ, раз уж он работает. И после некоторых исследований, все найденные мной руководства по выбору, с использованием glRenderMode, делают hits = glRenderMode (GL_RENDER); а не hits = glRenderMode (GL_SELECT); Примеры: opengl.org/archives/resources/faq/technical/selection. htm glprogramming.com/red/chapter13.html Итак, не совсем глупо, потому что, по-видимому, так оно и работает! И я надеюсь, что психиатру будет интересно проанализировать интеллектуальный процесс, стоящий за этим, не для меня, поскольку я не тот, кто создал OpenGL и решил, как он работает. - person SteveTJS; 03.04.2015
comment
Вы совершенно правы, извините. (если вы внесете незначительные изменения в свои сообщения (q / a)) Я смогу сбросить голосование против. - person j-p; 03.04.2015