最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

OpenGL Picking

2023-06-12 09:12 作者:我夢見珍妮  | 我要投稿


在開發(fā)OpenGL程序時,一個重要的問題就是互動,假設(shè)一個場景里面有很多元素,當用鼠標點擊不同元素時,期待作出不同的反應(yīng),那么在OpenGL里面,是怎么知道我當前鼠標的位置是哪一個物體呢?



OpenGL有一套機制,叫做Picking, 里面涉及到幾個核心概念:


1. selection mode. 選擇模式


2. name stack. 名字棧


3. hit record。 命中記錄


4. viewing volume。 視角范圍



在OpenGL的picking中,選擇物體不是選擇一個單獨的物體,而是選擇一片范圍內(nèi)的所有物體。這種設(shè)計思路是有點奇怪,但是OpenGL就是這麼設(shè)計的。假如鼠標當前的位置是(200,200),普通的應(yīng)用就是選擇在點(200,200)處的物體ID, 但OpenGL不然,它是選擇以(200,200)為中心的,比如長寬都為20的這個范圍內(nèi)可見的物體,也就是說,前面一種選擇,是以點為選擇依據(jù),OpenGL的選擇,是以中心為(200,200),長寬各位10的面為依據(jù),好像舉著一個畫框,只要在這個畫框內(nèi)的物體,都會當作返回結(jié)果。



我不是很理解為什么OpenGL要這麼設(shè)計,但肯定有它的道理。以上的幾個核心概念,就是配合這種設(shè)計思路的,不難看出:


1. Viewing volume。就是指用來選擇的畫框


2. hit record。就是所返回的物體數(shù)據(jù)


3. name stack。是用來分配并保存物體ID的堆棧


4. selection mode. OpenGL有三種模式,Render mode。就是普通的繪圖模式,Select mode。在picking時的選擇模式,F(xiàn)eedback mode。不畫圖,不選擇,而是把所有最終的渲染完之后的繪畫指令返回給用戶。在繪圖儀上作畫等方面特別有用


當需要相應(yīng)鼠標選擇事件的時候,要首先進入selection mode, 然后才能執(zhí)行相應(yīng)的操作步驟



以下是詳細的操作步驟:


1. 獲取鼠標位置


2. 進入選擇模式selection mode


3. 設(shè)置畫框大小view volume,當然,是根據(jù)鼠標位置來的


4. 像往常一樣繪制場景


5. 退出選擇模式,得到選擇結(jié)果



進入選擇模式:


1. glSelectBuffer,設(shè)置選擇緩沖區(qū),hit record會被OpenGL保存在里面


2. glRenderMode(GL_SELECT),正式進入選擇模式



設(shè)置畫框大小:


1. gluPickMatrix。設(shè)置畫框近平面大小


2. gluPerspective。影響畫框的容量



注意,上面的代碼中在執(zhí)行g(shù)luPickMatrix值錢先保存了投影矩陣,然后再重新創(chuàng)造一個新的供自己使用。原因是gluPickMatrix會操作投影舉證,該函數(shù)和后續(xù)的gluPerspective共同作用,最終會生成一個全新的投影矩陣,該矩陣中的所有物體,都會被視為選中。為了不影響舊有的投影矩陣,因此需要保存先

繪制場景:


繪制場景的時候有一點比較重要,那就是對每個需要繪制的單獨元素,起一個名字(ID),這樣OpenGL才能在推出選擇模式的時候告知調(diào)用者,哪個物體被選擇了。當然如果非不取,那OpenGL也會返回被選擇的物體,只是不帶名字。因此繪制場景的步驟一般如下:


1. glInitNames, 初始化name stack。 OpenGL的中對元素名字的操作需要通過一個棧,叫做名字棧,為啥這麼墨跡,不直接指定名字?具體原因是OpenGL總要有個地方去讀取名字,而且,一個名字下包括哪些需要繪畫的內(nèi)容?OpenGL怎么知道當前畫的這個人頭是屬于上個人的還是上上個人的?只能通過名字棧的變化才能知道。而且一個元素可以有多個內(nèi)容,怎么搞?于是乎名字棧就應(yīng)運而生,OpenGL認為這個東東可以解決這一系列問題


