Skip to main content
GameDev.net gamedev.net
🔒 Locked

Selection and occlusion.

Started by bluntman Apr 26, 2006 at 5:24 AM 2 replies 650+ views
Original Post
bluntman
bluntman
I have set up a system for selecting points on a mesh which works by drawing all the points, and getting thier 2D (screen) positions (using Feedback). Then when a selection box is drawn, all the points which fall within it are added to a list. For each point (potential selection) a pixel is read from the depth buffer (I know, slow!) and compared to the depth value from the selection buffer. If the value in the selection buffer indicates that the point associated with it is at the front of the depth buffer, then the point can be selected (or deselected). Firstly, can anyone recommend a better system that will still take into account whether the points are actually visible/occluded? Secondly, the system as it is has problems. When the point to be selected is very close to the camera, the comparison between depth values becomes inaccurate, and selection doesn't work correctly. Heres the code:

    // set feeback mode
    glSelectBuffer(FEEDBACK_BUFSIZE-1, FeedbackBuffer);

    // Init. feedback buffer
    glRenderMode(GL_SELECT);

    glInitNames();
    glPushName(0);

    // draw a feedback render
    Refresh(m_nLastFrame, DT_SELECTION);

    //Sleep(2000);

    // go back to visible render mode
    SelectBufferSize = glRenderMode(GL_RENDER);

    // draw a feedback render
    Refresh(m_nLastFrame, DT_DEPTH_SELECTION);

    glReadBuffer(GL_BACK);
