青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

選擇與反饋

章節(jié)目標

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

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

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

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

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

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

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

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

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

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

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

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

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

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()初始化它,這將簡單地清空棧。然后當你發(fā)布相應的繪制命令時向其中加入整數名字。正如你可能想象,棧控制命令允許你壓入名字(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*/
/********************************************************************/


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

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

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

void glPopName(void);
彈出名字棧棧頂的那一個名字。從空棧中彈出名字引發(fā)GL_STACK_UNDERFLOW錯誤。

void glLoadName(GLuint name);
用name取代名字棧棧頂的那個名字。如果棧是空的,剛調用過glInitName()后就是這樣,glLoadName()生成一個GL_INVALID_OPRATION錯。為避免這種情況,如果棧初始時是空的,那么在調用glLoadName()之前至少調用一次glPushName()以在名字棧中放上點東西。

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

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

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

除圖元之外,glRasterPos()產生的有效坐標也可以引起選擇命中。在多邊形的情況下,如果它已經被消隱掉的話不會有命中記錄出現。

每個命中記錄由四項組成,依次是:
當命中出現時名字棧中的名字數
至上次記錄的命中以來,被視見體裁剪后的圖元的所有頂點的窗口Z坐標的 最大和最小值
本次命中時名字棧的內容,最底元素最前。

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

-------------------------------------------------------------------------------
一個選擇的例子

在Example 12-2中,4個三角形(綠、紅、兩個黃)在選擇模式下繪制,相應的命中記錄被處理。第一個三角形生成一個命中,第二個不,第三第四個共同生成一個命中。定義了兩個例程:繪制三角形(drawTriangle()),繪制一個表示視見體的線框的盒子。processHits()例程打印出選擇數組。最后,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é)所描述的處理過程的一個擴展,你可以用選擇模式確定物體是否被拾取了。要做到這一點,用一個與投影矩陣相關聯(lián)的拾取矩陣將繪制限制在視口的一個很小的區(qū)域里,通常是在光標附近。然后允許某種形式的輸入,如點擊鼠標的一個鍵,引發(fā)選擇模式的初始化。建立起選擇模式并使用特定的拾取矩陣,繪制在光標附近的物體引發(fā)選擇命中。即,通常在拾取的時候確定哪個物體被畫在光標附近了。

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

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

另外,實現拾取的完全不同的方法在"Object Selection Using the Back Buffer"里有所描述。這一技術使用顏色值標識物體的不同部件。

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

深入

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

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

/*******************************************************************/
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.
-------------------------------------------------------------------------------
關于編寫使用選擇的程序的提示

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

評論

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

嗯,很好,謝謝博主,現在在學OpenGL,剛入門,會經常來看看的,希望能發(fā)現更多的好東東!!

ps:你那篇《Z坐標、深度緩存和透視投影》給我同學看了下,得到很高的贊揚哦,學到了不少東西!!   回復  更多評論   

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

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

http://www.51kaiyuan.net/index.php?controller=BoDashboard&action=Search3&classId=212  回復  更多評論   

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