2. glPushName。 創(chuàng)建一個名字。


3. 開始畫啊畫啊畫


4. glPopName。一個元素繪制結(jié)束


5. 從步驟2循環(huán)到4的一個個元素繪制


還有另外一個有用的函數(shù),glLoadName。它的作用是用一個新的名字替代棧頂當前的名字。說白了,就等同于:


glPopName()


glPushName(newName)



OpenGL里面,一個物體還可以有多個名字,這個貌似有點荒唐,確實也比較荒唐,但OpenGL也有它的道理,比如一個元素,它的名字叫“head",那么,如果我想知道這個頭是誰的頭,怎么搞?OpenGL告訴你壓力不大,再給他取一個名字叫”Aka",那么你就知道這是Aka的頭。也就是說,我繪制了一個元素,然后給它兩個名字,一個叫head, 一個叫aka,那么當你選擇了該物體的時候,你就知道了,這個物體是aka的頭。



示例代碼如下:


glPushName(Aka)


glPushName(Head)


draw()


glPopName(Head)


glPopName(Aka)


于是,draw出來的物體就有兩個名字了.




處理選擇結(jié)果:

處理選擇接過之前,要先推出selection模式,然后OpenGl會返回一個數(shù)目,被選中物體的數(shù)目,跟據(jù)該數(shù)目,就知道在選擇緩沖區(qū)里面保存了多少個物體,每個物體都有固定的數(shù)據(jù)結(jié)構(gòu),一個個的讀取該數(shù)據(jù)結(jié)構(gòu),就知道哪些物體被選取了。



重要的是選擇緩沖區(qū)中hit record的數(shù)據(jù)結(jié)構(gòu),該結(jié)構(gòu)是一個GLuinit的類型,也就說里面所有的數(shù)據(jù)都是uinit,等等,名字不是也在里面嗎,這可是string啊,no, 名字其實不是string,準確的說應(yīng)該叫ID,普通的1,2,3而已


每一個元素的結(jié)構(gòu)提如下:


1. 該物體的名字的數(shù)目。一個物體可以有多個名字,你懂的


2. 該物體被選中區(qū)域的最小Z值。我們往往根據(jù)這個值得知哪一個才是鼠標點所在的物體


3. 該物體被選中區(qū)域的最大Z值。


4. 名字


5. 名字。。



由于物體可以有多個名字,甚至可以木有名字,因此元素的結(jié)構(gòu)不是固定大小的,以下為例:


Hit Record Contents Description

0 表示這個元素沒名字

4.2822e+009 最小Z值

4.28436e+009 最大Z值

1 這個元素有1個名字

4.2732e+009 最小Z值

4.27334e+009 最大Z值

6 名字叫6

2 這個元素有2個名字

4.27138e+009 最小Z值

4.27155e+009 最大Z值

2 第一個名字叫2

5 第二個名字叫5


所以呢,只需要對著選擇緩沖區(qū),一個個的讀下去就對了,


注意:以上所有的概念和函數(shù),都只在selection mode下面有效。如果轉(zhuǎn)到了Render mode,系統(tǒng)怎么處理這些函數(shù)呢?很簡單,華麗的無視掉。



參考文獻:


http://www.lighthouse3d.com/opengl/picking/index.php3?openglway


________________________________________________________________________________________________


OpenGL中采用一種比較復(fù)雜的方式實現(xiàn)了拾取操作,即選擇模式。選擇模式是一種繪制模式,它基本思想是在一次拾取操作時,系統(tǒng)根據(jù)拾取操作的參數(shù)(如鼠標位置)生成一個特定視景體,然后由系統(tǒng)重新繪制場景中的所有圖元,但這些圖元并不會繪制到顏色緩存中,系統(tǒng)跟蹤有哪些圖元繪制到了這個特定的視景體中,并將這些對象 的標識符保存到拾取緩沖區(qū)數(shù)組中。



? ? 在OpenGL中實現(xiàn) 拾取操作主要包括以下步驟:


? ? 1.設(shè)置拾取緩沖區(qū)

? ? 拾取時,在特定的視景體中繪制每個對象都會產(chǎn)生一個命中消息,命中消息將存放在一個名字堆棧中,這個名字堆棧就是拾取緩沖區(qū)。函數(shù):

? ? ? ? void glSelectBuffer(GLsizei n, GLunint *buff);

指定了一個具有n個元素的整形數(shù)組buffer作為拾取緩沖區(qū)。對于每個命中消息,都會在拾取緩沖區(qū)數(shù)組中添加一條記錄,每條記錄包含了以下的信息:

? ? (1)命中發(fā)生時堆棧中的名稱序號;

? ? (2)拾取圖元所有頂點的最大和最小窗口z坐標。這兩個值的范圍都位于[0,1]內(nèi),他們都乘以232-1,然后四舍五入為最接近的無符號整數(shù)。

? ? (3)命中發(fā)生時堆棧中的內(nèi)容(物體的名字),最下面的名稱排在最前面。


? ? 2.進入選擇模式

? ? 在定義了拾取緩沖區(qū)后,需要激活選擇模式。選擇模式的指定采用函數(shù):

? ? ? ? GLint glRenderMode(GLenum mode);

其中,參數(shù)mode值可以為GL_RENDER(默認值)、GL_SELECT或GL_FEEDBACK,分別指定應(yīng)用程序處于渲染模式、選擇模式和反饋模式。應(yīng)用程序一直處于當前模式下,直到調(diào)用本函數(shù)改變?yōu)槠渌J綖橹埂?/p>


? ? 3.名字堆棧操作

? ? 在選擇模式下,需要對名字堆棧進行一系列操作,包括初始化、壓棧、彈棧以及棧頂元素操作等。

? ? ? ? void glInitNames();//初始化名字堆棧,其初始狀態(tài)為空

? ? ? ? void glPushName(GLuint name);//將一個名字壓入堆棧,其中name是標識圖元的一個無符號整數(shù)值

? ? ? ? void glLoad Name(GLuint name);//將名字堆棧的棧頂元素替換為name

? ? ? ? void glPopName();//將棧頂元素彈出


? ? 4.設(shè)置合適的變換過程

? ? 拾取操作可以通過矩形拾取窗口來實現(xiàn),我們可以用下面的函數(shù)調(diào)用:

? ? ? ? gluPickMatrix(xPick, yPick, widthPick, heightPick, *vp);

其中參數(shù)xPick和yPick指定相對于顯示區(qū)域左下角的拾取窗口中心的雙精度浮點屏幕坐標值。當使用鼠標進行選擇操作時,xPick和yPick由鼠標位置確定,但要注意y坐標的反轉(zhuǎn)。參數(shù)widthPick和heightPick指定拾取窗口的雙精度浮點寬高值。參數(shù)vp指定了一個包含當前顯示區(qū)域的坐標位置和尺寸等參數(shù)的整型數(shù)組,該參數(shù)可以通過函數(shù)glGetIntegerv來獲得。這個函數(shù)可以設(shè)置一個用于拾取操作的觀察空間。


? ? 5.為每個圖元分配名字并繪制

? ? 為了標識圖元,在圖元繪制過程中需要用一個整型值指定圖元的名稱,并在選擇模式下,將這個名字壓入到名字堆棧中。為了節(jié)省名字堆棧的空間,應(yīng)該在圖元繪制完成后,將其名字從堆棧中彈出。


? ? 6.切換回渲染模式

