OpenGL环境下的射线选择
?
用過OpenGL的人,應該都知道,OpenGL是自帶拾取功能的,但用過的人應該也知道,這功能確實不好用。
?
OpenGL自帶的選擇功能主要有兩種,名字堆棧(拾取)和讀深度值判斷選擇,但這兩種方法在實際項目中,未必都好用。
?
方法一:名字堆棧的方法,需要切換渲染模式,操作命名堆棧,計算揀選矩陣,檢查選中記錄。當要渲染的數據量特別大或渲染的對象眾多時,顯然是不可取的。
?
方法二:glReadPixel方法,讀深度值的方法,這種方法比前面一種方法在某些時候稍微好用些,但有一個致命的限制,你鼠標選擇的時候,必須選擇到繪有實體的地方,否則就得不到正確的深度值。例如你渲染一個三維地形圖,地形以Tin的方式渲染,如果你想選擇某個頂點,但鼠標落在空白區,你就無法得到正確的深度值,得不到正確的深度值,自然沒法根據gluUnproject函數反算到真實的地形坐標點,而實際應用中應該是即使你沒完全落在該頂點上,也應該可以根據一個緩沖,在所有緩沖區內部的點集中選擇一個距離光標最近的點作為你選擇的點。
本文介紹一種方法——射線選擇,這種方法也是游戲界和三維地形編程普遍采用的選擇方法。
?
首先介紹一個二維三維坐標轉換函數:?gluUnProject()
此函數的具體用途是將一個OpenGL視區內的二維點轉換為與其對應的場景中的三維坐標。
轉換過程如下圖所示(由點P在窗口中的XY坐標得到其在三維空間中的世界坐標):
?這個函數在glu.h中的原型定義如下:
?
?
代碼 int?APIENTRY?gluUnProject?(????GLdouble???????winx,?
????GLdouble???????winy,?
????GLdouble???????winz,?
????const?GLdouble?modelMatrix[16],?
const?GLdouble?projMatrix[16],?
const?GLint????viewport[4],?
????GLdouble???????*objx,?
????GLdouble???????*objy,?
????GLdouble???????*objz);
?
?
其中前三個值表示窗口坐標,中間三個分別為模型視圖矩陣(Model/View Matrix),投影矩陣(Projection Matrix)和視區(ViewPort),最后三個為輸出的世界坐標值。
第二步,首先獲得視圖矩陣,投影矩陣,視區三個數組值。
?
代碼 ?GLint????viewport[4];??GLdouble?modelview[16];?
?GLdouble?projection[16];?
?
?glGetIntegerv(GL_VIEWPORT,?viewport);?//?得到的是最后一個設置視口的參數
?glGetDoublev(GL_MODELVIEW_MATRIX,?modelview);?
?glGetDoublev(GL_PROJECTION_MATRIX,?projection);?
?
獲取這三個變量的代碼,應該放在繪制發生前,三個矩陣定以后。否則glPopMatrix之類的函數,可能導致你無法得到真正的投影矩陣和視圖矩陣。
第三步,獲取射線。因為兩點確定一條線,所以,先通過計算視圖最近點和最遠點,得到該射線。
?
代碼 ?winX?=?point.x;??winY?=?screenHeight?-?point.y;?
//獲取像素對應的前裁剪面的點坐標
?bool?bResult?=?gluUnProject(winX,?winY,?0.0,?modelview,?projection,?viewport,?&posX,?&posY,?&posZ);?
?FPoint3?nearPoint;
?nearPoint.x?=?posX;?nearPoint.y?=?posY;?nearPoint.z?=?posZ;
?//獲取像素對應的后裁剪面的點坐標
?bResult?=?gluUnProject(winX,?winY,?1.0,?modelview,?projection,?viewport,?&posX,?&posY,?&posZ);?
?FPoint3?farPoint;
?farPoint.x?=?posX;?farPoint.y?=?posY;?farPoint.z?=?posZ;
?
?
?
第四步,計算待選擇目標跟該的關系,將與射線距離最近的對象,作為選擇對象。
?
第五步,本文繪制了分布在不同三維空間的5個點,用鼠標右鍵,可以進行點的選擇,如果選中,點會變成黃色,鼠標左鍵可以隨意對這些點進行旋轉等。
程序源代碼
?
?
轉載于:https://www.cnblogs.com/yanhuiw/archive/2010/08/26/1809489.html
總結
以上是生活随笔為你收集整理的OpenGL环境下的射线选择的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cisco路由器交换机安全配置
- 下一篇: 【读书笔记】建造者模式代码完成与大家分享