⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter12.html

📁 OpenGl红宝书
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-2">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.07 [en] (Win98; I) [Netscape]">
   <META NAME="Author" CONTENT="Goran UnreaL Krajnovic">
   <TITLE>Chapter 12 - OpenGL Programming Guide (Addison-Wesley Publishing Company)</TITLE>
</HEAD>
<BODY BGCOLOR="#EFEFEF" LINK="#0000FF" VLINK="#551A8B" ALINK="#FF0000">

<DIV ALIGN=right><IMG SRC="figures/SGI_ID.gif" ALT="Silicon Graphics" NOSAVE HEIGHT=43 WIDTH=151 ALIGN=TEXTTOP></DIV>

<HR>
<H1>
Chapter 12<BR>
Selection and Feedback</H1>
<B>Chapter Objectives</B>
<P>After reading this chapter, you'll be able to do the following:
<UL>Create applications that allow the user to select a region of the screen
or pick an object drawn on the screen
<BR>&nbsp;
<P>Use OpenGL's feedback mode to obtain the results of rendering calculations</UL>
Some graphics applications simply draw static images of two- and three-dimensional
objects. Other applications allow the user to identify objects on the screen
and then to move, modify, delete, or otherwise manipulate those objects.
OpenGL is designed to support exactly such interactive applications. Since
objects drawn on the screen typically undergo multiple rotations, translations,
and perspective transformations, it can be difficult for you to determine
which object a user is selecting in a three-dimensional scene. To help
you, OpenGL provides a selection mechanism that automatically tells you
which objects are drawn inside a specified region of the window. You can
use this mechanism together with a special utility routine to determine
which object within the region the user is specifying, or <I>picking</I>,
with the cursor.
<P>Selection is actually a mode of operation for OpenGL; feedback is another
such mode. In feedback mode, you use your graphics hardware and OpenGL
to perform the usual rendering calculations. Instead of using the calculated
results to draw an image on the screen, however, OpenGL returns (or feeds
back) the drawing information to you. If you want to draw three-dimensional
objects on a plotter rather than the screen, for example, you would draw
the items in feedback mode, collect the drawing instructions, and then
convert them to commands the plotter can understand.
<P>In both selection and feedback modes, drawing information is returned
to the application rather than being sent to the framebuffer, as it is
in rendering mode. Thus, the screen remains frozen - no drawing occurs
- while OpenGL is in selection or feedback mode. This chapter explains
each of these modes in its own section:
<UL>"Selection" discusses how to use selection mode and related routines
to allow a user of your application to pick an object drawn on the screen.
<BR>&nbsp;
<P>"Feedback" describes how to obtain information about what would be drawn
on the screen and how that information is formatted.</UL>