? ? 在選擇模式下,所有的圖元繪制完成后,應(yīng)該再次調(diào)用函數(shù)glRenderMode選擇渲染模式,在幀緩沖存儲器中繪制圖元,并返回被選中圖元的個數(shù)。


hits=glRenderMode(GL_RENDER);返回值hits表示The number of hit records transferred to the select buffer(轉(zhuǎn)移到緩沖區(qū)中已命中的記錄數(shù))。


? ? ? ? ? ? ? ? glPushName(1);? ? ? ? ? ? ? ? //1? ? ? ? ? ? ? ? ? ? ? ? ? ??


? ? ? ? ? ? ?glColor3f(1.0f,0.0f,0.0f);? ? ? ? ? //2

? ? ? ? ? ?glRectf(60.0f,50.0f,150.0f,150.0f);? ? //3


表示2,3行繪制的對象在名字堆棧中的名字為1,并且該記錄的詳細信息記錄在緩沖區(qū)中。hits=glRenderMode(GL_RENDER);返回的是命中的記錄條數(shù)。根據(jù)條數(shù)用循環(huán)可以讀出緩沖區(qū)中每個命中物體的名字,根據(jù)名字即可畫出來。


7.分析選擇緩沖區(qū)中的數(shù)據(jù)

? ? 拾取操作完成之后,可以根據(jù)選擇緩沖區(qū)中的內(nèi)容進行分析,以確定拾取的圖元。


?


程序3-3 OpenGL實現(xiàn)的拾取操作的例子

#include <gl/glut.h>

#include "stdio.h"

const GLint pickSize = 32;

int winWidth = 400, winHeight = 300;


void Initial(void)

{

?glClearColor(1.0f, 1.0f, 1.0f, 1.0f);? ? ? ??

}


void DrawRect(GLenum mode)

{

?if(mode == GL_SELECT) glPushName(1); //壓入堆棧

?glColor3f(1.0f,0.0f,0.0f);

?glRectf(60.0f,50.0f,150.0f,150.0f);

?

if(mode == GL_SELECT) glPushName(2); //壓入堆棧

glColor3f(0.0f,1.0f,0.0f);

glRectf(230.0f,50.0f,330.0f,150.0f);


if(mode == GL_SELECT) glPushName(3); //壓入堆棧

glColor3f(0.0f,0.0f,1.0f);

glRectf(140.0f,140.0f,240.0f,240.0f);

}


void ProcessPicks(GLint nPicks, GLuint pickBuffer[])

{

?GLint i;

?GLuint name, *ptr;

printf("選中的數(shù)目為%d個\n",nPicks);

ptr=pickBuffer;

for(i=0;i<nPicks; i++){

?name=*ptr;? ? //選中圖元在堆棧中的位置

?ptr+=3;? ? ? ?//跳過名字和深度信息

?ptr+=name-1;? //根據(jù)位置信息獲得選中的圖元名字

?if(*ptr==1) printf("你選擇了紅色圖元\n");

?if(*ptr==2) printf("你選擇了綠色圖元\n");

?if(*ptr==3) printf("你選擇了藍色圖元\n");

?ptr++;

}

?printf("\n\n");

}


void ChangeSize(int w, int h)

{

winWidth = w;

winHeight = h;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0,winWidth,0.0,winHeight);

}


void Display(void)

{

glClear(GL_COLOR_BUFFER_BIT);

DrawRect(GL_RENDER);

glFlush();

}


void MousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse)

