简体   繁体   English

OpenGL 3D选择

[英]OpenGL 3D Selection

I am trying to create a 3D robot that should perform certain actions when certain body parts are clicked. 我正在尝试创建一个3D机器人,在点击某些身体部位时应执行某些操作。 I have successfully (sort of) implemented picking in that if you click on any x-plane part, it registers a hit, but not anywhere else. 我已经成功(有点)实施了拣选,如果你点击任何x平面部分,它会记录一个命中,但不是其他任何地方。 That is, it is not registering depth, and if you clicked on it's square head, you could only register a hit by clicking on the front of the head (facing you). 也就是说,它没有注册深度,如果你点击它的方头,你只能通过点击头部的正面(面向你)来注册命中。 Obviously, I don't fully understand picking and selection and am sloppily trying to transcribe what I know about 2D selection to 3D (my teacher is as helpful as a rock) but I have left something out or not changed something pertaining to depth. 显然,我并不完全理解挑选和选择,我正在努力将我对2D选择的了解转录为3D(我的老师和摇滚一样有用),但是我遗漏了一些东西,或者没有改变与深度相关的东西。 Can anyone help me out? 谁能帮我吗? Here are the related functions. 以下是相关功能。

void processHits (GLint hits, GLuint buffer[])
{
    unsigned int i, j;
    GLint n, *ptr;

    printf ("hits = %d\n", hits);
    ptr = (GLint *) buffer;

    //For each hit.
    for (i = 0; i < hits; i++)
    {
        n = *ptr;       //Number of names under current hit.
        ptr+=3;         //Bypass three integers: n, z1, z2.
        printf ("hit %d has %d name(s)\n", i, n);

        //For each name.
        for (j = 0; j < n; j++)
        {
            if(*ptr==1) printf ("Body hit.\n");
            else if(*ptr==2) printf ("Right shoulder hit.\n");
            else if(*ptr==3) printf ("Left shoulder hit.\n");
            else if(*ptr==4) printf ("Left arm hit.\n");
            else if(*ptr==5) printf ("Right arm hit.\n");
            else if(*ptr==6) printf ("Left leg hit.\n");
            else if(*ptr==7) printf ("Right leg hit.\n");
            else if(*ptr==8) printf ("Right foot hit.\n");
            else if(*ptr==9) printf ("Left foot hit.\n");
            else if(*ptr==10) printf ("Neck hit.\n");
            else if(*ptr==11) printf ("Head hit.\n");
            else printf ("Nothing hit.\n");

            ptr++;
        }
        printf ("\n");
    }
}

void selection(int mouse_x, int mouse_y)
{
    GLuint buffer[512];                     //Set up a selection buffer.
    GLint hits;                             //The number of objects we selected.
    GLint viewport[4];                      //Viewport size. [0] Is <x>, [1] Is <y>, [2] Is <length>, [3] Is <width>.

    glGetIntegerv(GL_VIEWPORT, viewport);   //Sets the array <viewport> to size and location of screen relative to window.
    glSelectBuffer(512, buffer);            //Tell OpenGL to use our array for selection.

    glRenderMode(GL_SELECT);                //Puts OpenGL in selection mode. Nothing will be drawn. Object IDs and extents stored in buffer.

    glInitNames();                          //Initializes name stack.
    glPushName(0);                          //Push an entry onto the stack.

    glMatrixMode(GL_PROJECTION);            //Selects the projection matrix.
    glPushMatrix();                         //Push the projection matrix.
    glLoadIdentity();                       //Resets matrix.

    //This creates a matrix that will zoom up to a small portion of the screen, where the mouse is.
    gluPickMatrix((GLdouble) mouse_x, (GLdouble) (viewport[3]-mouse_y), 0.01, 0.01, viewport);

    gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);                                 //Select the modelview matrix.
    drawObjects(GL_SELECT);                                     //Render the targets to the selection buffer.
    glMatrixMode(GL_PROJECTION);                                //Select the projection matrix.
    glPopMatrix();                                              //Pop the projection matrix.
    glMatrixMode(GL_MODELVIEW);                                 //Select the modelview matrix.
    hits = glRenderMode(GL_RENDER);
    processHits (hits, buffer);

    //printf("%d ", hits);

    //Post redisplay message.
    glutPostRedisplay();
}

void mouse(int button, int state, int x, int y)
{    
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        selection(x, y);
    }
} 

It's not entirely clear what you're asking for. 你要求的并不完全清楚。 If you mean you're only getting a hit record for the object that's front-most, then that's kind of expected. 如果你的意思是你只获得了最前面的对象的命中记录,那就是那种预期。 Polygon(s) that are culled won't generate any hit record(s). 剔除的多边形不会产生任何命中记录。 If you want hit records for polygons that would normally be culled, you'll want to use glDisable(GL_CULL_FACE); 如果你想要通常被剔除的多边形的命中记录,你将需要使用glDisable(GL_CULL_FACE); while you do the drawing in selection mode. 在选择模式下进行绘图时。 This prevents polygons from being culled, so they can produce hit records. 这可以防止多边形被剔除,因此它们可以生成命中记录。

Read about Object Selection Using the Back Buffer here . 在此处阅读使用Back Buffer选择对象选择。 I implemented it once and it worked great. 我实施了一次,效果很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM