OpenGL - 鼠标选择与拾取

来源:互联网 发布:mac系统降级10.12 编辑:程序博客网 时间:2024/05/16 14:51

看《OpenGL编程指南》里第13章选择与反馈,有些云里雾里,于是上网搜一些关于这方面的来看,终于觉得弄清楚一点了,在这里写下些我的理解。

首先推荐看一篇博文 http://blog.sina.com.cn/s/blog_4a9aa55c0100vu57.html (文章1),我是看了这个才明白的,然后又看了http://blog.sina.com.cn/s/blog_6923201d01011hur.html(文章2)里面的例子。还有一篇文章,非常强大的从矩阵和投影变换原理方面解释了选择的原理:http://hi.baidu.com/ayokawamadoka/item/74a9af254c063afb51fd8740 (文章三)。这里只说说我理解的一些部分。

1.glLoadName()和glPushName()

文章1和2的例子用到了glLoadName();,我开始不明白它与glPushName()的区别,后来查了下:

void glLoadName(GLuint name):
  用name取代名字栈栈顶的那个名字。如果栈是空的,刚调用过glInitName()后就是这样,glLoadName()生成一个GL_INVALID_OPRATION错。为避免这种情况,如果栈初始时是空的,那么在调用glLoadName()之前至少调用一次glPushName()以在名字栈中放上点东西。

void glPushName(GLuint name);
  将name压入名字栈。压入名字超过栈容量时将生成一个GL_STACK_OVERFLOW错误。名字栈深度因OpenGL实现(implementations)不同而不同,但最少要能容纳64个名字。你可以用参数GL_NAME_STACK_DEPTH调用glGetIntegerv()以获取名字栈深度。

也就是说,用glLoadName()可以直接将当前这个名字取代名字栈顶的名字,这样就可以直接用了,但是在初始化时要 :加上glPushName(0);

        glInitNames();//初始化名称栈
        glPushName(0);//要加上这句代码
而glPushName()只是从栈尾加入名字,所以使用后一般要将之前的push进来的pop出去(我暂时这么理解,还不十分确定):

........... 

  if (GL_SELECT)
    {
        glPushName(id);
    }

   drawSomething();

     if (GL_SELECT)
    {
        glPopName();//将之前旧的pop出去
    }

...........

2.processHits(hits,selectBuf) 处理点击记录函数。这里我改动文章1的例子,来阐述我的理解:


//hits为产生的点击的数量,buffer中存储点击记录,每个点击记录由四个项目组成
void processHits(GLint hits, GLuint buffer[])
{
 
unsigned int i, j;
 
GLuint ii, jj, names, *ptr;

 ptr = ( GLuint *)buffer;   

 for( i=0; i<hits; i++)   //处理每一个点击记录
 

       /* 这里是我参考文章1,加上我自己的理解:
        某一个点击记录来说,由四个项目组成:
        (1)当点击发生时,名字堆栈中的名称数量 names - 即:选中物体的个数
        (2,3)自上一个点击记录之后,与视景体相交的所有顶点的最小和最大窗口坐标z值
        (4)当点击发生时,名称堆栈的内容,从最底部的元素开始 (元素一共names个)
        */

      names =*ptr;     //获得名字堆栈中的名称数量
     
ptr +=3;              //跳过前三个记录----直接到栈底元素

      for( j=0;j<names; j++ ) //开始处理名字堆栈中的内容

     {
 
      //访问名字栈里每一个内容

          i= *ptr;
 
        ptr++;
     }

      //如果没有上面for()循环依次访问名字栈的内容,则这里应该写:ptr += names;//跳到下一轮hit点击记录

 }

}


暂时就这些,如果后面有新发现或改动我再补充。


原创粉丝点击