From 9f6d5f1d84580bc10733e1cfb0ddace8a7f19aaa Mon Sep 17 00:00:00 2001 From: cignoni Date: Tue, 8 Apr 2014 09:37:44 +0000 Subject: [PATCH] Completed the rewriting all the picking stuff. Now the default is NOT using OpenGL. And it is actually faster on all the machines I have tested... --- wrap/gl/pick.h | 651 +++++++++++++++++++------------------------------ 1 file changed, 257 insertions(+), 394 deletions(-) diff --git a/wrap/gl/pick.h b/wrap/gl/pick.h index 21fcff72..a229e8ca 100644 --- a/wrap/gl/pick.h +++ b/wrap/gl/pick.h @@ -20,16 +20,7 @@ * for more details. * * * ****************************************************************************/ -/**************************************************************************** - History -$Log: not supported by cvs2svn $ -Revision 1.10 2006/12/07 00:39:22 cignoni -Added a class prototype for avoiding the inclusion of tetra.h -Revision 1.9 2006/12/04 09:27:13 cignoni -Removed useless include - -****************************************************************************/ #ifndef __PICK______H #define __PICK______H @@ -40,77 +31,125 @@ namespace vcg{ template class GLPickTri { - typedef typename MESH_TYPE::FaceIterator FaceIterator; + typedef typename MESH_TYPE::FaceIterator FaceIterator; typedef typename MESH_TYPE::VertexIterator VertexIterator; typedef typename MESH_TYPE::FacePointer FacePointer; typedef typename MESH_TYPE::VertexPointer VertexPointer; typedef typename MESH_TYPE::VertexType VertexType; -public: +private: - static bool PickNearestFace(int x, int y, MESH_TYPE &m, FacePointer &fi,int width=4, int height=4) + static Point3f Proj(const Eigen::Matrix4f &M, const float * viewport, const Point3f &p) { - std::vector result; - int val=PickFace(x,y,m,result,width,height); - if(val!=0) - { - fi=result[0]; - return true; - } - fi=NULL; - return false; + const float vx=viewport[0]; + const float vy=viewport[1]; + const float vw2=viewport[2]/2.0f; + const float vh2=viewport[3]/2.0f; + Eigen::Vector4f vp(p[0],p[1],p[2],1.0f); + Eigen::Vector4f vpp = M*vp; + Eigen::Vector4f ndc = vpp/vpp[3]; + + Point3f sc( + vw2*ndc[0] + vx+vw2, + vh2*ndc[1] + vy+vh2, + ndc[2] + ); + + return sc; } + static void FillProjectedVector(MESH_TYPE &m, std::vector &pVec, const Eigen::Matrix4f &M, const float * viewportF) + { + pVec.resize(m.vert.size()); + for(size_t i=0;i &pVec, const Eigen::Matrix4f &M, const float * viewportF) - { - pVec.resize(m.vert.size()); - for(size_t i=0;i(); + } - static int PickVertSW(int x, int y, MESH_TYPE &m, std::vector &result, int width=4, int height=4,bool sorted=true) + // compute a bbox in Device Coordinate (with the z without the near far normalization and ranged in -1 1) + static Box3f ComputeDCBox(int x, int y, int width, int height) + { + Box3f bb; + bb.SetNull(); + bb.Add(Point3f(x-width/2.0f,y-height/2.0f,-1.0f)); + bb.Add(Point3f(x+width/2.0f,y+height/2.0f, 1.0f)); + return bb; + } + +public: + + static bool PickClosestFace(int x, int y, MESH_TYPE &m, FacePointer &fp,int width=4, int height=4) + { + Eigen::Matrix4f M; + float viewportF[4]; + glGetMatrixAndViewport(M,viewportF); + Box3f reg=ComputeDCBox(x,y,width,height); + + float bzmin = std::numeric_limits::max(); + fp=0; + for(size_t i=0;i::max(); + vp=0; + + Box3f reg=ComputeDCBox(x,y,width,height); + + for(size_t i=0;i &result, int width=4, int height=4) { result.clear(); - Eigen::Matrix4d mp,mm; - Eigen::Matrix4f M; static Eigen::Matrix4f lastM; static MESH_TYPE *lastm=0; static std::vector pVec; - GLint viewport[4]; - Box2f reg; - reg.Add(Point2f(x-width/2.0f,y-height/2.0f)); - reg.Add(Point2f(x+width/2.0f,y+height/2.0f)); - glGetIntegerv(GL_VIEWPORT,viewport); + Eigen::Matrix4f M; float viewportF[4]; - for(int i=0;i<4;++i) viewportF[i]=viewport[i]; + glGetMatrixAndViewport(M,viewportF); - glGetDoublev(GL_PROJECTION_MATRIX, mp.data()); - glGetDoublev(GL_MODELVIEW_MATRIX, mm.data()); - - M = (mp*mm).cast(); + Box3f reg =ComputeDCBox(x,y,width,height); if(M!=lastM || &m != lastm) { @@ -121,99 +160,25 @@ public: for(size_t i=0;ireg.max[0]) continue; - if(pp[1]reg.max[1]) continue; - result.push_back(&m.vert[i]); + if(reg.IsIn(pVec[i])) + result.push_back(&m.vert[i]); } return result.size(); } - static int PickVert(int x, int y, MESH_TYPE &m, std::vector &result, int width=4, int height=4,bool sorted=true) + static int PickFace(int x, int y, MESH_TYPE &m, std::vector &result, int width=4, int height=4) { - result.clear(); - if(width==0 ||height==0) return 0; - long hits; - int sz=m.vert.size()*5; - GLuint *selectBuf =new GLuint[sz]; - glSelectBuffer(sz, selectBuf); - glRenderMode(GL_SELECT); - glInitNames(); - - /* Because LoadName() won't work with no names on the stack */ - glPushName(-1); - double mp[16]; - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT,viewport); - glMatrixMode(GL_PROJECTION); - glGetDoublev(GL_PROJECTION_MATRIX ,mp); - glPushMatrix(); - glLoadIdentity(); - gluPickMatrix(x, y, width, height, viewport); - glMultMatrixd(mp); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - int vcnt=0; - VertexIterator vi; - for(vi=m.vert.begin();vi!=m.vert.end();++vi) - { - if(!(*vi).IsD()) - { - glLoadName(vcnt); - glBegin(GL_POINTS); - glVertex( (*vi).P() ); - glEnd(); - } - vcnt++; // the counter should advance even for deleted faces! - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - hits = glRenderMode(GL_RENDER); - std::vector< std::pair > H; - for(long ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); - } - if(sorted) - std::sort(H.begin(),H.end()); - result.resize(H.size()); - for(long ii=0;ii &result, int width=4, int height=4) - { - result.clear(); - Eigen::Matrix4d mp,mm; - Eigen::Matrix4f M; static Eigen::Matrix4f lastM; static MESH_TYPE *lastm=0; static std::vector pVec; - GLint viewport[4]; + float viewportF[4]; + Eigen::Matrix4f M; + glGetMatrixAndViewport(M,viewportF); + result.clear(); Box3f reg; reg.Add(Point3f(x-width/2.0f,y-height/2.0f,-1.0f)); reg.Add(Point3f(x+width/2.0f,y+height/2.0f,1.0f)); - glGetIntegerv(GL_VIEWPORT,viewport); - float viewportF[4]; - for(int i=0;i<4;++i) viewportF[i]=viewport[i]; - - glGetDoublev(GL_PROJECTION_MATRIX, mp.data()); - glGetDoublev(GL_MODELVIEW_MATRIX, mm.data()); - - M = (mp*mm).cast(); if(M!=lastM || &m != lastm) { @@ -227,84 +192,50 @@ public: const Point3f &p0 = pVec[tri::Index(m,m.face[i].V(0))]; const Point3f &p1 = pVec[tri::Index(m,m.face[i].V(1))]; const Point3f &p2 = pVec[tri::Index(m,m.face[i].V(2))]; - if(IntersectionTriangleBox(reg,p0,p1,p2)) + if( (p0[2]>-1.0f) && (p1[2]>-1.0f) && (p2[2]>-1.0f) && IntersectionTriangleBox(reg,p0,p1,p2)) result.push_back(&m.face[i]); } return result.size(); } - static int PickFace(int x, int y, MESH_TYPE &m, std::vector &result, int width=4, int height=4,bool sorted=true) + + // Same of above but it also assumes that you want only visible faces. + // Visibility is computed according to the current depth buffer. + static int PickVisibleFace(int x, int y, MESH_TYPE &m, std::vector &resultZ, int width=4, int height=4) + { + float vp[4]; + Eigen::Matrix4f M; + glGetMatrixAndViewport(M,vp); + + int screenW = (int)(vp[2]-vp[0]); + int screenH = (int)(vp[3]-vp[1]); + + GLfloat *buffer = new GLfloat[screenW*screenH]; + glReadPixels(vp[0],vp[1],vp[2],vp[3],GL_DEPTH_COMPONENT,GL_FLOAT,buffer); + + std::vector result; + PickFace(x,y,m,result,width,height); + float LocalEpsilon = 0.001f; + for(size_t i =0;iP() ); - glVertex( (*fi).V(1)->P() ); - glVertex( (*fi).V(2)->P() ); - glEnd(); - } - fcnt++; // the counter should advance even for deleted faces! - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - hits = glRenderMode(GL_RENDER); - //xstring buf; - //if (hits <= 0) return 0; - std::vector< std::pair > H; - for(long ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); - } - if(sorted) - std::sort(H.begin(),H.end()); - // if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second); - result.resize(H.size()); - for(long ii=0;ii=0 && p[0]=0 && p[1]= (p[2]+1.0)/2.0f) + resultZ.push_back(result[i]); + } } + delete [] buffer; + return resultZ.size(); + } + + + // Same of above but it also assumes that you want only visible faces. // Visibility is computed according to the current depth buffer. - static int PickFaceVisible(int x, int y, MESH_TYPE &m, std::vector &resultZ, int width=4, int height=4, bool sorted=true) + static int OldPickFaceVisible(int x, int y, MESH_TYPE &m, std::vector &resultZ, int width=4, int height=4, bool sorted=true) { // First step @@ -321,7 +252,7 @@ public: glReadPixels(vp[0],vp[1],vp[2],vp[3],GL_DEPTH_COMPONENT,GL_FLOAT,buffer); std::vector result; - PickFace(x,y,m,result,width,height,sorted); + OldPickFace(x,y,m,result,width,height,sorted); float LocalEpsilon = 0.001f; for(size_t i =0;i &result, int width=4, int height=4,bool sorted=true) + { + result.clear(); + if(width==0 ||height==0) return 0; + long hits; + int sz=m.face.size()*5; + GLuint *selectBuf =new GLuint[sz]; + // static unsigned int selectBuf[16384]; + glSelectBuffer(sz, selectBuf); + glRenderMode(GL_SELECT); + glInitNames(); -////////////////////////////////////////////////////////////////////////// -template -class GLPickTetra -{ - typedef typename TETRA_MESH_TYPE::TetraIterator TetraIterator; - typedef typename TETRA_MESH_TYPE::TetraPointer TetraPointer; - typedef typename TETRA_MESH_TYPE::VertexType VertexType; + /* Because LoadName() won't work with no names on the stack */ + glPushName(-1); + double mp[16]; -public: -static bool PickNearestTetra(int x, int y,TETRA_MESH_TYPE &m, TetraIterator &ti,int width=4, int height=4) -{ - std::vector result; - int val=PickTetra(x,y,m,result,width,height); - if(val!=0) - { - ti=result[0]; - return true; - } - ti=0; - return false; -} + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT,viewport); + glMatrixMode(GL_PROJECTION); + glGetDoublev(GL_PROJECTION_MATRIX ,mp); + glPushMatrix(); + glLoadIdentity(); + //gluPickMatrix(x, viewport[3]-y, 4, 4, viewport); + gluPickMatrix(x, y, width, height, viewport); + glMultMatrixd(mp); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + int fcnt=0; + FaceIterator fi; + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + if(!(*fi).IsD()) + { + glLoadName(fcnt); + glBegin(GL_TRIANGLES); + glVertex( (*fi).V(0)->P() ); + glVertex( (*fi).V(1)->P() ); + glVertex( (*fi).V(2)->P() ); + glEnd(); + } + fcnt++; // the counter should advance even for deleted faces! + } -// class prototype needed for avoid the inclusion of tetra.h -class Tetra; + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + hits = glRenderMode(GL_RENDER); + //xstring buf; + //if (hits <= 0) return 0; + std::vector< std::pair > H; + for(long ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); + } + if(sorted) + std::sort(H.begin(),H.end()); + // if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second); + result.resize(H.size()); + for(long ii=0;ii &result, int width=4, int height=4) -{ - result.clear(); - long hits; - int sz=m.tetra.size()*5; - unsigned int *selectBuf =new unsigned int[sz]; - // static unsigned int selectBuf[16384]; - glSelectBuffer(sz, selectBuf); - glRenderMode(GL_SELECT); - glInitNames(); + delete [] selectBuf; + return result.size(); + } - /* Because LoadName() won't work with no names on the stack */ - glPushName(-1); - double mp[16]; - - int viewport[4]; - glGetIntegerv(GL_VIEWPORT,viewport); - glMatrixMode(GL_PROJECTION); - glGetDoublev(GL_PROJECTION_MATRIX ,mp); - glPushMatrix(); - glLoadIdentity(); - //gluPickMatrix(x, viewport[3]-y, 4, 4, viewport); - gluPickMatrix(x, y, width, height, viewport); - glMultMatrixd(mp); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - int tetracnt=0; - TetraIterator ti; - for(ti=m.tetra.begin();ti!=m.tetra.end();++ti) + static int OldPickVert(int x, int y, MESH_TYPE &m, std::vector &result, int width=4, int height=4,bool sorted=true) { - if(!(*ti).IsD()) - { - glLoadName(tetracnt); - glBegin(GL_TRIANGLES); - for (int face=0;face<4;face++) - { - //glLoadName(tetracnt); - VertexType *v0=ti->V(Tetra::VofF(face,0)); - VertexType *v1=ti->V(Tetra::VofF(face,1)); - VertexType *v2=ti->V(Tetra::VofF(face,2)); - glVertex(v0->P()); - glVertex(v1->P()); - glVertex(v2->P()); + result.clear(); + if(width==0 ||height==0) return 0; + long hits; + int sz=m.vert.size()*5; + GLuint *selectBuf =new GLuint[sz]; + glSelectBuffer(sz, selectBuf); + glRenderMode(GL_SELECT); + glInitNames(); - } + /* Because LoadName() won't work with no names on the stack */ + glPushName(-1); + double mp[16]; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT,viewport); + glMatrixMode(GL_PROJECTION); + glGetDoublev(GL_PROJECTION_MATRIX ,mp); + glPushMatrix(); + glLoadIdentity(); + gluPickMatrix(x, y, width, height, viewport); + glMultMatrixd(mp); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + int vcnt=0; + VertexIterator vi; + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + { + if(!(*vi).IsD()) + { + glLoadName(vcnt); + glBegin(GL_POINTS); + glVertex( (*vi).P() ); glEnd(); - tetracnt++; + } + vcnt++; // the counter should advance even for deleted faces! } - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - hits = glRenderMode(GL_RENDER); - //xstring buf; - //if (hits <= 0) return 0; - std::vector< std::pair > H; - int ii; - for(ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); - } - std::sort(H.begin(),H.end()); -// if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second); - result.resize(H.size()); - for(ii=0;ii > result; - int val=PickTetraFace(x,y,m,result,width,height); - if(val!=0) - { - ti=result[0].first; - face=result[0].second; - return true; - } - ti=0; - face=-1; - return false; -} - -static int PickTetraFace(int x, int y, TETRA_MESH_TYPE &m, std::vector > &result, int width=4, int height=4) -{ - result.clear(); - long hits; - int sz=(m.tetra.size()*4)*5; - unsigned int *selectBuf =new unsigned int[sz]; - // static unsigned int selectBuf[16384]; - glSelectBuffer(sz, selectBuf); - glRenderMode(GL_SELECT); - glInitNames(); - - /* Because LoadName() won't work with no names on the stack */ - glPushName(-1); - double mp[16]; - - int viewport[4]; - glGetIntegerv(GL_VIEWPORT,viewport); - glMatrixMode(GL_PROJECTION); - glGetDoublev(GL_PROJECTION_MATRIX ,mp); - glPushMatrix(); - glLoadIdentity(); - //gluPickMatrix(x, viewport[3]-y, 4, 4, viewport); - gluPickMatrix(x, y, width, height, viewport); - glMultMatrixd(mp); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - int tetracnt=0; - TetraIterator ti; - VertexType *v0; - VertexType *v1; - VertexType *v2; - int face; - for(ti=m.tetra.begin();ti!=m.tetra.end();++ti) - { - if(!(*ti).IsD()) - { - for (face=0;face<4;face++){ - v0=ti->V(Tetra::VofF(face,0)); - v1=ti->V(Tetra::VofF(face,1)); - v2=ti->V(Tetra::VofF(face,2)); - glLoadName(tetracnt); - glBegin(GL_TRIANGLES); - glVertex(v0->P()); - glVertex(v1->P()); - glVertex(v2->P()); - glEnd(); - tetracnt++; - } + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + hits = glRenderMode(GL_RENDER); + std::vector< std::pair > H; + for(long ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); + } + if(sorted) + std::sort(H.begin(),H.end()); + result.resize(H.size()); + for(long ii=0;ii > H; - int ii; - for(ii=0;ii(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3])); + delete [] selectBuf; + return result.size(); } - std::sort(H.begin(),H.end()); -// if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second); - result.resize(H.size()); - for(ii=0;ii(&*ti,index%4); - } - - delete [] selectBuf; - return result.size(); -} }; - } #endif