• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            選擇與反饋

            章節(jié)目標(biāo)

            讀完此章之后,你將能夠做到:
            建立允許用戶選擇(select)屏幕區(qū)域或拾取(pick)繪制在屏幕上的物體的應(yīng)用程序
            利用OpenGL的反饋(feedback)模式獲取絢染計(jì)算結(jié)果

            有些圖形應(yīng)用程序只繪制兩維和三維物體構(gòu)成的靜態(tài)圖形,另一些允許用戶識(shí)別屏幕上的物體并移動(dòng)、修改、刪除或用其它方法操縱這些物體。OpenGL正是設(shè)計(jì)用于支持這些交互式應(yīng)用程序的。因?yàn)槔L制在屏幕上的物體通常經(jīng)過多次旋轉(zhuǎn)、移動(dòng)和透視變換,所以確定用戶選中了三維場景中的哪個(gè)物體會(huì)很困難。為了幫助你,OpenGL提供了一個(gè)選取機(jī)制可惟自動(dòng)告訴你哪個(gè)物體被繪制在窗口的提定區(qū)域里。你可以用這個(gè)機(jī)制與一個(gè)工具例程(a special utility routine)一道決定哪個(gè)物體在用戶說明或用光標(biāo)選取的區(qū)域里。

            選擇(selection)實(shí)際上是OpenGL的一個(gè)操作模式;反饋(feedback)是這類模式中的別一個(gè)。在反饋模式中,你用你的圖形硬件和OpenGL完成通常的絢染計(jì)算。但與用這個(gè)計(jì)算結(jié)果去在屏幕上繪制圖形相反,OpenGL返回(或反饋(feeds back))這些繪制信息給你。如果你想在繪圖儀而不是屏幕上繪制圖形,舉個(gè)例子,你就得在反饋模式繪制它們,收集繪制指令,然后將這些指令轉(zhuǎn)換為繪圖儀可以理解的命令。

            在選擇和反饋模式中,繪制信息返回給應(yīng)用程序而不是象在絢染模式中那樣送往幀緩沖。因此,當(dāng)OpenGL處于選擇或反饋模式時(shí),屏幕將被凍結(jié)-沒有圖形出現(xiàn)。這一章將會(huì)在各自的節(jié)中解釋這些模式:

            “選擇(Selection)” 討論怎樣使用選擇模式和相關(guān)的例程以使你程序的用戶能拾取畫在屏幕上的物體。

            “反饋(Feedback)” 描述了怎樣獲取有關(guān)什么將被畫在屏幕上的信息和這些信息是以什么格式組織的。

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

            通常,當(dāng)你打算使用OpenGL的選擇機(jī)制時(shí),你首先把你的場景畫進(jìn)幀緩沖,然后進(jìn)入選擇模式并重新繪制這個(gè)場景。然而,一旦你進(jìn)入了選擇模式,幀緩沖的內(nèi)容將保存不變,直到你退出選擇模式。當(dāng)你退出時(shí),OpenGL返回一個(gè)圖元(premitives)清單,圖元可能被視見體(viewing volume)分割(記住,視見體是由當(dāng)前模式視見和投影矩陣及你定義的所有裁剪面定義,裁剪面詳見"Additional Clipping Planes.")。每個(gè)被視見體圖元引出一資選擇命中(hit)。確切的說,圖元清單是作為一個(gè)取整數(shù)值的名字(integer-valued names)數(shù)組和相關(guān)的數(shù)據(jù)-命中記錄(hit record)-對(duì)應(yīng)名字棧(name stack)的當(dāng)前內(nèi)容。當(dāng)你在選擇模式下發(fā)布圖元繪制命令時(shí)向名字棧中加入名字就可建立起名字棧。這樣,當(dāng)名字清單被返回后,你就可以用它來確定屏幕上的哪個(gè)圖元可能被用戶選中了。

            除了這個(gè)選擇機(jī)制之外,OpenGL提供了一個(gè)工具例程,以便在某些情況下通過限定在視口(viewport)一個(gè)小區(qū)域內(nèi)繪制來簡化選擇。通常你可以用這個(gè)例程決定哪個(gè)物體被畫在光標(biāo)附近了,這樣你就能識(shí)別用戶拾取了哪個(gè)物體。你也可以通過指定附加的裁剪面來界定一個(gè)選擇區(qū)域;詳見"Additional Clipping Planes"。因?yàn)槭叭∈沁x擇的一個(gè)特殊情況,所以本章選講選擇,然后講拾取。

            基本步驟
            建立名字矩陣
            命中記錄
            一個(gè)選擇的例子
            拾取
            關(guān)于編寫使用選擇的程序的提示

            ------------------------------------------------------------------------
            基本步驟

            為使用選擇機(jī)制,你得作以下幾步:
            1、用glSelectBuffer()指定用于返回命中記錄的數(shù)組。
            2、以GL_SELECT為參數(shù)調(diào)用glRenderMode()進(jìn)入選擇模式。
            3、用glInitName()和glPushName()初始化名字棧。
            4、定義用于選擇的視見體。通常它與你原來用于繪制場景的視見體不同。因此你或許會(huì)想用glPushMatrix()和glPopMatrix()來保存和恢復(fù)當(dāng)前的變換矩陣。
            5、交替發(fā)布圖元繪制命令和名字棧控制命令,這樣每個(gè)感興趣的圖元都會(huì)被指定適當(dāng)?shù)拿帧?br>6、退出選擇模式并處理返回的選擇數(shù)據(jù)(命中記錄)。

            后面的段落將描述glSelectBuffer()和glRenderMode()。下一節(jié)則講解名字棧的控制。

            void glSelectBuffer(GLsizei size, GLuint *buffer);
            指定用于返回選擇數(shù)據(jù)的數(shù)組。參數(shù)buffer是指向無符號(hào)整數(shù)(unsigned integer)數(shù)組的指針,數(shù)據(jù)就存在這個(gè)數(shù)組中,size參數(shù)說明數(shù)組中最多能夠保存的值的個(gè)數(shù)。要在進(jìn)入選擇模式之前調(diào)用glSelectBuffer()!

            GLint glRenderMode(GLenum mode);
            控制應(yīng)用程序是否進(jìn)入絢染(rendering)、選擇或反饋模式。mode參數(shù)可以是GL_RENDER(默認(rèn))、GL_SELECT或GL_FEEDBACK之一。應(yīng)用程序?qū)⒈3痔幱诮o定模式,直到再次以不同的參數(shù)調(diào)用glRenderMode()。在進(jìn)入選擇模式之前必須調(diào)用glSelectBuffer()指定選擇數(shù)組。類似的,進(jìn)入反饋模式之前要調(diào)用glFeedbackBuffer()指定反饋數(shù)組。如果當(dāng)前模式是GL_SELECT或GL_FEEDBACK之一,那么glRenderMode()的返回值有意義。返回值是當(dāng)前退出當(dāng)前模式時(shí),選擇命中數(shù)或放在反饋數(shù)組中的值的個(gè)數(shù)。(譯者注:調(diào)用此函數(shù)就會(huì)退出當(dāng)前模式);負(fù)值意味著選擇或反饋數(shù)組溢出(overflowed)。你可以用GL_RENDER_MODE調(diào)用glGetIntegerv()獲取當(dāng)前模式。

            -------------------------------------------------------------------------------
            建立名字矩陣

            正如前面提到的,名字棧是返回給你的選擇信息的基礎(chǔ)。要建立名字棧,首先用glInitNames()初始化它,這將簡單地清空棧。然后當(dāng)你發(fā)布相應(yīng)的繪制命令時(shí)向其中加入整數(shù)名字。正如你可能想象,棧控制命令允許你壓入名字(glPushName()),彈出名字(glPopName()),替換棧頂?shù)拿郑╣lLoadName())。
            /********************************************************************/
            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*/
            /********************************************************************/


            在這個(gè)例子中,前兩個(gè)被繪制的物體有自己的名字,第三和第四個(gè)共用一個(gè)名字。這樣,如果第三或第四個(gè)物體中的一個(gè)或全部引起一個(gè)選擇命中,只有一個(gè)命中記錄返回給你。如果處理命中記錄時(shí)不想?yún)^(qū)分各個(gè)物體的話,可以讓多個(gè)物體共享一個(gè)名字。

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

            void glPushName(GLuint name);
            將name壓入名字棧。壓入名字超過棧容量時(shí)將生成一個(gè)GL_STACK_OVERFLOW錯(cuò)誤。名字棧深度因OpenGL實(shí)現(xiàn)(implementations)不同而不同,但最少要能容納64個(gè)名字。你可以用參數(shù)GL_NAME_STACK_DEPTH調(diào)用glGetIntegerv()以獲取名字棧深度。

            void glPopName(void);
            彈出名字棧棧頂?shù)哪且粋€(gè)名字。從空棧中彈出名字引發(fā)GL_STACK_UNDERFLOW錯(cuò)誤。

            void glLoadName(GLuint name);
            用name取代名字棧棧頂?shù)哪莻€(gè)名字。如果棧是空的,剛調(diào)用過glInitName()后就是這樣,glLoadName()生成一個(gè)GL_INVALID_OPRATION錯(cuò)。為避免這種情況,如果棧初始時(shí)是空的,那么在調(diào)用glLoadName()之前至少調(diào)用一次glPushName()以在名字棧中放上點(diǎn)東西。

            如果不是在選擇模式下,對(duì)glPushName()、glPopName()、glLoadName()的調(diào)用將被忽略。這使得在選擇模式和正常的絢染模式下用相同的繪制代碼大為簡化。

            -------------------------------------------------------------------------------
            命中記錄

            在選擇模式下,被視見體裁剪的每個(gè)圖元引起一個(gè)選擇命中。當(dāng)前一個(gè)名字棧控制命令被執(zhí)行或glRenderMode()被調(diào)用后,OpenGL將一個(gè)命中記錄寫進(jìn)選擇數(shù)組,如果從上一次名字棧操縱或glRenderMode()調(diào)用以來有了一個(gè)命中記錄的話。這個(gè)過程中,共用同樣名字的物體-例如:由多個(gè)圖元組成的物體-不生成多個(gè)命中記錄。當(dāng)然,命中記錄不保證會(huì)被寫進(jìn)數(shù)組中直到glRenderMode()被調(diào)用。

            除圖元之外,glRasterPos()產(chǎn)生的有效坐標(biāo)也可以引起選擇命中。在多邊形的情況下,如果它已經(jīng)被消隱掉的話不會(huì)有命中記錄出現(xiàn)。

            每個(gè)命中記錄由四項(xiàng)組成,依次是:
            當(dāng)命中出現(xiàn)時(shí)名字棧中的名字?jǐn)?shù)
            至上次記錄的命中以來,被視見體裁剪后的圖元的所有頂點(diǎn)的窗口Z坐標(biāo)的 最大和最小值
            本次命中時(shí)名字棧的內(nèi)容,最底元素最前。

            當(dāng)前你進(jìn)入選擇模式時(shí),OpenGL初始化一個(gè)指針指向選擇數(shù)組的起點(diǎn)。每寫入一個(gè)命中記錄,指針相應(yīng)更新。如果寫入一個(gè)命中記錄會(huì)使數(shù)組中值的個(gè)數(shù)超過glSelectBuffer()的size參數(shù)時(shí),OpenGL會(huì)寫入盡可能多的記錄并設(shè)置一個(gè)溢出標(biāo)志。當(dāng)用glRenderMode()退出選擇模式時(shí),這條命令返回被寫入的記錄的個(gè)數(shù)(包括一條部分記錄如果有的話),清除名字棧,復(fù)位溢出標(biāo)識(shí),重置棧指針。如設(shè)定溢了出標(biāo)識(shí)則返回值是-1。

            -------------------------------------------------------------------------------
            一個(gè)選擇的例子

            在Example 12-2中,4個(gè)三角形(綠、紅、兩個(gè)黃)在選擇模式下繪制,相應(yīng)的命中記錄被處理。第一個(gè)三角形生成一個(gè)命中,第二個(gè)不,第三第四個(gè)共同生成一個(gè)命中。定義了兩個(gè)例程:繪制三角形(drawTriangle()),繪制一個(gè)表示視見體的線框的盒子。processHits()例程打印出選擇數(shù)組。最后,selectObjects()在選擇模式下繪制三角形以生成命中記錄。

            /*****************************************************************************/
            Example 12-2 : A Selection Example: select.c

            #include <GL/gl.h>
            #include <GL/glu.h>
            #include "aux.h"

            void drawTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat z)
            {
                glBegin (GL_TRIANGLES);
                glVertex3f (x1, y1, z);
                glVertex3f (x2, y2, z);
                glVertex3f (x3, y3, z);
                glEnd ();
            }

            void drawViewVolume (GLfloat x1, GLfloat x2, GLfloat y1, GLfloat y2, GLfloat z1, GLfloat z2)
            {
                glColor3f (1.0, 1.0, 1.0);
                glBegin (GL_LINE_LOOP);
                glVertex3f (x1, y1, -z1);
                glVertex3f (x2, y1, -z1);
                glVertex3f (x2, y2, -z1);
                glVertex3f (x1, y2, -z1);
                glEnd ();

                glBegin (GL_LINE_LOOP);
                glVertex3f (x1, y1, -z2);
                glVertex3f (x2, y1, -z2);
                glVertex3f (x2, y2, -z2);
                glVertex3f (x1, y2, -z2);
                glEnd ();

                glBegin (GL_LINES); /* 4 lines */
                glVertex3f (x1, y1, -z1);
                glVertex3f (x1, y1, -z2);
                glVertex3f (x1, y2, -z1);
                glVertex3f (x1, y2, -z2);
                glVertex3f (x2, y1, -z1);
                glVertex3f (x2, y1, -z2);
                glVertex3f (x2, y2, -z1);
                glVertex3f (x2, y2, -z2);
                glEnd ();
            }

            void drawScene (void)
            {
                glMatrixMode (GL_PROJECTION);
                glLoadIdentity ();
                gluPerspective (40.0, 4.0/3.0, 0.01, 100.0);

                glMatrixMode (GL_MODELVIEW);
                glLoadIdentity ();
                gluLookAt (7.5, 7.5, 12.5, 2.5, 2.5, -5.0, 0.0, 1.0, 0.0);
                glColor3f (0.0, 1.0, 0.0); /* green triangle */
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -5.0);
                glColor3f (1.0, 0.0, 0.0); /* red triangle */
                drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, -5.0);
                glColor3f (1.0, 1.0, 0.0); /* yellow triangles */
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, 0.0);
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -10.0);
                drawViewVolume (0.0, 5.0, 0.0, 5.0, 0.0, 10.0);
            }

            void processHits (GLint hits, GLuint buffer[])
            {
                unsigned int i, j;
                GLuint names, *ptr;

                printf ("hits = %d\n", hits);
                ptr = (GLuint *) buffer;
                for (i = 0; i < hits; i++) { /* for each hit */
                    names = *ptr;
                    printf(" number of names for hit = %d\n", names); ptr++;
                    printf (" z1 is %u;", *ptr); ptr++;
                    printf (" z2 is %u\n", *ptr); ptr++;
                    printf (" the name is ");
                    for (j = 0; j < names; j++) { /* for each name */
                        printf ("%d ", *ptr); ptr++;
                    }
                    printf ("\n");
                }
            }

            #define BUFSIZE 512

            void selectObjects(void)
            {
                GLuint selectBuf[BUFSIZE];
                GLint hits, viewport[4];

                glSelectBuffer (BUFSIZE, selectBuf);
                (void) glRenderMode (GL_SELECT);

                glInitNames();
                glPushName(-1);

                glPushMatrix ();
                glMatrixMode (GL_PROJECTION);
                glLoadIdentity ();
                glOrtho (0.0, 5.0, 0.0, 5.0, 0.0, 10.0);
                glMatrixMode (GL_MODELVIEW);
                glLoadIdentity ();
                glLoadName(1);
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -5.0);
                glLoadName(2);
                drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, -5.0);
                glLoadName(3);
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, 0.0);
                drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -10.0);
                glPopMatrix ();
                glFlush ();

                hits = glRenderMode (GL_RENDER);
                processHits (hits, selectBuf);
            }

            void myinit (void)
            {
                glDepthFunc(GL_LEQUAL);
                glEnable(GL_DEPTH_TEST);
                glShadeModel(GL_FLAT);
            }

            void display(void)
            {
                glClearColor (0.0, 0.0, 0.0, 0.0);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                drawScene ();
                selectObjects ();
                glFlush();
            }


            int main(int argc, char** argv)
            {
                auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
                auxInitPosition (0, 0, 200, 200);
                auxInitWindow (argv[0]);
                myinit ();
                auxMainLoop(display);
            }
            /************************************************************************************/


            -------------------------------------------------------------------------------
            拾取

            作為前一節(jié)所描述的處理過程的一個(gè)擴(kuò)展,你可以用選擇模式確定物體是否被拾取了。要做到這一點(diǎn),用一個(gè)與投影矩陣相關(guān)聯(lián)的拾取矩陣將繪制限制在視口的一個(gè)很小的區(qū)域里,通常是在光標(biāo)附近。然后允許某種形式的輸入,如點(diǎn)擊鼠標(biāo)的一個(gè)鍵,引發(fā)選擇模式的初始化。建立起選擇模式并使用特定的拾取矩陣,繪制在光標(biāo)附近的物體引發(fā)選擇命中。即,通常在拾取的時(shí)候確定哪個(gè)物體被畫在光標(biāo)附近了。

            拾取的建立幾乎與正規(guī)的選擇模式完全一樣,只有以下的主要區(qū)別:

            拾取通常由某個(gè)輸入設(shè)備觸發(fā)。在下面的例子中,按鼠標(biāo)左鍵運(yùn)行實(shí)現(xiàn)拾取的函數(shù)。
            用例程gluPickMatrix()將一個(gè)特殊的投影矩陣乘到當(dāng)前矩陣上。它要在把投影矩陣乘到棧上之前調(diào)用。

            另外,實(shí)現(xiàn)拾取的完全不同的方法在"Object Selection Using the Back Buffer"里有所描述。這一技術(shù)使用顏色值標(biāo)識(shí)物體的不同部件。

            void gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, GLint viewport[4]);
            建立一個(gè)投影矩陣用于將繪制限制在視口的一個(gè)小區(qū)域里,并將這個(gè)矩陣乘到當(dāng)前矩陣棧上。拾取區(qū)域的中心是窗口坐標(biāo)(x,y)處,通常是光標(biāo)位置。width和height定義選取區(qū)域大小,用屏幕坐標(biāo)。(你可以認(rèn)為寬和高是設(shè)備第三的)。viewport[]表明當(dāng)前視口邊界,這可以用調(diào)用glGetIntegerv(GL_VIEWPORT,GLint *viewport);獲得。

            深入

            gluPickMatrix()建立的矩陣的凈結(jié)果(net result)是將裁剪區(qū)域變換到單位立方體-1&1e;(x,y,z)&1e;1(或-w&1e;(wx,wy,wz)&1e;w)。拾取矩陣實(shí)際上提供了一個(gè)正交變換將這個(gè)單位立方體的一個(gè)子區(qū)域映射到單位立方體。因?yàn)樽儞Q是任意的,你可以讓拾取為不同類型的領(lǐng)域工作-如,用于旋轉(zhuǎn)窗口的矩形區(qū)域。在某些情況下,你會(huì)發(fā)覺用附加的裁剪平面定義拾取區(qū)域要容易些。

            Example 12-3演示了一個(gè)簡單的選取。它也演示了怎樣用多個(gè)名字標(biāo)識(shí)同一圖元的不同部件,在這里行和列是一個(gè)被選物體。一個(gè)3X3矩陣被畫出來,每個(gè)廣場有不同的顏色。數(shù)組board[3][3]維護(hù)每個(gè)塊的當(dāng)前點(diǎn)擊總數(shù)。當(dāng)前鼠標(biāo)左鍵被按下,pickSquares()例子被調(diào)用來識(shí)別哪個(gè)方塊被鼠標(biāo)拾取了。在網(wǎng)格中兩個(gè)名字標(biāo)識(shí)一個(gè)方塊-一個(gè)表示行、一個(gè)表示列。當(dāng)鼠標(biāo)左鍵被按下,光標(biāo)位置下的所有方塊的顏色也會(huì)改變。

            /*******************************************************************/
            Example 12-3 : A Picking Example: picksquare.c

            #include <GL/gl.h>
            #include <GL/glu.h>
            #include "aux.h"

            int board[3][3]; /* amount of color for each square */

            /* Clear color value for every square on the board */
            void myinit(void)
            {
                int i, j;
                for (i = 0; i < 3; i++)
                    for (j = 0; j < 3; j ++)
                        board[i][j] = 0;
                glClearColor (0.0, 0.0, 0.0, 0.0);
            }

            void drawSquares(GLenum mode)
            {
                GLuint i, j;
                for (i = 0; i < 3; i++) {
                    if (mode == GL_SELECT)
                        glLoadName (i);
                    for (j = 0; j < 3; j ++) {
                        if (mode == GL_SELECT)
                            glPushName (j);
                        glColor3f ((GLfloat) i/3.0, (GLfloat) j/3.0,
                        (GLfloat) board[i][j]/3.0);
                        glRecti (i, j, i+1, j+1);
                        if (mode == GL_SELECT)
                            glPopName ();
                    }
                }
            }

            void processHits (GLint hits, GLuint buffer[])
            {
                unsigned int i, j;
                GLuint ii, jj, names, *ptr;

                printf ("hits = %d\n", hits);
                ptr = (GLuint *) buffer;
                for (i = 0; i < hits; i++) { /* for each hit */
                    names = *ptr;
                    printf (" number of names for this hit = %d\n", names);
                    ptr++;
                    printf (" z1 is %u;", *ptr); ptr++;
                    printf (" z2 is %u\n", *ptr); ptr++;
                    printf (" names are ");
                    for (j = 0; j < names; j++) { /* for each name */
                        printf ("%d ", *ptr);
                        if (j == 0) /* set row and column */
                            ii = *ptr;
                        else if (j == 1)
                            jj = *ptr;
                        ptr++;
                    }
                    printf ("\n");
                    board[ii][jj] = (board[ii][jj] + 1) % 3;
                }
            }

            #define BUFSIZE 512

            void pickSquares(AUX_EVENTREC *event)
            {
                GLuint selectBuf[BUFSIZE];
                GLint hits;
                GLint viewport[4];
                int x, y;

                x = event->data[AUX_MOUSEX];
                y = event->data[AUX_MOUSEY];
                glGetIntegerv (GL_VIEWPORT, viewport);

                glSelectBuffer (BUFSIZE, selectBuf);
                (void) glRenderMode (GL_SELECT);

                glInitNames();
                glPushName(-1);

                glMatrixMode (GL_PROJECTION);
                glPushMatrix ();
                glLoadIdentity ();
                /* create 5x5 pixel picking region near cursor location */
                gluPickMatrix((GLdouble) x,
                (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
                gluOrtho2D (0.0, 3.0, 0.0, 3.0);
                drawSquares (GL_SELECT);
                glPopMatrix ();
                glFlush ();

                hits = glRenderMode (GL_RENDER);
                processHits (hits, selectBuf);
            }

            void display(void)
            {
                glClear(GL_COLOR_BUFFER_BIT);
                drawSquares (GL_RENDER);
                glFlush();
            }

            void myReshape(GLsizei w, GLsizei h)
            {
                glViewport(0, 0, w, h);
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                gluOrtho2D (0.0, 3.0, 0.0, 3.0);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
            }


            int main(int argc, char** argv)
            {
                auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
                auxInitPosition (0, 0, 100, 100);
                auxInitWindow (argv[0]);
                myinit ();
                auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, pickSquares);
                auxReshapeFunc (myReshape);
                auxMainLoop(display);
            }

            Picking with Multiple Names and a Hierarchical Model

            Multiple names can also be used to choose parts of a hierarchical object in a scene. For example, if you were rendering an
            assembly line of automobiles, you might want the user to move the mouse to pick the third bolt on the left front tire of the third
            car in line. A different name can be used to identify each level of hierarchy: which car, which tire, and finally which bolt. As
            another example, one name can be used to describe a single molecule among other molecules, and additional names can
            differentiate individual atoms within that molecule.

            Example 12-4 is a modification of Example 3-4 that draws an automobile with four identical wheels, each of which has five
            identical bolts. Code has been added to manipulate the name stack with the object hierarchy.

            Example 12-4 : Creating Multiple Names

            draw_wheel_and_bolts()
            {
                long i;

                draw_wheel_body();
                for (i = 0; i < 5; i++) {
                    glPushMatrix();
                    glRotate(72.0*i, 0.0, 0.0, 1.0);
                    glTranslatef(3.0, 0.0, 0.0);
                    glPushName(i);
                    draw_bolt_body();
                    glPopName();
                    glPopMatrix();
                }
            }

            draw_body_and_wheel_and_bolts()
            {
                draw_car_body();
                glPushMatrix();
                glTranslate(40, 0, 20); /* first wheel position*/
                glPushName(1); /* name of wheel number 1 */
                draw_wheel_and_bolts();
                glPopName();
                glPopMatrix();
                glPushMatrix();
                glTranslate(40, 0, -20); /* second wheel position */
                glPushName(2); /* name of wheel number 2 */
                draw_wheel_and_bolts();
                glPopName();
                glPopMatrix();

                /* draw last two wheels similarly */
            }

            Example 12-5 uses the routines in Example 12-4 to draw three different cars, numbered 1, 2, and 3.

            Example 12-5 : Using Multiple Names

            draw_three_cars()
            {
                glInitNames();
                glPushMatrix();
                translate_to_first_car_position();
                glPushName(1);
                draw_body_and_wheel_and_bolts();
                glPopName();
                glPopMatrix();

                glPushMatrix();
                translate_to_second_car_position();
                glPushName(2);
                draw_body_and_wheel_and_bolts();
                glPopName();
                glPopMatrix();

                glPushMatrix();
                translate_to_third_car_position();
                glPushName(3);
                draw_body_and_wheel_and_bolts();
                glPopName();
                glPopMatrix();
            }


            Assuming that picking is performed, the following are some possible name-stack return values and their interpretations. In
            these examples, at most one hit record is returned; also, d1 and d2 are depth values.

            empty The pick was outside all cars

            2 d1d2 2 1 Car 2, wheel 1

            1 d1d2 3 Car 3 body

            3 d1d2 1 1 0 Bolt 0 on wheel 1 on car 1

            The last interpretation assumes that the bolt and wheel don't occupy the same picking region. A user might well pick both the
            wheel and the bolt, yielding two hits. If you receive multiple hits, you have to decide which hit to process, perhaps by using the
            depth values to determine which picked object is closest to the viewpoint. The use of depth values is explored further in the
            next section.

            Picking and Depth Values

            Example 12-6 demonstrates how to use depth values when picking to determine which object is picked. This program draws
            three overlapping rectangles in normal rendering mode. When the left mouse button is pressed, the pickRects() routine is
            called. This routine returns the cursor position, enters selection mode, initializes the name stack, and multiplies the picking
            matrix onto the stack before the orthographic projection matrix. A selection hit occurs for each rectangle the cursor is over
            when the left mouse button is clicked. Finally, the contents of the selection buffer is examined to identify which named objects
            were within the picking region near the cursor.

            The rectangles in this program are drawn at different depth, or z, values. Since only one name is used to identify all three
            rectangles, only one hit can be recorded. However, if more than one rectangle is picked, that single hit has different minimum
            and maximum z values.

            Example 12-6 : Picking with Depth Values: pickdepth.c

            #include <GL/gl.h>
            #include <GL/glu.h>
            #include "aux.h"

            void myinit(void)
            {
                glClearColor (0.0, 0.0, 0.0, 0.0);
                glDepthFunc(GL_LEQUAL);
                glEnable(GL_DEPTH_TEST);
                glShadeModel(GL_FLAT);
                glDepthRange (0.0, 1.0); /* The default z mapping */
            }

            void drawRects(GLenum mode)
            {
                if (mode == GL_SELECT)
                    glLoadName (1);
                glBegin (GL_QUADS);
                glColor3f (1.0, 1.0, 0.0);
                glVertex3i (2, 0, 0);
                glVertex3i (2, 6, 0);
                glVertex3i (6, 6, 0);
                glVertex3i (6, 0, 0);
                glColor3f (0.0, 1.0, 1.0);
                glVertex3i (3, 2, -1);
                glVertex3i (3, 8, -1);
                glVertex3i (8, 8, -1);
                glVertex3i (8, 2, -1);
                glColor3f (1.0, 0.0, 1.0);
                glVertex3i (0, 2, -2);
                glVertex3i (0, 7, -2);
                glVertex3i (5, 7, -2);
                glVertex3i (5, 2, -2);
                glEnd ();
            }

            void processHits (GLint hits, GLuint buffer[])
            {
                unsigned int i, j;
                GLuint names, *ptr;

                printf ("hits = %d\n", hits);
                ptr = (GLuint *) buffer;
                for (i = 0; i < hits; i++) { /* for each hit */
                    names = *ptr;
                    printf (" number of names for hit = %d\n", names);
                    ptr++;
                    printf (" z1 is %u;", *ptr); ptr++;
                    printf (" z2 is %u\n", *ptr); ptr++;
                    printf (" the name is ");
                    for (j = 0; j < names; j++) { /* for each name */
                        printf ("%d ", *ptr); ptr++;
                    }
                    printf ("\n");
                }
            }

            #define BUFSIZE 512

            void pickRects(AUX_EVENTREC *event)
            {
                GLuint selectBuf[BUFSIZE];
                GLint hits;
                GLint viewport[4];
                int x, y;

                x = event->data[AUX_MOUSEX];
                y = event->data[AUX_MOUSEY];
                glGetIntegerv (GL_VIEWPORT, viewport);

                glSelectBuffer (BUFSIZE, selectBuf);
                (void) glRenderMode (GL_SELECT);

                glInitNames();
                glPushName(-1);

                glMatrixMode (GL_PROJECTION);
                glPushMatrix ();
                glLoadIdentity ();
                /* create 5x5 pixel picking region near cursor location */
                gluPickMatrix ((GLdouble) x,
                (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
                glOrtho (0.0, 8.0, 0.0, 8.0, 0.0, 2.0);
                drawRects (GL_SELECT);
                glPopMatrix ();
                glFlush ();

                hits = glRenderMode (GL_RENDER);
                processHits (hits, selectBuf);
            }

            void display(void)
            {
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                drawRects (GL_RENDER);
                glFlush();
            }

            void myReshape(GLsizei w, GLsizei h)
            {
                glViewport(0, 0, w, h);
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho (0.0, 8.0, 0.0, 8.0, 0.0, 2.0);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
            }


            int main(int argc, char** argv)
            {
                auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
                auxInitPosition (0, 0, 100, 100);
                auxInitWindow (argv[0]);
                myinit ();
                auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, pickRects);
                auxReshapeFunc (myReshape);
                auxMainLoop(display);
            }


            Try This

            Try This

            Modify Example 12-6 to add additional calls to glPushName() so that multiple names are on the stack when the
            selection hit occurs. What will the contents of the selection buffer be?

            By default, glDepthRange() sets the mapping of the z values to [0.0,1.0]. Try modifying the glDepthRange() values
            and see how it affects the z values that are returned in the selection array.
            -------------------------------------------------------------------------------
            關(guān)于編寫使用選擇的程序的提示

            posted on 2007-08-15 11:49 zmj 閱讀(1345) 評(píng)論(3)  編輯 收藏 引用

            評(píng)論

            # re: 選擇與反饋 2007-08-17 17:02 andyliu

            嗯,很好,謝謝博主,現(xiàn)在在學(xué)OpenGL,剛?cè)腴T,會(huì)經(jīng)常來看看的,希望能發(fā)現(xiàn)更多的好東東!!

            ps:你那篇《Z坐標(biāo)、深度緩存和透視投影》給我同學(xué)看了下,得到很高的贊揚(yáng)哦,學(xué)到了不少東西!!   回復(fù)  更多評(píng)論   

            # re: 選擇與反饋 2007-10-03 00:12 linben

            開源gis中文鏡像--我要開源

            http://www.51kaiyuan.net/index.php?controller=BoDashboard&action=Search3&classId=212  回復(fù)  更多評(píng)論   

            # re: 選擇與反饋 2007-10-13 20:53 flyman

            樓主精神可嘉,鼓勵(lì)鼓勵(lì)。  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久久精品一区二区三区| 久久九九青青国产精品| 91亚洲国产成人久久精品网址 | 亚洲国产高清精品线久久| 久久伊人五月天论坛| 久久婷婷色香五月综合激情| 噜噜噜色噜噜噜久久| 2021久久国自产拍精品| 国产成人精品久久亚洲高清不卡| 亚洲人成网站999久久久综合| 波多野结衣久久一区二区| 久久99国内精品自在现线| 国产精品欧美久久久久天天影视| 亚洲欧美另类日本久久国产真实乱对白| 久久91精品国产91久| 九九久久99综合一区二区| 色婷婷狠狠久久综合五月| 99久久精品国产麻豆| 久久天天躁狠狠躁夜夜不卡| 国产高潮久久免费观看| 亚洲AV日韩精品久久久久久| 久久精品国产一区二区| 久久国产精品久久精品国产| 久久久久久久91精品免费观看| 久久国产一区二区| 无遮挡粉嫩小泬久久久久久久| 久久久久久国产a免费观看不卡 | 免费精品久久久久久中文字幕| 精品国产青草久久久久福利| 国内精品久久久久久久涩爱| 久久综合综合久久综合| 欧美日韩精品久久久久| 一级做a爱片久久毛片| 久久亚洲精品人成综合网| 99精品国产免费久久久久久下载| 国产精品久久久久久久| 久久综合给合久久狠狠狠97色 | 久久香蕉一级毛片| 久久婷婷五月综合97色| 浪潮AV色综合久久天堂| 久久一日本道色综合久久|