<<opengl编程基础>> 3.13 拾取和选择模式

来源:互联网 发布:mac foxmail 撤回邮件 编辑:程序博客网 时间:2024/05/16 01:20

   OpenGL中的拾取是对OpenGL图形管线的一个应用。所以OpenGL中的拾取是在图形管线投影变换(Projection Transformation)阶段利用拾取矩阵来实现的。

    1.为了理解这个过程,先来复习一下OpenGL的图形管线

 

 

pipleline 

(1)总的来说,OpenGL图形管线大体分为上面的五个阶段。在编程的时候使用glMatrixMode(GL_MODELVIEW),或者    

   glMatrixMode(GL_PROJECTION)就是告诉OpenGL我们是要在那个阶段进行操作。

(2)先来看看投影变换,因为理解投影变换是理解OpenGL拾取的前提条件。

   为了简单起见,这里以正交投影(Orthogonal Projection)为例。

   在OpenGL中,使用正交投影可以调用glOrtho (left, right, bottom, top, zNear, zFar)

   其中的六个参数分别对应正交投影视体六个平面观察坐标系原点的距离

   一旦在程序中调用了这个函数,OpenGL会马上创建根据给定的六个参数创建一个视体,并且把视体的大小归一化到-1到1之间。

   也就是说,OpenGL会自动把你给的参数所对应的x,y,z值转换为-1到1之间的值。并且这个视体的中心就是观察坐标系的原点。

   要注意的是:当视体归一化后,z轴的方向要反向,也就是说,这里OpenGL的右手坐标系要换成左手坐标系。

              原因很简单,z轴朝向显示器里的方向更符合我们的常识,越向里就离我们越远,z的值也就越大。

orthogonal

 

当我们调用了glOrtho()这个函数后,OpenGL会建立一个矩阵,也就是投影矩阵。

这个矩阵可以分解为三个步骤:

     首先,将我们设置的视体移动到观察坐标的原点

     然后,在缩放为边长为2的单位视体。因为转化后的视体坐标都在-1和1之间,所以视体的边长就是2。

     然后,再对z进行反方向。

    它就是进行移动缩放反号三个操作而已。现在我们在OpenGL中检查一下是不是进行了这样的操作。添加下面的代码。

 

(3)弄清楚了OpenGL中的投影变换,现在就开看看大家关心的拾取操作

   OpenGL的拾取就是利用投影变换中归一化视体这个操作来实现的。

   拾取的时候,我们可以想象想用一个方框来选择我们要选择的物体,比如一个边长为2的正方形。

   我们用鼠标在窗口上点击的时候一旦点到一个位置,那么就在这个位置生成一个边长为2的正方形。

   正方形内包围的物体就是我们要选择的物体,如果这个正方形内没有包围任何东西,就说明什么都没有选择到。

   这个过程就和我们归一化投影然后再剪裁的过程是一样的。OpenGL会自动剪裁掉在归一化视体之外的物体,那么如果我们把选择物体用的方框转换为用投影时的视体,那么在这个方框外的东西,也就是我们没有选择的东西,OpenGL会自动的为我们扔掉。所以OpenGL提供了选择模式glRenderMode(GL_SELECT),当我们进行拾取前进入这个模式,然后设定好我们的选择框的大小,再为我们要选择的物体设定好名字,也就是我们说的名字栈。接下来的操作和投影变换就一样了,先把这个选择框移归一化为边长为-1到1的正方体,然后移动到原点,最后放大为我们窗口的大小。(这时OpenGL已经把在选择框外的东西剪裁掉了,如果这个时候我们显示投影矩阵中的内容的话,就会只看到我们选择到的东西,并且放大和窗口一样大。)然后OpenGL会把选中的物体信息记录在一个叫做SelectBuffer的缓冲中,这个缓冲就是个一维数组,里面保存了名字栈中名字的个数,选择到的物体的最小最大深度值,也就是z的值,这个值是个0到1之间的值,也就是里我们最近的为0,最远的为1。selectBuffer是个整型的数组,所以这里保存的深度值是乘以0xFFFFFFFF后的值。当然最重要的,其中还保存了我们选择到的物体的名字,这样只要在程序中判断选择到物体的名字,我们就可以判断是不是选择到了要选择的物体了。整个拾取的过程可如下。

 

picking

 

    上图中左边的正方体是我们归一化的视体,拾取的时候就是在这个空间中拾取的。红色的小框是我们的选择框。里面的红色就是我们选择到的物体的一部分。现在要做的就是把这个小框转变为视体,这样OpenGL才能为我们把不要的东西扔掉。

     所以,首先还是把这个小框移动到观察坐标系的原点,然后再放大为我们归一化视体的大小。这样整个视体中就只有我们选中的东西了。上图中间显示了这个过程。

    视体外的东西已经被OpenGL剪裁掉,选中的记录会保存到selectbuffer中。因为这些操作是在选择模式下完成的,所以看不到我们选择的过程,但是如果我们把选择的过程显示出来的话,就会看到上图右边的样子。整个窗口就铺满了我们选择的部分。在OpenGL中,提供了这个设置拾取框的函数。

gluPickMatrix (x, y, width, height, viewport[4]);

x,y:是鼠标点击到窗口上的坐标,

width和height:就是这个拾取框的长宽

viewport:是为了得到我们窗口的大小。

一但调用了该函数,OpenGL就会创建一个拾取矩阵。分解这个矩阵的话可以看到,这个矩阵就是上面的移动拾取框到原点,然后再放大为视体大小这两个步骤。所以即使我们不使用这个函数,也可以自己计算出这个拾取矩阵。



原创粉丝点击