高明向 陳定方 楊艷芳
(武漢理工大學(xué)理學(xué)院1) 武漢 430063) (武漢理工大學(xué)智能制造與控制研究所2) 武漢 430063)
在開發(fā)和用戶交互的三維圖形處理程序[1-2]時,常常需要使用鼠標(biāo)控制模型的平移、旋轉(zhuǎn)和縮放等模型變換操作.模型變換的具體形式是多種多樣的[3],許多變換結(jié)果可以通過幾個基本變換的連續(xù)作用而得到.如果將這些基本變換形式以菜單或者工具欄命令的形式進(jìn)行定義[4],程序的菜單/工具欄將是非常臃腫的.如果以快捷鍵的形式進(jìn)行定義,將會嚴(yán)重侵占應(yīng)用程序的快捷鍵資源,導(dǎo)致定義程序使用的其它快捷鍵時出現(xiàn)困難,也不便于用戶操作.將模型變換命令進(jìn)行可視化表示,建立模型變換組件,并使用鼠標(biāo)對這些命令進(jìn)行選擇與執(zhí)行,既方便用戶操作又可節(jié)約應(yīng)用程序資源.本文在基于Open GL的建模環(huán)境中實(shí)現(xiàn)了這項(xiàng)技術(shù).
作為一種快速、高質(zhì)量的3D圖形軟件接口,Open GL提供了一種進(jìn)行交互式3D應(yīng)用的選擇操作.通過Open GL的選擇機(jī)制[5],用戶能夠知道,在窗口中的某個特定區(qū)域中繪制的是哪個物體,用戶用鼠標(biāo)選取了哪個物體等.
在使用Open GL的選擇機(jī)制時,首先將景物繪制到幀緩存中,然后進(jìn)入選擇模式并重新繪制景物.進(jìn)入選擇模式后,幀緩存的內(nèi)容將不發(fā)生變化.在退出選擇模式時,Open GL返回一個與視圖體相交的圖元系列.系列中的每個圖元都會產(chǎn)生一個命中信息,并以圖元名稱及選中記錄數(shù)組的形式返回.在選擇模式中,當(dāng)發(fā)送繪制圖元命令時,要為圖元命名.這樣,在返回名稱列表時,可以用它來確定用戶選中的圖元[6].
基于這種選擇機(jī)制,可以先將基本的模型變換命令用一定的圖元進(jìn)行可視化表示,從而創(chuàng)建模型變換組件,然后使用鼠標(biāo)對這些圖元進(jìn)行選取,選取了特定的圖元相當(dāng)于選擇了相應(yīng)的模型變換命令.下面介紹實(shí)現(xiàn)這種模型變換組件的關(guān)鍵技術(shù).
3D環(huán)境中平移變換的基本操作有3種:分別沿著x,y和z 3個坐標(biāo)軸方向的平移.為增強(qiáng)平移變換操作的便利性,可再增加3種變換形式:分別在xoy,yoz和xoz平面上的平移操作.
如圖1所示,平移變換命令可使用三維直角坐標(biāo)系統(tǒng)進(jìn)行可視化表示:3條共點(diǎn)且相互垂直的有向線段構(gòu)成該變換系統(tǒng)的坐標(biāo)軸,分別表示沿著x,y和z方向的平移命令,任意兩個軸所在的平面上各繪制一個4邊形,分別表示在xoy,yoz和xoz平面上的平移命令.為描述方便,把這些軸或者四邊形稱為變換系統(tǒng)的部件.
圖1 平移變換組件
用鼠標(biāo)選取這些部件的過程可分為兩個階段:當(dāng)鼠標(biāo)處于一個部件的上方時,稱為命中(hit)部件,此時按下鼠標(biāo)按鍵,部件才被選中(selected).在繪制變換系統(tǒng)時,給每個部件分別命名,當(dāng)一個部件被選中時,由部件的名稱即可解析出相應(yīng)的平移變換命令,并通知應(yīng)用程序,準(zhǔn)備執(zhí)行.當(dāng)按下并移動鼠標(biāo)時,開始執(zhí)行這個命令,進(jìn)行相應(yīng)的平移變換操作.
用鼠標(biāo)平移物體的過程中,一般要求物體總是處于鼠標(biāo)下方,與鼠標(biāo)同步移動.實(shí)現(xiàn)這種要求的基本方法是,移動鼠標(biāo)過程中,實(shí)時計(jì)算鼠標(biāo)點(diǎn)的窗口坐標(biāo)對應(yīng)的三維空間坐標(biāo),然后將物體的位置坐標(biāo)用它代替即可.
下面的算法給出一種將鼠標(biāo)點(diǎn)的窗口坐標(biāo)映射到三維空間坐標(biāo)的方法.這種方法以被選中物體的位置為參考,先求出該點(diǎn)的屏幕深度,然后以這個屏幕深度為參考,把鼠標(biāo)的窗口坐標(biāo)映射為三維空間坐標(biāo):
void Win Pos To World(int pos X,int pos Y,float obj-Position[],floatworld Pos[])
{
double win Coordinate[]= {0,0,0};
//將物體位置坐標(biāo)映射為窗口坐標(biāo),獲取該位置處對應(yīng)的屏幕深度
World ToScreen(obj Position,win Coordinate);//將鼠標(biāo)的窗口坐標(biāo)映射為三維空間坐標(biāo)
Screen To World(pos X,pos Y,win Coordinate[2],world Pos);
}
函數(shù) Win Pos To World(*)有4個參數(shù),pos X,pos Y是鼠標(biāo)點(diǎn)的窗口坐標(biāo);obj Position[]是被選中物體的三維空間位置,當(dāng)物體被選中時,使變換系統(tǒng)的原點(diǎn)移動到這個位置,因此物體的位置就是變換系統(tǒng)(局部坐標(biāo)系)的原點(diǎn)對應(yīng)的三維空間坐標(biāo)(世界坐標(biāo)系);worl d Pos[]是鼠標(biāo)點(diǎn)對應(yīng)的三維空間坐標(biāo).Worl d To Screen(*)方法封裝了Open GL實(shí)用庫中的gl u Project(*)函數(shù),作用是把給定的三維空間坐標(biāo)映射為窗口坐標(biāo),win Coor dinate[2]是該點(diǎn)對應(yīng)的屏幕深度值.Screen To Worl d(*)方法封裝了gl u Un Pr oject(*)函數(shù),作用是把窗口坐標(biāo)映射為由win Coordinate[2]指定的屏幕深度處三維空間坐標(biāo).
使用這種方法移動物體會存在的這樣的問題:當(dāng)選定了一種變換命令并開始移動物體時,變換系統(tǒng)的原點(diǎn)會突然跳到鼠標(biāo)的下方,而且鼠標(biāo)與變換系統(tǒng)原點(diǎn)間的屏幕距離越遠(yuǎn),這種跳躍越明顯.原因是,如圖2所示,設(shè)在按下鼠標(biāo)按鍵時,鼠標(biāo)位于P0,這點(diǎn)與變換系統(tǒng)的原點(diǎn)O間總會存在一定的屏幕距離,相應(yīng)于三維空間中,此二點(diǎn)總是存在一定的向量差OP0,而將物體位置坐標(biāo)用鼠標(biāo)坐標(biāo)代替時,并沒有將這個差值考慮進(jìn)去.所以,確定物體平移后的位置時,只要將這個差值考慮進(jìn)去,問題就解決了.
圖2 消除跳躍的方法
縮放組件的實(shí)現(xiàn)方法與平移組件非常相似,實(shí)現(xiàn)的效果見圖4b),不再贅述.
最基本的旋轉(zhuǎn)變換有3種,即分別繞著x,y,z坐標(biāo)軸的旋轉(zhuǎn)變換.下文提及的旋轉(zhuǎn)變換中,旋轉(zhuǎn)角度均可用鼠標(biāo)移動的屏幕距離與窗口寬度、高度的相對大小確定.因而,下文僅說明如何確定旋轉(zhuǎn)軸.
繞著3個坐標(biāo)軸的旋轉(zhuǎn)操作命令,可以用xoy,yoz和xoz平面上的以變換系統(tǒng)原點(diǎn)為圓心的3個圓環(huán)(ring)進(jìn)行可視化表示.當(dāng)鼠標(biāo)選中xoy面上的圓環(huán)時表示執(zhí)行繞著z軸的旋轉(zhuǎn)命令,而選中xoz面上的圓環(huán)時表示執(zhí)行繞著y軸的旋轉(zhuǎn)命令等等.
為了便于判斷哪個部件被命中或者選中,只要對處于命中/選中狀態(tài)的圓環(huán)使用不同的顏色繪制即可.為了看上去更具有立體感,這些圓環(huán)需要由兩部分構(gòu)成:一是靠近視點(diǎn)的部分,用實(shí)線繪制,二是遠(yuǎn)離視點(diǎn)的部分,則用虛線繪制.當(dāng)變換系統(tǒng)處于場景中的不同位置或者視點(diǎn)位置發(fā)生變化時,這2個部分是不斷變化的,因而要動態(tài)更新這兩部分的數(shù)據(jù).更新方法是:將構(gòu)成圓環(huán)的每個點(diǎn)相對于圓心的位置矢量與由物體指向視點(diǎn)的矢量進(jìn)行點(diǎn)乘運(yùn)算,結(jié)果為正值的構(gòu)成靠近視點(diǎn)的部分,反之則構(gòu)成遠(yuǎn)離視點(diǎn)的部分.
繞空間任意軸旋轉(zhuǎn)亦是一種常用的變換方式.這種變換命令可直接使用以變換系統(tǒng)的原點(diǎn)為圓心的填充圓(filled circle)進(jìn)行可視化表示.這個圓與基本變換中使用的圓環(huán)半徑相同.當(dāng)鼠標(biāo)位于填充圓內(nèi),且沒有命中4.1所述的部件時,通過改變填充圓的透明度,通知用戶即將執(zhí)行繞任意軸旋轉(zhuǎn)的命令,按下并移動鼠標(biāo)時就可通知程序執(zhí)行該命令.
至于旋轉(zhuǎn)角度和旋轉(zhuǎn)軸的求解,比較典型的方法是Ne He Open GL編程指南中提供的旋轉(zhuǎn)球法[7].本文提出了一種更為簡單的求解旋轉(zhuǎn)軸的方法.
如圖3所示,設(shè)O點(diǎn)是旋轉(zhuǎn)變換系統(tǒng)(局部坐標(biāo)系統(tǒng))的原點(diǎn),位于物體的位置坐標(biāo)(世界坐標(biāo))處,^n是填充圓面的單位法線向量,其方向由O點(diǎn)指向視點(diǎn)(根據(jù)§4.4的方法,總可以保證圓面與視點(diǎn)正對).設(shè)當(dāng)鼠標(biāo)位于P0點(diǎn)時按下左鍵并移動,某時刻移動到了P1點(diǎn).則此過程的旋轉(zhuǎn)軸用向量r表示,可由下式計(jì)算:
式中:OP0,OP1分別為從O 點(diǎn)到P0,P1點(diǎn)的向量.O點(diǎn)的世界坐標(biāo)是已知的,等于欲進(jìn)行旋轉(zhuǎn)變換物體位置的世界坐標(biāo).^n由視點(diǎn)和O點(diǎn)的世界坐標(biāo)求出.P0點(diǎn)和P1點(diǎn)的世界坐標(biāo)可使用2.3的方法由鼠標(biāo)窗口坐標(biāo)映射到世界坐標(biāo)得到.
圖3 求解任意旋轉(zhuǎn)軸
三維計(jì)算機(jī)圖形學(xué)中,把視點(diǎn)與物體(位置)的連線稱為視線.繞著視線的旋轉(zhuǎn)變換也是較為常用的一種變換形式.這種變換的可視化表示方法較為簡單,可直接使用以變換系統(tǒng)的原點(diǎn)為圓心的圓環(huán)表示,但半徑必須比§4.2填充圓的半徑大.這種變換的旋轉(zhuǎn)軸即為視點(diǎn)的三維空間坐標(biāo)(世界坐標(biāo))與物體的空間坐標(biāo)(變換系統(tǒng)原點(diǎn)對應(yīng)的世界坐標(biāo))的差值構(gòu)成的空間向量.
對于4.2,4.3所使用的填充圓,必須隨著視點(diǎn)或者物體位置的不同對它們的空間方位進(jìn)行調(diào)整,以使其始終正對視點(diǎn),以免出現(xiàn)有時看起來呈正圓形,有時呈橢圓形,有時又呈一條線的情況.調(diào)整方法是:首先,計(jì)算視點(diǎn)與物體(位置)的連線與xoz面的夾角angle XZ以及該連線在xoz面的投影與z軸夾角angle Z.然后,使這些圓面繞著Y軸旋轉(zhuǎn)angle XZ.最后,使它們繞著X軸旋轉(zhuǎn)-angle Z.
本文在Visual C++編程環(huán)境下,將這些變換組件封裝在一起,構(gòu)建CTransfor m類,這就使得這些變換組件能夠很容易地應(yīng)用到圖形或應(yīng)用系統(tǒng)中.只要在程序文件中包含該類的頭文件,并定義一個該類的實(shí)例(指針變量,或者聲明一個CTransfor m類型的普通變量),然后利用類所提供的用戶接口,執(zhí)行必要的命令即可.
CTransfor m類提供了3種用戶接口.一種是變換組件的屬性接口,用于設(shè)置/獲取變換組件的位置、縮放量、旋轉(zhuǎn)軸、當(dāng)前的變換類型及狀態(tài)等.另一種是組件的繪制接口,用根據(jù)當(dāng)前變換的類型及狀態(tài),顯示不同的變換組件.三種變換類型間的切換可以通過菜單或者工具欄實(shí)現(xiàn),僅需要增加三個程序菜單項(xiàng)或工具欄按鈕.第三種是用于獲取3D場景視點(diǎn)信息的接口,該接口主要用于旋轉(zhuǎn)變換,能夠根據(jù)視點(diǎn)的位置自動調(diào)整旋轉(zhuǎn)組件的在場景中的姿態(tài)(參閱4.4).
圖4是三類模型變換組件的實(shí)現(xiàn)效果圖.當(dāng)選中一個物體時,根據(jù)程序的當(dāng)前變換要求顯示相應(yīng)的變換組件,并將該組件定位到被選中的物體上,根據(jù)模型變換的實(shí)際需要,通過鼠標(biāo)選擇相應(yīng)的變換部件,按下并移動鼠標(biāo)時,相應(yīng)的變換命令得以執(zhí)行.這項(xiàng)技術(shù)已經(jīng)用于正在開發(fā)的虛擬物理環(huán)境的軟件平臺及“基于磁各向異性的Galfenol本征非線性模型及其應(yīng)用研究(20090143110005)”的仿真軟件開發(fā)試驗(yàn)中,使得應(yīng)用程序的界面得到很大程度的簡化,同時也使得對場景中模型的控制變得簡單、方便,效果好.
圖4 模型變換組件效果圖
[1]劉鵬程,艾廷華,胡晉山.基于Open GL技術(shù)的隧道仿真系統(tǒng)的研究與開發(fā)[J].計(jì)算機(jī)工程,2008,34(6):240-242.
[2]朱志峰,余德義.利用OPENGL技術(shù)開發(fā)3D飛行仿真應(yīng)用程序[J].計(jì)算機(jī)仿真,2005,21(3):194-196.
[3]王勝全,范燮昌,談士力.Open GL中的坐標(biāo)變換分析[J].機(jī)械與電子,2004(2):65-67.
[4]王亞平,余 柯,羅 堃.在Open GL中一種新的拾取方法及其應(yīng)用[J].工程圖學(xué)學(xué)報(bào),2003(2):60-64.
[5]Woo M,Neider J,Davis T.OPENGL編程權(quán)威指南[M].北京:中國電力出版社,2001.
[6]楊 冬,王 琰,祁 燕.虛擬裝配環(huán)境中基于分層結(jié)構(gòu)三維實(shí)體的拾?。跩].沈陽理工大學(xué)學(xué)報(bào),2007,26(1):17-20.
[7]Terence J.Open GL Tutorials:Lesson 48[CP/OL].[2011-02-26].htt p://nehe.gamedev.net/data/lessons/lesson.asp?lesson=48