选择与反馈 (OpenGL)

章节目标

读完此章之后,你将能够做到:
建立允许用户选择(select)屏幕区域或拾取(pick)绘制在屏幕上的物体的应用程序
利用OpenGL的反馈(feedback)模式获取绚染计算结果

有 些图形应用程序只绘制两维和三维物体构成的静态图形,另一些允许用户识别屏幕上的物体并移动、修改、删除或用其它方法操纵这些物体。OpenGL正是设计 用于支持这些交互式应用程序的。因为绘制在屏幕上的物体通常经过多次旋转、移动和透视变换,所以确定用户选中了三维场景中的哪个物体会很困难。为了帮助 你,OpenGL提供了一个选取机制可惟自动告诉你哪个物体被绘制在窗口的提定区域里。你可以用这个机制与一个工具例程(a special utility routine)一道决定哪个物体在用户说明或用光标选取的区域里。

选择(selection)实际上是OpenGL的 一个操作模式;反馈(feedback)是这类模式中的别一个。在反馈模式中,你用你的图形硬件和OpenGL完成通常的绚染计算。但与用这个计算结果去 在屏幕上绘制图形相反,OpenGL返回(或反馈(feeds back))这些绘制信息给你。如果你想在绘图仪而不是屏幕上绘制图形,举个例子,你就得在反馈模式绘制它们,收集绘制指令,然后将这些指令转换为绘图仪 可以理解的命令。

在选择和反馈模式中,绘制信息返回给应用程序而不是象在绚染模式中那样送往帧缓冲。因此,当OpenGL处于选择或反馈模式时,屏幕将被冻结-没有图形出现。这一章将会在各自的节中解释这些模式:

“选择(Selection)” 讨论怎样使用选择模式和相关的例程以使你程序的用户能拾取画在屏幕上的物体。

“反馈(Feedback)” 描述了怎样获取有关什么将被画在屏幕上的信息和这些信息是以什么格式组织的。

---------------------------------------------------
Section

通 常,当你打算使用OpenGL的选择机制时,你首先把你的场景画进帧缓冲,然后进入选择模式并重新绘制这个场景。然而,一旦你进入了选择模式,帧缓冲的内 容将保存不变,直到你退出选择模式。当你退出时,OpenGL返回一个图元(premitives)清单,图元可能被视见体(viewing volume)分割(记住,视见体是由当前模式视见和投影矩阵及你定义的所有裁剪面定义,裁剪面详见"Additional Clipping Planes.")。每个被视见体图元引出一资选择命中(hit)。确切的说,图元清单是作为一个取整数值的名字(integer-valued names)数组和相关的数据-命中记录(hit record)-对应名字栈(name stack)的当前内容。当你在选择模式下发布图元绘制命令时向名字栈中加入名字就可建立起名字栈。这样,当名字清单被返回后,你就可以用它来确定屏幕上 的哪个图元可能被用户选中了。

除了这个选择机制之外,OpenGL提供了一个工具例程,以便在某些情况下通过限定在视口 (viewport)一个小区域内绘制来简化选择。通常你可以用这个例程决定哪个物体被画在光标附近了,这样你就能识别用户拾取了哪个物体。你也可以通过 指定附加的裁剪面来界定一个选择区域;详见"Additional Clipping Planes"。因为拾取是选择的一个特殊情况,所以本章选讲选择,然后讲拾取。

基本步骤
建立名字矩阵
命中记录
一个选择的例子
拾取
关于编写使用选择的程序的提示

------------------------------------------------------------------------
基本步骤

为使用选择机制,你得作以下几步:
1、用glSelectBuffer()指定用于返回命中记录的数组。
2、以GL_SELECT为参数调用glRenderMode()进入选择模式。
3、用glInitName()和glPushName()初始化名字栈。
4、定义用于选择的视见体。通常它与你原来用于绘制场景的视见体不同。因此你或许会想用glPushMatrix()和glPopMatrix()来保存和恢复当前的变换矩阵。
5、交替发布图元绘制命令和名字栈控制命令,这样每个感兴趣的图元都会被指定适当的名字。
6、退出选择模式并处理返回的选择数据(命中记录)。

后面的段落将描述glSelectBuffer()和glRenderMode()。下一节则讲解名字栈的控制。

void glSelectBuffer(GLsizei size, GLuint *buffer);
指定用于返回选择数据的数组。参数buffer是指向无符号整数(unsigned integer)数组的指针,数据就存在这个数组中,size参数说明数组中最多能够保存的值的个数。要在进入选择模式之前调用glSelectBuffer()!

GLint glRenderMode(GLenum mode);
控 制应用程序是否进入绚染(rendering)、选择或反馈模式。mode参数可以是GL_RENDER(默认)、GL_SELECT或 GL_FEEDBACK之一。应用程序将保持处于给定模式,直到再次以不同的参数调用glRenderMode()。在进入选择模式之前必须调用 glSelectBuffer()指定选择数组。类似的,进入反馈模式之前要调用glFeedbackBuffer()指定反馈数组。如果当前模式是 GL_SELECT或GL_FEEDBACK之一,那么glRenderMode()的返回值有意义。返回值是当前退出当前模式时,选择命中数或放在反馈 数组中的值的个数。(译者注:调用此函数就会退出当前模式);负值意味着选择或反馈数组溢出(overflowed)。你可以用 GL_RENDER_MODE调用glGetIntegerv()获取当前模式。

-------------------------------------------------------------------------------
建立名字矩阵

正 如前面提到的,名字栈是返回给你的选择信息的基础。要建立名字栈,首先用glInitNames()初始化它,这将简单地清空栈。然后当你发布相应的绘制 命令时向其中加入整数名字。正如你可能想象,栈控制命令允许你压入名字(glPushName()),弹出名字(glPopName()),替换栈顶的名 字(glLoadName())。
/********************************************************************/
Example 12-1: Creating a Name Stack
glInitNames();
glPushName(-1);

glPushMatrix(); /* save the current transformation state */

/*to do: create your desired viewing volume here */

glLoadName(1);
drawSomeObject();
glLoadName(2);
drawAnotherObject();
glLoadName(3);
drawYetAnotherObject();
drawJustOneMoreObject();

glPopMatrix (); /* restore the previous transformation state*/
/********************************************************************/


在这个例子中,前两个被绘制的物体有自己的名字,第三和第四个共用一个名字。这样,如果第三或第四个物体中的一个或全部引起一个选择命中,只有一个命中记录返回给你。如果处理命中记录时不想区分各个物体的话,可以让多个物体共享一个名字。

void glInitNames(void);
清空名字栈。

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

void glPopName(void);
弹出名字栈栈顶的那一个名字。从空栈中弹出名字引发GL_STACK_UNDERFLOW错误。

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

如果不是在选择模式下,对glPushName()、glPopName()、glLoadName()的调用将被忽略。这使得在选择模式和正常的绚染模式下用相同的绘制代码大为简化。

-------------------------------------------------------------------------------

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值