选择和反馈

无论是在选择还是在反馈模式下,绘图信息总是返回到应用程序而不是像渲染模式那样发送到帧缓冲区。因此,在选择或反馈模式下,屏幕冻结,不会进行绘图。在这两种模式下,颜色、深度、模板和累积缓冲区的内容并不会受到影响。

选择

一般情况下,当我们打算使用OpenGL的选择机制时,首先把整个场景绘制到帧缓冲区,然后进入选择模式,并对场景进行重绘。但是,在进入选择模式之后,帧缓冲区的内容将不会修改,除非退出选择模式。当退出选择模式时,OpenGL返回与视景体相交的图元列表。与视景体相交的每个图元都会产生一个选择点击。这个图元列表实际上是以点击纪录的形式返回的,它包含了一个整型数组names以及相关的数据,对应于名字栈中的当前内容。在选择模式下,当调用用于绘制图元的函数时,可以把这些名称加载到名字栈中,从而完成对名字栈的创建。因此,当名称列表返回时,可以用它来确定屏幕上的哪些图元可能被用户选择。

除了这种选择机制之外,OpenGL还提供了一个工具函数,把绘图限制在视口中的一个小型区域内,它在某些情况下可以简化选择过程。一般情况下,可以使用这个函数确定哪个物体靠近光标,由此判断用户挑选的是哪个土体。

  • 基本步骤

    • 用glSelectBuffer()函数指定用于返回点击纪录的数组;
    • 用glRenderMode()指定GL_SELECT,进入选择模式;
    • 使用glInitName()和glPushName()对名字栈进行初始化;
    • 定义用于选择的视景体。通常,这个视景体与最初用于绘制场景的视景体不同,因此很可能需要用glglPushMatrix()和glPopMatrix()函数保存和恢复当前的变化状态;
    • 交替调用绘制图元的函数和操纵名字栈的函数,为每个相关的图元分配一个适当的名称;
    • 退出选择模式,并处理返回的选择数据(点击纪录)。
  • 创建名字栈

    为了创建名字堆栈,首先需要用glInitNames()函数对它进行初始化,这个函数只是简单地清除这个堆栈。然后,在调用绘图函数时,向这个堆栈添加整数类型的名称。用于操纵名字堆栈的函数包括一个把名称压入到名字堆栈中的函数(glPushName()),也包括一个从名字堆栈弹出名称的函数(glPopName()),还包括一个用不同的名字替换名字堆栈顶部元素的函数(glLoadName())。

  • 点击纪录

    在选择模式下,与视景体相交的图元会导致一次选择点击。在执行用于操纵名字堆栈的函数或调用glglRenderMode()函数之后,如果出现了一次点击,OpenGL就会在数组中写入一个点击纪录。按照这种处理方式,共享相同名称的对象(例如被多个图元使用的对象)不会产生多条点击纪录。另外,在调用glglRenderMode()之前,点击纪录并不能保证被写入到选择数组中。

    除了几何图元之外,glRasterPos()或glWindowPos()所产生的有效光栅位置坐标也会导致选择点击。

    每个点击纪录都由4个项目组成,按顺序分别如下所示:

    • 当点击发生时名字堆栈中的名称数量;
    • 自上一个点击纪录之后,与视景体相交的图元的所有定点的最小和最大窗口坐标z值。这两个值的范围在0-1之内,它们都与2³²-1相乘,然后四舍五入到最接近的无符号整数;
    • 在点击发生时名字堆栈的内容,从最底部的元素开始。

    在进入选择模式时,OpenGL会对一个指针进行初始化,使它指向选择数组的起始位置。每次当一条点击纪录写入到这个数组时,这个指针也会相应地进行更新。如果写入一条点击纪录会导致数组中值的数量超过glSelectBuffer()函数所指定的size参数,OpenGL将在这个数组中写入尽可能多的纪录,并设置一个溢出标志。当使用glRenderMode()函数退出选择模式时,这个函数会返回它所写入的点击记录的数量(在溢出情况下,还可能包含一条不完整的纪录),并清除名字堆栈,重置溢出标志和堆栈指针。如果设置了溢出标志,这个函数的返回值为-1。

  • 挑选

    可以通过选择模式来确定一个物体是否被挑选。为了实现这个目的,可以使用一个特殊的挑选矩阵,并协同使用投影矩阵,把绘图限制在视口的一个小区域内,一般是在靠近光标的位置。然后,允许某些形式的输入(例如点击鼠标按钮),对选择模式进行初始化。在确立了选择模式并使用了特殊的挑选矩阵之后,在靠近光标位置处绘制物体就会导致选择点击。因此,挑选一般是用于判断哪些物体是在靠近光标的位置绘制的。

    挑选的设置基本上与常规的选择相同,主要由下面几点区别:

    • 挑选通常是由输入设备触发的;
    • 可以使用工具函数gluPickMatrix(),把当前的投影矩阵与一个特殊的挑选矩阵相乘。这个函数应该在乘以标准的投影矩阵(例如调用gluPerspective()或glOrtho())之前调用。

    gluPickMatrix()创建的矩阵的净效果是把裁剪区域变换为单位立方体-1 ≦ (x, y, z) ≦ 1,挑选矩阵有效地执行一次正交变换,把裁剪区域映射到单位立方体上。由于变换是任意的,因此可以让挑选作用于不同类型的区域,例如,可以把它作用于经过旋转的窗口矩形部分。

    可以使用多个名称来选择场景中一个层次式物体的不同部分。在挑选时同样可以使用深度值来确定需要挑选的物体。

  • 编写使用选择的程序的一些建议

    绝大多数允许用户对几何物体进行交互性编辑的程序都提供了一种机制,允许用户挑选可以进行编辑的项或项组。对于二维绘图程序(例如,文本编辑器、页面设置程序以及电路设计程序),执行自己的挑选计算可能比使用OpenGL的挑选机制方便得多。寻找二维物体的边框,并把它们组织成层次式的数据结构以提高搜索速度常常比较方便。

    另举一个例子,由于只有集合图形会产生点击,因此我们可能想创建自己的方法来挑选文本。设置当前光栅位置是一种几何操作,但它只是在当前光栅位置创建一个可挑选的点,通常是在文本的左下角。如果编辑器需要在字符串内部操纵单个的字符,就必须使用其他的挑选机制。在挑选模式下,可以在每个字符周围绘制更少的矩形,但是把文本作为一种特殊情况来处理显然会容易很多。

    如果决定使用OpenGL的挑选机制,应该对程序以及它所使用的数据结构进行组织,使OpenGL无论在选择模式下还是在正常的渲染模式下都更容易绘制正确的物体。这样,当用户进行了挑选时,可以在挑选操作中使用相同的数据结构,把物体显示在屏幕上。另外,还需要考虑是否允许用户挑选多个物体。其中一个方法是为每个项存储1个位,表示它是否已经被选择(但是,这种方法要求对所有的物体进行遍历,以便找出被选择的项)。