{

GLuint pickBuffer[pickSize];

GLint nPicks, vp[4];


if(button == GLUT_LEFT_BUTTON && action == GLUT_DOWN){

?glSelectBuffer(pickSize,pickBuffer); //設(shè)置選擇緩沖區(qū)

glRenderMode(GL_SELECT); //激活選擇模式

glInitNames();? ?//初始化名字堆棧

glMatrixMode(GL_PROJECTION);

glPushMatrix();

glLoadIdentity();

glGetIntegerv(GL_VIEWPORT, vp);

//定義一個10×10的選擇區(qū)域

gluPickMatrix(GLdouble(xMouse), GLdouble(vp[3]-yMouse),10.0,10.0,vp);

gluOrtho2D(0.0,winWidth,0.0,winHeight);

DrawRect(GL_SELECT);

//恢復(fù)投影變換

glMatrixMode(GL_PROJECTION);

glPopMatrix();

glFlush();


//獲得選擇集并輸出

nPicks = glRenderMode(GL_RENDER);

ProcessPicks(nPicks, pickBuffer);

glutPostRedisplay();

}

}


int main(int argc, char* argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);?

glutInitWindowSize(400,300);? ? ? ? ? ? ? ? ?

glut


___________________________________________________________________________________————————————

以下內(nèi)容主要整理《OpenGL編程指南》第13章的內(nèi)容。主要解決以下問題:


?


(1)如何允許用戶選擇屏幕上的一塊區(qū)域或者挑選屏幕上所繪制的一個物體?


?


一. 選擇


?


1. OpenGL的選擇機制如何實現(xiàn)


?


當我們打算使用OpenGL的選擇機制時:


(1)首先把整個場景繪制到幀緩沖區(qū)中;


(2)然后進入選擇模式,并且對場景進行重繪,此時,幀緩沖區(qū)的內(nèi)容將不會被修改;


(3)退出選擇模式時,OpenGL就會返回與視景體相交的圖元列表,與視景體相交的每一個圖元都產(chǎn)生一個所謂的“選擇點擊”。


?(圖元列表:實際上是以點擊記錄的形式返回,包含了圖元的名稱以及相關(guān)的數(shù)據(jù)。我們可以訪問該列表并處理其中的內(nèi)容)


?


2. 基本步驟


?


//在繪制了場景之后,進入以下步驟


?


(1)


#define BUFSIZE 512


GLuint selectBuf[BUFSIZE];


glSelectBuffer( BUFSIZE, selectBuf );? ?//指定將“圖元列表”(點擊記錄)返回到selectBuf數(shù)組中


?


(2)


glRenderMode( GL_SELECT );? ?//進入選擇模式


?


(3)


glInitNames();? ? // //初始化名字堆棧并壓入初始元素


glPushName();


?


(4)


glPushMatrix();? ?//為重繪設(shè)置好投影矩陣,注意,為了不影響繪制模式,要用glPushMatrix和glPopMatrix


glMatrixMode(GL_PROJECTION);


glLoadIdentity();


glOrtho(0.0,5.0,0.0,5.0,0.0,10.0);


glMatrixMode(GL_MODELVIEW);


glLoadIdentity();


?


(5)


glLoadName(1);? ?//將名字堆棧的堆頂設(shè)置為1,因此,之后繪制的物體的名字為1


drawTri();


?


glLoadName(2);? ?//將名字堆棧的堆頂設(shè)置為2,因此,之后繪制的物體的名字為2


drawTri();


?


glLoadName(3);? ?//將名字堆棧的堆頂設(shè)置為3,因此,之后繪制的物體的名字為3


drawTri();


drawTri();


?


(6)


glPopMatrix();? ?//對應(yīng)glPushMatrix


glFlush();


?


(7)


//返回繪制模式,hits記錄的是產(chǎn)生的點擊的個數(shù),即在視景體內(nèi)的圖元的個數(shù)


Gluint hits = glRenderMode(GL_RENDER);?


?


(8)


//處理點擊記錄


printf("hits = %d\n", hits); //輸出一共產(chǎn)生的點擊的個數(shù)


?


//注意:


//圖元列表(點擊記錄)selectBuf中記錄了所有的點擊記錄

//某一個點擊記錄來說,由四個項目組成:

//(1)當點擊發(fā)生時,名字堆棧中的名稱數(shù)量


//(2)自上一個點擊記錄之后,與視景體相交的所有頂點的最小和最大窗口坐標z值

//(3)當點擊發(fā)生時,名稱堆棧的內(nèi)容,從最底部的元素開始

?


GLuint *ptr = selectBuf;


GLuint names;


for( i=0; i<hits; i++ )


{


? ? names = *ptr;? ?//點擊發(fā)生時,名字堆棧中的名稱數(shù)量


? ? printf("names = %d\n",names );


? ? ptr++;


?


? ? ptr += 2;? //跳過兩個z值


?


? ? for( j=0; j<names; j++ )


? ? {


? ? ? ? printf("%d", *ptr);? //輸出點擊發(fā)生時,名字堆棧中所有的名稱


? ? ? ? ptr++;


? ? }


}


?


二. 拾取


?


1. 如何拾取


?


前一節(jié)介紹了OpenGL的選擇機制如何實現(xiàn)和使用,這一節(jié)將深入的介紹如何利用選擇模式來確定一個物體是否被挑選。


為了實現(xiàn)這個目的,可以在選擇模式中使用一個特殊的挑選矩陣,結(jié)合投影矩陣,把繪圖限制在視口的一個小區(qū)域內(nèi),一般是在靠近光標的位置。這樣,只有靠近光標位置的物體才會引起點擊。


?


gluPickMatrix( GLdouble x, GLdouble y, GLdouble width, GLdouble height, GLint viewport[4] );


(x,y)就是挑選區(qū)域的中心的窗口坐標,width和height定義了屏幕坐標下這個挑選區(qū)域的大小,viewport是指視口邊界,通過glGeIntegerv(GL_VIEWPORT, GLint *viewport)獲得


?


(2) 具體實例


?


下面,用OpenGL編程指南上的實例來介紹如何實現(xiàn)拾取。


?


//該程序完成的功能是:繪制9個方塊,鼠標左鍵點擊,改變方塊的顏色


#include <gl/glut.h>?


int board[3][3];? ?//存儲幾個方塊的顏色


#define BUFSIZE 512

//處理點擊記錄:

//hits為產(chǎn)生的點擊的數(shù)量,buffer中存儲點擊記錄,每個點擊記錄由四個項目組成

void processHits(GLint hits, GLuint buffer[])

{

?unsigned int i, j;

?GLuint ii, jj, names, *ptr;


?ptr = ( GLuint * )buffer;? ?


?


?for( i=0; i<hits; i++ )? ? //處理每一個點擊記錄

?{?

?//某一個點擊記錄來說,由四個項目組成:

//(1)當點擊發(fā)生時,名字堆棧中的名稱數(shù)量


//(2)自上一個點擊記錄之后,與視景體相交的所有頂點的最小和最大窗口坐標z值

//(3)當點擊發(fā)生時,名稱堆棧的內(nèi)容,從最底部的元素開始

? names = *ptr;? ? ? //獲得名字堆棧中的名稱數(shù)量

? ptr += 3;? ? ? ? ? ? ? ?//跳過前三個記錄


? for( j=0; j<names; j++ ) //開始處理名字堆棧中的內(nèi)容,獲取被選中的方塊的index

? {

? ?//對應(yīng)于繪制方塊時,壓入名字堆棧中的內(nèi)容


? ?if ( j == 0)? ? ? ? //x方向上的index

? ? ii = *ptr;

? ?else if( j== 1)? //y方向上的index

? ? jj = *ptr;

? ?ptr++;

? }


?}

?board[ii][jj] = (board[ii][jj] + 1) % 3;? ?//改變被選中方塊的顏色


}


?


//繪制所有方塊,參數(shù)有GL_RENDER和GL_SELECT兩種模式

void drawSquares(GLenum mode)

