首页 > 代码库 > 可视化入门3:拾取

可视化入门3:拾取

opengl 拾取方式有二:
其一:视景体拾取
1.绘制:
需要有函数在两种模式下绘制相同的对象;
void RenderObjects(GLuint mode){
         if(mode==GL_SELECT){
          glLoadName(name); //设置名字
          drawObj();
}else{
         drawObj();
}
}

2.鼠标处理:

在选择模式下绘制

注意:1.正确的设置拾取视景体;并且还原原始的视景体;

            2.正确的使用原始的模型视图变换;不一定需要还原(如果模型视图没有变化);

            3.正确的还原原始的渲染状态;注意下划线;

        GLuint selectBuff[512];

        GLint hits, viewport[4];

        glSelectBuffer(512, selectBuff);

        glGetIntegerv(GL_VIEWPORT, viewport);

        glRenderMode(GL_SELECT);//进入选择模式,一下绘制不再显示;

        glInitNames();

          glPushName(0);

          int n = 3;//拾取浮动范围;

        glMatrixMode(GL_PROJECTION);

        glPushMatrix(); //保存视图矩阵;

       glLoadIdentity();//归零,用于重新计算;

            gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), n, n, viewport);

            gluPerspective(60.0,(GLsizei)5 / (GLsizei)5,0.1 , 10.0); //设定失去视景体;

           gluOrtho2D(-0.6,0.6,0.6,0.6);

            glMatrixMode(GL_MODELVIEW);

           glPushMatrix();

   {

    glTranslatef(0,0,-9.0f);

    glTranslatef(dx,dy,dz);

    glRotatef(angle,0, 1.0f, 0);

    glTranslatef(-96.0f,-94.0f,-56.0f);

   }//选择模式下的模型视图变化*/

            RenderObjects(GL_SELECT);//以选择模式绘制;进入绘制部分

   glPopMatrix();

   glMatrixMode(GL_PROJECTION);

            glPopMatrix();

          glMatrixMode(GL_MODELVIEW);

            hits = glRenderMode (GL_RENDER);

             processHits(hits,selectBuff);

3.处理部分:注意每个拾取的数据结构即可;

击中的物件的名字的数目
这个物件中最近的点的深度值
这个物件中最远的点的深度值
击中的物件的名字之一
击中的物件的名字之二 
(若有多个名字,则如此类推...)

void processHits(GLint hits,GLuint buffer[]){/**/

 printf("hits = %d\n",hits);

 GLuint *ptr = (GLuint *)buffer;

 GLuint names;

 for(int i = 0;i<hits;i++){

  names = *ptr;

  //printf("numeber of names for this hit = %d ",names);

   ptr++;

  //printf("\t z1 is %f \n",(float)*ptr/0x7fffffff);

   ptr++;

  //printf("\t z1 is %f \n",(float)*ptr/0x7fffffff);

   ptr++;

  //printf("\t name are : %d \n" , *ptr);

  hited.push_back(*ptr);

  ptr++;

 }

 glutPostRedisplay();

}

4.gluPickMatrix()的使用;

5.各种矩阵的获取与使用;

 



其二:射线拾取

 

第一步: 
实现屏幕坐标到三维世界空间坐标的转化,利用函数 gluUnProject直接可以得到屏幕坐标相应的三维空间坐标。

[cpp] view plaincopy
  1. gluUnProject((GLdouble)xpos,(GLdouble)ypos,1.0,mvmatrix,projmatrix,viewport,&wx,&wy,&wz);    
  2. //xpos,ypos 是以屏幕左下角为原点的屏幕坐标.   
  3. //1.0代表返回zbuffer为1.0处(远剪切面交点)的世界坐标   
  4. //mvmatrix 为视矩阵,通过GetDoublev(GL_MODELVIEW_MATRIX,mvmatrix)得到   
  5. //projmatrix为投影矩阵,通过glGetDoublev(GL_PROJECTION_MATRIX,projmatrix)得到   
  6. //viewport为视口,通过glGetIntegerv(GL_VIEWPORT,viewport)得到   
  7. //wx、wy、wz 就是我们要得到的世界坐标,得到这样两个世界坐标,射线就确定了   
  8. //或者也可以用原点(视点)来代替其中一个点,因为这条射线是从视点出发的。  
 

第二步: 
射线和要检测的三角形求交点,用到的原理和公式如下。 
原理一:三角形内的任意一点都可以用变量u、v和其三个顶点坐标来确定

[cpp] view plaincopy
  1. vPoint = V1 + u*(V2-V1) + v*(V3-V1) ;   
  2. //0   
  3. //V1,V2,V3为三角形的三个顶点,是已知量  
 

原理二:射线上的任意一点可以用射线的方向向量(格式化后的)乘以其模(该向量长度)来表示

[cpp] view plaincopy
  1. vPoint =originPoint+dir * len;  
射线和三角形相交则必定同时满足上面的两个条件所以有:
[cpp] view plaincopy
  1. (-Dir)*len+ (V2-V1)*u + (V3-V1)*v = originPoint-V1;  

 

 

可视化入门3:拾取