反馈

反馈与选择具有一个相似之处:在这两种模式下,不会产生任何像素,并且屏幕被冻结。在这两种模式下,不会发生实际的绘图。反之,与渲染图元有关的信息被发送到应用程序。选择和反馈模式的关键区别在于它们返回的信息。在选择模式下,一些已分配的名称返回到一个整型数组中。在反馈模式下,与经过变换的图元有关的一些信息返回到一个浮点型数组中。发送到反馈数组的值包括一些标记(指定了被处理和变换的图元类型,如点、直线、多边形、图像或位图),然后是图元的顶点、颜色或其他数据。这些返回值都是经过了完整的光照和视图转换。为了进入反馈模式,可以用GL_FEEDBACK为参数调用glRenderMode()函数。

  • 调用glFeedbackBuffer()函数,指定用于保存反馈信息的数组。这个函数的参数描述了数据的类型以及写入到数组的数据量;
  • 以GL_FEEDBACK为参数调用glRenderMode()函数,进入反馈模式。在此之后,在退出反馈模式之前,图元不会通过光栅化产生像素,帧缓冲区的内容也不会发生变化;
  • 绘制图元。在发布绘图命令时,可以多次调用glPassThrough()函数在返回的反馈数据中插入标记,以方便对反馈数据进行解析;
  • 如果想返回到常规的绘图模式,可以用GL_RENDER为参数调用glRenderMode()函数,退出反馈模式。glRenderMode()函数的返回值就是反馈数组中所存储的值的数量。
  • 对反馈数组中的数据进行解析。

  • 反馈数组

    在反馈模式下,每个将要光栅化的图元都会生成一块数据值,并复制到反馈数组中。数据值的数量是由glFeedbackBuffer()函数的type参数决定的。

    每块反馈数据都是从一个表示图元类型的代码开始,紧接着是描述图元顶点以及相关信息的值。此外,它还写入了像素矩形的信息。另外,可以反馈数组返回显式创建的过渡标记。

  • 在反馈模式下使用标记

    反馈是在变换、光照、多边形剔除以及使用glPolygonMode()设置多边形模式之后发生的。当把一个超过3条边组成的多边形分解为几个三角形(如果我们所使用的OpenGL实现通过进行这种分解法来执行多边形渲染)后,也可能会发生反馈。因此,我们可能难以理解接收到的反馈数据。为了便于对反馈数据进行解析,可以根据需要在绘图命令序列中添加对glPassThrough()函数的调用,插入一些过渡标记。例如,可以用过渡标记分隔不同图元返回的反馈值。

    无论是在反馈模式还是选择模式下,物体的信息总是在任何片断测试之前返回。因此在反馈模式或选择模式下,那些无法通过裁剪测试、alpha测试或模板测试的物体仍然会对它们的数据进行处理和返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值