<HR>
<H2>
<A NAME="X"></A>Selection</H2>
Typically, when you're planning to use OpenGL's selection mechanism, you
first draw your scene into the framebuffer and then you enter selection
mode and redraw the scene. Once you're in selection mode, however, the
contents of the framebuffer don't change until you exit selection mode.
When you exit, OpenGL returns a list of the primitives that would have
intersected the viewing volume (remember that the viewing volume is defined
by the current modelview and projection matrices and any clipping planes
you've specified, as explained in "Additional Clipping Planes." ) Each
primitive that intersects the viewing volume causes a selection <I>hit</I>.
The list of primitives is actually returned as an array of integer-valued
<I>names</I> and related data - the <I>hit records</I> - that correspond
to the current contents of the <I>name stack</I>. You construct the name
stack by loading names onto it as you issue primitive drawing commands
while in selection mode. Thus, when the list of names is returned, you
can use it to determine which primitives might have been selected on the
screen by the user.
<P>In addition to this selection mechanism, OpenGL provides a utility routine
designed to simplify selection in some cases by restricting drawing to
a small region of the viewport. Typically, you use this routine to determine
which objects are drawn near the cursor, so that you can identify which
object the user is picking. You can also delimit a selection region by
specifying additional clipping planes; see "Additional Clipping Planes"
for more information about how to do this. Since picking is a special case
of selection, selection is described first in this chapter, and then picking.
<P>
<HR>
<H3>
The Basic Steps</H3>
To use the selection mechanism, you need to perform the following steps.
<OL>Specify the array to be used for the returned hit records with <B>glSelectBuffer()</B>.
<BR>&nbsp;
<P>Enter selection mode by specifying GL_SELECT with <B>glRenderMode()</B>.
<BR>&nbsp;
<P>Initialize the name stack using <B>glInitNames()</B> and <B>glPushName()</B>.
<BR>&nbsp;
<P>Define the viewing volume you want to use for selection. Usually, this
is different from the viewing volume you used to draw the scene originally,
so you probably want to save and then restore the current transformation
state with <B>glPushMatrix()</B> and <B>glPopMatrix()</B>.
<BR>&nbsp;
<P>Alternately issue primitive drawing commands and commands to manipulate
the name stack so that each primitive of interest has an appropriate name
assigned.
<BR>&nbsp;
<P>Exit selection mode and process the returned selection data (the hit
records).</OL>
The following paragraphs describe <B>glSelectBuffer()</B> and <B>glRenderMode()</B>.
In the next section, the commands to manipulate the name stack are described.
void <B>glSelectBuffer</B>(GLsizei <I>size</I>, GLuint *<I>buffer</I>);
<P>Specifies the array to be used for the returned selection data. The
<B>buffer</B> argument is a pointer to an array of unsigned integers into
which the data is put, and <B>size</B> indicates the maximum number of
values that can be stored in the array. You need to call <B>glSelectBuffer()</B>
before entering selection mode.
<P>GLint <B>glRenderMode</B>(GLenum <B>mode</B>);
<P>Controls whether the application is in rendering, selection, or feedback
mode. The <B>mode</B> argument can be one of GL_RENDER (the default), GL_SELECT,
or GL_FEEDBACK. The application remains in a given mode until <B>glRenderMode()</B>
is called again with a different argument. Before entering selection mode,
<B>glSelectBuffer()</B> must be called to specify the selection array.
Similarly, before entering feedback mode, <B>glFeedbackBuffer()</B> must
be called to specify the feedback array. The return value for <B>glRenderMode()</B>
has meaning if the current render mode (that is, not the <B>mode</B> parameter)
is either GL_SELECT or GL_FEEDBACK: The return value is the number of selection
hits or the number of values placed in the feedback array when either mode
is exited; a negative value means that the selection or feedback array
has overflowed. You can use GL_RENDER_MODE with <B>glGetIntegerv()</B>
to obtain the current mode.
<P>
<HR>
<H3>
Creating the Name Stack</H3>
As mentioned in the previous section, the name stack forms the basis for
the selection information that's returned to you. To create the name stack,
first you initialize it with <B>glInitNames()</B>, which simply clears
the stack, and then you add integer names to it as you issue corresponding
drawing commands. As you might expect, the commands to manipulate the stack
allow you to push a name onto it (<B>glPushName()</B>), pop a name off
of it (<B>glPopName()</B>), and replace the name on the top of the stack
with a different one (<B>glLoadName()</B>). Example 12-1 shows what your
name-stack manipulation code might look like with these commands.
<P><B>Example 12-1 : </B>Creating a Name Stack
<PRE>glInitNames();
glPushName(-1);

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

&nbsp;&nbsp;&nbsp; /* create your desired viewing volume here */

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

glPopMatrix ();&nbsp;&nbsp; /* restore the previous transformation state*/</PRE>
In this example, the first two objects to be drawn have their own names,
and the third and fourth objects share a single name. With this setup,
if either or both of the third and fourth objects causes a selection hit,
only one hit record is returned to you. You can have multiple objects share
the same name if you don't need to differentiate between them when processing
the hit records. void <B>glInitNames</B>(void);
<P>Clears the name stack so that it's empty.
<P>void <B>glPushName</B>(GLuint <B>name</B>);
<P>Pushes <B>name</B> onto the name stack. Pushing a name beyond the capacity
of the stack generates the error GL_STACK_OVERFLOW. The name stack's depth
can vary among different OpenGL implementations, but it must be able to
contain at least sixty-four names. You can use the parameter GL_NAME_STACK_DEPTH
with <B>glGetIntegerv()</B> to obtain the depth of the name stack.
<P>void <B>glPopName</B>(void);
<P>Pops one name off the top of the name stack. Popping an empty stack
generates the error GL_STACK_UNDERFLOW.
<P>void <B>glLoadName</B>(GLuint <B>name</B>);
<P>Replaces the value on the top of the name stack with <B>name</B>. If
the stack is empty, which it is right after <B>glInitNames()</B> is called,
<B>glLoadName()</B> generates the error GL_INVALID_OPERATION. To avoid
this, if the stack is initially empty, call <B>glPushName()</B> at least
once to put something on the name stack before calling <B>glLoadName()</B>.
<P>Calls to <B>glPushName()</B>, <B>glPopName()</B>, and <B>glLoadName()</B>
are ignored if you're not in selection mode. You might find that it simplifies
your code to use these calls throughout your drawing code, and then use
the same drawing code for both selection and normal rendering modes.
<P>
<HR>
<H3>
The Hit Record</H3>
In selection mode, a primitive that intersects the viewing volume causes
a selection hit. Whenever a name-stack manipulation command is executed
or <B>glRenderMode()</B> is called, OpenGL writes a hit record into the
selection array if there's been a hit since the last time the stack was
manipulated or <B>glRenderMode()</B> was called. With this process, objects
that share the same name - for example, an object that's composed of more
than one primitive - don't generate multiple hit records. Also, hit records
aren't guaranteed to be written into the array until <B>glRenderMode()</B>
is called.
<P>In addition to primitives, valid coordinates produced by <B>glRasterPos()
</B>can cause a selection hit. In the case of polygons, no hit occurs if
the polygon would have been culled.
<P>Each hit record consists of four items, in order:
<UL>The number of names on the name stack when the hit occurred.
<BR>&nbsp;
<P>Both the minimum and maximum window-coordinate <I>z</I> values of all
vertices of the primitives that intersected the viewing volume since the
last recorded hit. These two values, which lie in the range [0,1], are
each multiplied by 232-1 and rounded to the nearest unsigned integer.
<BR>&nbsp;
<P>The contents of the name stack at the time of the hit, with the bottommost
element first.</UL>
When you enter selection mode, OpenGL initializes a pointer to the beginning
of the selection array. Each time a hit record is written into the array,
the pointer is updated accordingly. If writing a hit record would cause

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -