Original Post
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: Thanks!
// 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);
}
}
}
}
}
}