{

?GLuint i,j;


?for(i=0; i<3; i++)

?{

? if( mode == GL_SELECT )? ? ? ?//如果是在選擇模式下,將名字堆棧的首元素換成x方向上的索引

? ?glLoadName(i);


?


? for( j=0; j<3; j++ )

? {

? ?if( mode == GL_SELECT )? ? //將y方向上的索引壓入名字堆棧

? ? ?glPushName(j);


?


? ?//繪制方塊,在GL_SELECT模式下,某一個方塊會被選中,因此,會產(chǎn)生一個點擊記錄


? ?//該點擊被記錄時,名字堆棧中有兩個名稱,分別是i和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 pickSquares(int button, int state, int x, int y)

{

?GLuint selectBuf[BUFSIZE];? ?//存儲點擊記錄

?GLint hits;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//點擊記錄的個數(shù)

?GLint viewport[4];? ? ? ? ? ? ? ? ? ? //視口


?


?if( button != GLUT_LEFT_BUTTON || state != GLUT_DOWN )

? return;


?


?glGetIntegerv(GL_VIEWPORT, viewport);? //獲得視口


?glSelectBuffer( BUFSIZE, selectBuf );? ? //指定存儲點擊記錄的數(shù)組

?glRenderMode( GL_SELECT );? ? ? ? ? //進入選擇模式


?


?glInitNames();? ? ? ? ? ?//初始化名字堆棧并壓入初始元素

?glPushName(0);


?


?glMatrixMode(GL_PROJECTION);

?glPushMatrix();

?glLoadIdentity();

?

?//設(shè)置挑選矩陣,挑選區(qū)域的中心坐標是(x,viewport[3]-y),大小是(5,5)

?gluPickMatrix( (GLdouble) x, (GLdouble) ( viewport[3] - y ) , 5.0, 5.0, viewport );?

?//設(shè)置投影矩陣

?gluOrtho2D(0.0, 3.0, 0.0, 3.0 );


?//在選擇模式下繪制方塊

?drawSquares(GL_SELECT);

?

?glMatrixMode(GL_PROJECTION);

?glPopMatrix();

?glFlush();? ? ? ? //繪制結(jié)束


?


//處理點擊記錄


?hits = glRenderMode(GL_RENDER); //獲取記錄下的點擊的個數(shù)

?processHits(hits, selectBuf);? ? ? ? ? ?//處理點擊記錄selectBuf


?glutPostRedisplay();

}


?


void init()

{

?glEnable(GL_DEPTH_TEST);

?glShadeModel(GL_FLAT);

?for( int i=0;i <3; i++ )? ? ? ? ? ? //初始化9個方塊的顏色

? for( int j=0; j<3; j++ )

? ?board[i][j] = 0;

}

void display()

{

?glClearColor(0.0,0.0,0.0,0.0);

?glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

?drawSquares(GL_RENDER);? //基本繪制

?glFlush();

}


void reshape( int w, int 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)

{

?glutInit(&argc, argv);

?glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

?glutInitWindowSize(200,200);

?glutInitWindowPosition(100,100);

?glutCreateWindow("pick");

?init();

?glutMouseFunc(pickSquares);? ?//當鼠標點擊時,調(diào)用pickSquares,進入選擇模式進行繪制

?glutReshapeFunc(reshape);

?glutDisplayFunc(display);? ? ? //display只完成基本的繪制

?glutMainLoop();

?return 0;

}


OpenGL Picking的評論 (共 條)

分享到微博請遵守國家法律
来宾市| 土默特左旗| 西昌市| 农安县| 文登市| 漯河市| 黑山县| 柘城县| 泰顺县| 沙坪坝区| 古丈县| 明水县| 平和县| 河源市| 阿鲁科尔沁旗| 库伦旗| 中方县| 康平县| 琼结县| 西贡区| 高安市| 洞口县| 凌海市| 都匀市| 岳西县| 宿迁市| 石嘴山市| 专栏| 湄潭县| 福泉市| 正镶白旗| 荆门市| 宜都市| 拜城县| 天祝| 临泽县| 巴彦淖尔市| 西乌珠穆沁旗| 镇赉县| 东明县| 石棉县|