樓主精神可嘉,鼓勵鼓勵。  回復  更多評論   


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


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美不卡视频| 欧美成人性网| 亚洲在线一区| 国产欧美日韩视频在线观看| 欧美不卡在线视频| 亚洲一区二区三区在线看| 亚洲人成久久| 猫咪成人在线观看| 免费黄网站欧美| 欧美激情第8页| 亚洲欧洲日本在线| 日韩视频一区二区在线观看 | 久久精品九九| 日韩图片一区| 性久久久久久| 欧美激情亚洲精品| 国产精品久久久一区麻豆最新章节 | 亚洲乱码日产精品bd| 国产欧美日韩麻豆91| 伊人成人在线| 日韩视频免费观看| 久久xxxx| 91久久久久| 久久久久久噜噜噜久久久精品| 亚洲国产1区| 亚洲永久免费观看| 欧美.日韩.国产.一区.二区| 亚洲精品国产精品久久清纯直播| 亚洲精品久久久久久下一站| 亚洲午夜精品久久久久久浪潮| 亚洲精品国久久99热| 一区二区不卡在线视频 午夜欧美不卡在 | 国产欧美日韩中文字幕在线| 欧美国产视频一区二区| 国产精品乱人伦一区二区| 精品91免费| 久久精品国产一区二区电影| 亚洲日本成人在线观看| 欧美成人久久| 91久久嫩草影院一区二区| 免费成人毛片| 久久精品国产999大香线蕉| 国产伦一区二区三区色一情| 亚洲一区视频| 一区二区免费看| 欧美精品一区二区三区在线播放 | 欧美制服丝袜第一页| 国内精品久久久久久| 亚洲精品自在久久| 亚洲欧洲视频| 国产精品分类| 裸体女人亚洲精品一区| 新片速递亚洲合集欧美合集| 国产精品综合不卡av| 久久米奇亚洲| 欧美福利视频网站| 午夜精品视频在线观看| 亚洲一区二区成人在线观看| 国产精品亚洲综合色区韩国| 久久黄金**| 欧美猛交免费看| 久久精品99无色码中文字幕| 美女图片一区二区| 西西裸体人体做爰大胆久久久| 亚洲欧美日韩国产中文在线| 一区二区在线观看视频在线观看| 亚洲激情校园春色| 黄色成人av在线| 亚洲精品专区| 亚洲国产视频一区二区| 校园激情久久| 午夜欧美精品| 欧美激情一区二区三级高清视频| 亚洲综合精品自拍| 欧美四级电影网站| 亚洲第一级黄色片| 国产综合色在线| 午夜一区在线| 久久成人人人人精品欧| 国产精品美女久久久免费| 亚洲乱码国产乱码精品精98午夜| 极品尤物一区二区三区| 午夜视黄欧洲亚洲| 欧美婷婷六月丁香综合色| 亚洲国内自拍| 亚洲一区美女视频在线观看免费| 欧美成人午夜剧场免费观看| 亚洲大胆视频| 亚洲一区二区三区欧美| 欧美视频在线观看免费| 亚洲欧美电影在线观看| 午夜精品久久一牛影视| 国产日韩精品一区二区| 久久久夜色精品亚洲| 欧美激情网站在线观看| 在线亚洲一区| 亚洲福利视频一区二区| 欧美日韩国产不卡在线看| 亚洲网站在线| 免费成人高清在线视频| 99国产精品久久久| 国产亚洲精品福利| 欧美激情一区三区| 欧美亚洲午夜视频在线观看| 米奇777超碰欧美日韩亚洲| 亚洲欧美国产va在线影院| 红桃av永久久久| 国产午夜亚洲精品不卡| 欧美成人高清| 免费短视频成人日韩| 欧美一区亚洲二区| 亚洲私人影院在线观看| 亚洲人在线视频| 美女脱光内衣内裤视频久久影院| 亚洲午夜激情| 亚洲淫片在线视频| 国产日产亚洲精品| 欧美激情一区二区三级高清视频| 亚洲在线不卡| 欧美一级夜夜爽| 欧美在线免费视频| 欧美在线观看视频| 亚洲毛片网站| 有码中文亚洲精品| 国产精品美腿一区在线看 | 久久国产精品一区二区三区四区| 亚洲美女视频在线免费观看| 亚洲国产婷婷综合在线精品| 在线观看视频欧美| 亚洲精品久久| 午夜精品理论片| 欧美在线啊v| 久久久91精品国产一区二区三区| 久久精品免费看| 亚洲国产精品电影| 亚洲日本理论电影| 亚洲欧美中文日韩在线| 亚洲一区二区视频在线| 亚洲激情在线观看视频免费| 久久国产成人| 久久久久国产精品午夜一区| 亚洲精品国产精品国自产观看 | 免费久久99精品国产自在现线| 国产精品一区视频| 亚洲午夜91| 久久亚洲综合网| 1204国产成人精品视频| 欧美成人久久| 亚洲欧美色一区| 欧美成人免费网站| 亚洲视频一区在线| 久久婷婷国产麻豆91天堂| 欧美人成在线| 亚洲日本免费电影| 乱人伦精品视频在线观看| 亚洲影院色无极综合| 欧美激情五月| 99热在这里有精品免费| 久久一综合视频| 国产精品一区二区三区久久| 亚洲精选视频免费看| 麻豆精品视频在线观看视频| 亚洲黄色av| 欧美一区精品| 国内久久精品| 欧美成人a∨高清免费观看| 久久精品91久久香蕉加勒比 | 亚洲亚洲精品三区日韩精品在线视频| 欧美福利视频在线| 欧美日韩成人综合| 亚洲伊人久久综合| 欧美在线影院| 亚洲免费大片| 欧美一二三区精品| 最新国产成人av网站网址麻豆| 欧美激情一区二区三区蜜桃视频| 欧美激情一区二区三区在线视频| 欧美一区二区三区四区在线观看| 久久九九电影| 新狼窝色av性久久久久久| 久久综合伊人77777| 亚洲精品视频在线观看网站| 亚洲一区二区少妇| 日韩午夜在线| 亚洲欧美日韩区| 99re6热在线精品视频播放速度| 一区二区三区不卡视频在线观看| 一区二区三区在线免费播放| 日韩手机在线导航| 亚洲精品久久久一区二区三区| 在线视频中文亚洲| 在线中文字幕不卡| 欧美人与性禽动交情品| 免费不卡欧美自拍视频| 国产一级一区二区| 一本色道久久综合亚洲精品婷婷 | 欧美在线免费视频| 午夜精品久久久久久久99热浪潮| 亚洲一区成人| 国产精品高潮在线|