//    Sleep(2000);

    // loop through the feedback buffer and parse out any objects which were drawn
    buf_ptr = 0;

    Events::ObjectsEventData selectionData, deselectionData;

    unsigned int *buffer = FeedbackBuffer;
    float zeps = (0.000015*GeoForm->m_Data.m_OverlayOffset);
    while (buf_ptr < SelectBufferSize)
    {
    	int hits = *buffer;
        buffer++;
        float zval = (GLfloat)*buffer/0xffffffff;
        buffer++;
        //float zval2 = (GLfloat)*buffer/0xffffffff;
        buffer++;

        buf_ptr++;
        for(i=0; i<hits; i++)
        {
        	selectionname = *buffer;
            buffer++;
//            bool TFrameData::GetPTInfo(float pt, char *name, float *ptbase, float *ptrange)
            m_DataStore->m_Framedata.GetPTInfo(selectionname, ptname, &ptbase, &ptrange);

			index = m_DataStore->m_Framedata.Index(ptname, &type);

            if(m_DataStore->m_Framedata.GetPointer(ptname, &tgv)==FL_OK)
            {
            	if(tgv.Type() == GVMESH)
                {
                    // now we need to find the relating x and y screen coordinates
                    fbr = FindFeedbackRecord(index, (selectionname - ptbase)-1);
                    if(fbr != NULL)
                    {
                        bool cansel = true;
                        if(!WireframeMeshes->Checked)
                        {
                            cansel = false;
                            GLfloat depthbuff[1];
                            glReadPixels(fbr->x, fbr->y, 1, 1, GL_DEPTH_COMPONENT,
                                GL_FLOAT, (GLvoid *)depthbuff);

                            if(zval>(depthbuff[0]-zeps)
                                    && zval<(depthbuff[0]+zeps))
                                cansel = true;
                        }
                        if(cansel)
                        {
                            // check for a hit on the planar projection plane
                            if(selectionname == ptbase)
                            {
                                if(m_SelectionType == ST_INVERT)
                                {
                                    if (m_DataStore->m_Framedata.Selected(ptname, MESHTEXTUREPLANE, 0))
                                    {
                                        m_DataStore->m_Framedata.DeSelect(ptname, MESHTEXTUREPLANE, 0);
                                        deselectionData.AddRecord(ptname, MESHTEXTUREPLANE);
                                    }
                                    else
                                    {
                                        m_DataStore->m_Framedata.Select(ptname, MESHTEXTUREPLANE, 0);
                                        selectionData.AddRecord(ptname, MESHTEXTUREPLANE, 0);
                                    }
                                }
                                else if(m_SelectionType == ST_ADD &&
                                        !m_DataStore->m_Framedata.Selected(ptname, MESHTEXTUREPLANE, 0))
                                {
                                    m_DataStore->m_Framedata.Select(ptname, MESHTEXTUREPLANE, 0);
                                    selectionData.AddRecord(ptname, MESHTEXTUREPLANE);
                                }
                                else if(m_SelectionType == ST_SUBTRACT &&
                                        m_DataStore->m_Framedata.Selected(ptname, MESHTEXTUREPLANE, 0))
                                {
                                    m_DataStore->m_Framedata.DeSelect(ptname, MESHTEXTUREPLANE, 0);
                                    deselectionData.AddRecord(ptname, MESHTEXTUREPLANE);
                                }
                                GeoForm->m_Data.ObjectSelectionChanged(ptname);
                            }
                            // check for hit on pivot
                            else if(selectionname == ptbase+1)
                            {
                                if(m_SelectionType == ST_INVERT)
                                {
                                    if (m_DataStore->m_Framedata.Selected(ptname, MESHPIVOT, 0))
                                    {
                                        m_DataStore->m_Framedata.DeSelect(ptname, MESHPIVOT, 0);
                                        deselectionData.AddRecord(ptname, MESHPIVOT);
                                    }
                                    else
                                    {
                                        m_DataStore->m_Framedata.Select(ptname, MESHPIVOT, 0);
                                        selectionData.AddRecord(ptname, MESHPIVOT);
                                    }
                                }
                                else if(m_SelectionType == ST_ADD &&
                                        !m_DataStore->m_Framedata.Selected(ptname, MESHPIVOT, 0))
                                {
                                    m_DataStore->m_Framedata.Select(ptname, MESHPIVOT, 0);
                                    selectionData.AddRecord(ptname, MESHPIVOT);
                                }
                                else if(m_SelectionType == ST_SUBTRACT &&
                                        m_DataStore->m_Framedata.Selected(ptname, MESHPIVOT, 0))
                                {
                                    m_DataStore->m_Framedata.DeSelect(ptname, MESHPIVOT, 0);
                                    selectionData.AddRecord(ptname, MESHPIVOT);
                                }

                                GeoForm->m_Data.ObjectSelectionChanged(ptname);
                            }
                            else
                            {
                                // find out the index of the actual point hit
                                int meshcomponentindex = (selectionname - ptbase) - 2;
                                if(m_SelectionType == ST_INVERT)
                                {
                                    if (m_DataStore->m_Framedata.Selected(ptname, MESHPOINT,
                                            meshcomponentindex))
                                    {
                                        m_DataStore->m_Framedata.DeSelect(ptname, MESHPOINT,
                                            meshcomponentindex);
                                        deselectionData.AddRecord(ptname, MESHPOINT, meshcomponentindex);
                                    }
                                    else
                                    {
                                        m_DataStore->m_Framedata.Select(ptname, MESHPOINT,
                                            meshcomponentindex);
                                        selectionData.AddRecord(ptname, MESHPOINT, meshcomponentindex);
                                    }
                                }
                                else if(m_SelectionType == ST_ADD &&
                                        !m_DataStore->m_Framedata.Selected(ptname, MESHPOINT, meshcomponentindex))
                                {
                                    m_DataStore->m_Framedata.Select(ptname, MESHPOINT,
                                        meshcomponentindex);
                                    selectionData.AddRecord(ptname, MESHPOINT, meshcomponentindex);
                                }
                                else if(m_SelectionType == ST_SUBTRACT &&
                                        m_DataStore->m_Framedata.Selected(ptname, MESHPOINT, meshcomponentindex))
                                {
                                    m_DataStore->m_Framedata.DeSelect(ptname, MESHPOINT,
                                        meshcomponentindex);
                                    deselectionData.AddRecord(ptname, MESHPOINT, meshcomponentindex);
                                }

                                //DepthMapSequenceForm->MeshPointSelectionChanged(tgv.Name());
                                //GeoForm->m_Data.ObjectSelectionChanged(ptname, meshcomponentindex);
                            }
                        }
                    }
                }
            	else
                {
                    // now we need to find the relating x and y screen coordinates
                    fbr = FindFeedbackRecord(index, (selectionname - ptbase)-1);
                    if(fbr != NULL)
                    {
                        GLfloat depthbuff[1];
                        glReadPixels(fbr->x, fbr->y, 1, 1, GL_DEPTH_COMPONENT,
                            GL_FLOAT, (GLvoid *)depthbuff);

                        if(zval>(depthbuff[0]-0.000005) && zval<(depthbuff[0]+0.000005))
                        {
                            if(m_SelectionType == ST_INVERT)
                            {
                                // check for a hit on the planar projection plane
                                if (m_DataStore->m_Framedata.Selected(ptname))
                                {
                                    m_DataStore->m_Framedata.DeSelect(ptname);
                                    deselectionData.AddRecord(ptname);
                                }
                                else
                                {
                                    m_DataStore->m_Framedata.Select(ptname);
                                    selectionData.AddRecord(ptname);
                                }
                            }
                            else if(m_SelectionType == ST_ADD &&
                                    !m_DataStore->m_Framedata.Selected(ptname))
                            {
                                m_DataStore->m_Framedata.Select(ptname);
                                selectionData.AddRecord(ptname);
                            }
                            else if(m_SelectionType == ST_SUBTRACT &&
                                    m_DataStore->m_Framedata.Selected(ptname))
                            {
                                m_DataStore->m_Framedata.DeSelect(ptname);
                                deselectionData.AddRecord(ptname);
                            }

                            //GeoForm->m_Data.ObjectSelectionChanged(ptname);
                        }
                    }
                }
            }
        }
    }

Thanks!
zedzeek
zedzeek
the quickest way is to do it all yourself on the cpu.
first find out all the points that are with the area.
+ then for each of these cast a ray from it to the camera position + see if it intersects any polygons
Palidine
Palidine
If you have bounding boxes/spheres around every object and have those objects in a nice container (octtree/quadtree) you can do a simple first pass line/box or line/sphere collision test through your spatial partition tree. Then sort the objects by distance to camera. Then do a detail ray/mesh collision and take the first one that collides in your list.

-me
bluntman
bluntman
Oh, sorry, this isn't for a games application, its a modelling application! Generally there is only one model loaded at a time. And the model is constantly altered (by the user), so not sure how well a bsp/octree would work, and without an octree then the cpu intersection algo would be slow correct?
Using occlusion query occured to me, but I need something that will work on fx series upwards (radeons aswell preferably), not sure if OQ is implemented on these.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.