摘要:分析openGL三維圖形顯示流程,討論其坐標變換過程,推導了openGL坐標與Windows屏幕坐標的轉換關系,給出了在MFC下實現openGL圖形編程的方法。
關鍵詞:openGL;幾何變換;坐標轉換
中圖分類號:TP391文獻標識碼:A文章編號:1009-3044(2008)34-1749-03
The Research of OpenGL Geometric Transformation and Conversion of the Windows Screen Coordinates
WENG Wei1,HUANG Cui-lan1,CAI Jian-li2
(1.Department of Computer Science and Technology, Xiamen University of Technology, Xiamen 361024, China; 2. Department of Automation, Xiamen University, Xiamen 361005, China)
Abstract: By analysing the processes of openGL 3D graphics and discussng it's coordinate alternation process, the thises derives the transformation relationship between openGL coordinate and the Windows screen coordinate. Meanwhile it gives the openGL graphical programming approach under the platform of MFC.
Key words: openGL;geometric transform;coordinate transformations
1 引言
openGL(open graphics library,開放性圖形庫)是以SGI的GL三維圖形庫為基礎制定的一個開放式三維圖形庫,目前得到了許多軟硬件廠商的支持,是世界上最流行的圖形API之一,已經成為一個工業標準。openGL獨立于硬件設備,窗口系統和操作系統,可移植性高,主要有繪制模型、幾何變換、光照處理、紋理映射、圖像操作、動畫等功能[1],已經在軍事、航天、醫學、虛擬現實等領域得到了廣泛的應用[2]。
利用openGL進行三維圖形繪制時,世界坐標系的三維物體位置坐標信息經過幾何變換、投影變換、裁剪變換和視口變換這幾個空間坐標變換過程變為屏幕坐標系的坐標。論文[3]分析了openGL常見坐標使用中的問題;論文[4]討論了坐標變換相關的openGL API,但沒有涉及幾何變換的具體公式,亦沒有研究openGL坐標和屏幕坐標的轉換問題,不便于進行交互圖形設計;論文[5]討論了正投影和透視投影下openGL坐標和屏幕坐標的轉換關系,但設定了判斷條件,不具有一致性。
本文首先在世界坐標系下討論了openGL的幾何變換過程,然后推導了openGL坐標與Windows屏幕坐標的轉換關系,最后給出了在MFC下實現openGL圖形編程的方法。
2 openGL三維圖形顯示流程
繪制三維圖形是一項復雜的任務,對于一個特定的圖形,光照、材質、紋理等因素都會影響它的繪制,openGL采用狀態機模型來控制這些非位置因素[6],由一系列的點所組成的圖元受狀態機控制以便形成真實感圖形。openGL要將現實三維圖形顯示在二維屏幕上,關鍵是一系列的幾何變換,包括平移、旋轉、縮放、投影、裁剪和視口變換,基本過程如圖1所示[7]。
2.1 三維幾何變換
openGL中的世界坐標系x軸正方向水平向左,y軸正方向水平向上,z軸正方向垂直屏幕向外。三維幾何變換均在世界坐標系中完成,openGL提供了幾個API實現這些變換,相關函數原型如下:
1) 平移
glTranslate{fd}(TYPE x,TYPE y,TYPE z);
x,y,z為x軸、y軸和z軸方向上的平移量。
2) 旋轉
glRotate{fd}(TYPE angle,TYPE x,TYPE y,TYPE z);
angle為旋轉角度,后三個變量與原點的連線構成旋轉軸。
3) 縮放
glScale{fd}(TYPE x,TYPE y,TYPE z)
該函數可以對物體沿x軸、y軸和z軸分別放大或縮小。
三維幾何變換中還有一個視點變換,函數原型如下:
Void gluLookAT(GLdouble ex,GLdouble ey, GLdouble ez, Gldouble cx, Gldouble cy, Gldouble cz, Gldouble ux, Gldouble uy, Gldouble uz)
openGL成像原理與攝像機拍攝類似,這個函數功能就是設定攝像機的位置,點(ex,ey,ez)三個參數指定攝像機位置,點(ex,ey,ez)到點(cx,cy,cz)方向為攝像機拍攝方向,(ux,uy,uz)指定了向上向量的方向,所有參數均相對于世界坐標系,相當與在世界坐標系中建立了一個以攝像機位置為坐標原點的視坐標系,如圖2所示。通常,攝像機置于世界坐標系上的z軸上,拍攝方向為z的負軸,類似于人眼觀察屏幕。
事實上,openGL對頂點坐標位置的一系列變換為矩陣運算。圖形在世界坐標系中進行一系列的平移、旋轉和縮放,然后變換到視坐標系中。這就相當于圖形在世界坐標系中進行平移、旋轉和縮放后,再進行一次世界坐標系的平移和旋轉變換,這個變換的效果與世界坐標系到視坐標系的變換等效就可以了。
2.2 投影變換
投影變換是模仿人類視覺效果的重要手段,離我們遠的物體看起來小,而進的物體看起來大。投影函數如下:
void glFrustum(Gldouble left,Gldouble rihgt,Gldouble bottom,Gldouble top,Gldouble near,Gldouble far)。
如圖3所示,該函數建立透視投影模型,并設定了裁剪范圍(稱為視景體),只有在棱錐體中near和far所截取的棱臺里面的物體才是可視部分,物體位于這個棱臺之外的部分被裁剪掉了。該圖中相機位于坐標系原點,相機所對的方向為z軸負方向,投影面是z=-near所指的平面(near和far只取正值)。投影面中由left、right、bottom和top四個參數所圍成的矩形可以看成是視口變換中的窗口(事實上,openGL中有一系列的標準化變換過程)。設視景體中有點(x,y,z),投影到窗口上對應的點為(xw,yw,near),那么應滿足如下關系式:
■(1)
■(2)
另一類投影為平行投影,這種投影無論物體距離相機多遠投影后物體的大小都不變,雖不是人類視覺效果的模擬,但在實踐中經常使用,其投影函數如下:
void glOrtho(Gldouble left,Gldouble rihgt,Gldouble bottom,Gldouble top,Gldouble near,Gldouble far)。
該函數對應的模型如圖4所示,位于長方體中的物體參與投影運算,長方體之外的部分被裁剪掉,投影面就是z=-near所指的平面。視景體中的點投影到窗口上x坐標與y坐標都不變。
還有其他方法實現投影,但就效果上來說,與這兩類投影類似。
2.3 裁剪變換
在投影變換模型中已經包含了裁剪變換,openGL還可以在定義裁剪平面,該平面將視景體中的物體截成兩部分,平面之上的部分不參與投影,平面之下的部分才參與投影:
Void glClipPlane(Glenm plane,Const Gldouble *equation)
參數plane指定了裁剪面號,equation指向4個系數數組,這4個系數為平面方程Ax+By+Cz+D=0的系數。
2.4 視口變換
最后一步為窗口到視口的變換,視口對于屏幕上的顯示區域,該區域一般充滿整個屏幕,可以由以下函數設定:
glViewport(Glint vx,Glint vy,Glsizei width,Glsizei height)。
窗口變換到視口變換的過程如圖5所示。
根據比例關系,窗口內的點 (xw,yw)映射到視口內的點(xv,yv) 應滿足:
■ (3)
■ (4)
3 openGL與Windows坐標轉換
設視景體中的點(x,y,z)經過透視投影到窗體上的點為(xw,yw,near),繼而點(xw,yw,near) 對應到視口上的點為(xv,yv,0),那么根據(1)和(3)有: ■(5)
據(2)和(4)有:
■(6)
一般情況下,Windows屏幕坐標左上角為坐標原點,與圖2中視口坐標原點在左下角不一致;另外,視口也不一定充滿整個屏幕,為了一般化公式,在進行一次Windows屏幕坐標到視口坐標的轉換,如圖6所示。
圖6中點(point x,point y) 為Windows屏幕坐標,為了轉換為視口坐標,需要知道Windows窗口的寬度和高度。Windows窗口坐標有很多中單位,一般采用像素坐標,其寬度和高度可用Windows API得知,設保存在結構體m_rect 中, m_rect.width保存Windows屏幕寬度,m_rect.height 保存Windows高度。那么,對應的視口坐標為:
xv=point x (7)
yv=retc.bottom-point y (8)
將(7)式代入(5)式中,有:
■ (9)
將(8)式代入(6)式,有:
■(10)
式(9)和(10)即是Windows屏幕坐標(point x,point y)到視景體中坐標(x,y)的轉換公式。若是采用平行投影,此時視景體中的點投影到窗口上x坐標和y坐標都沒有變,直接根據式(3)和(4),有:
■(11)
■(12)
在Windows編程中,屏幕上任何一點的坐標可以方便地用鼠標事件等方法獲得。該公式能夠通過獲得屏幕坐標逆向算出視景體中的坐標,在交換式圖形圖像編程中有廣泛的應用。
4 基于MFC的實現
MFC(Microsoft Foundation Class)提供了完善的基礎類庫,其框架下的消息相應機制和多態性給程序設計帶來了極大的方便。openGL是一個與平臺無關的三維圖形接口,采用客戶/服務器機制,服務器解釋繪圖命令。那么像素格式管理和渲染環境管理必須通過由其他語言和平臺來設置。oepenGL圖形庫被封裝在一個動態鏈接庫OpenGL32.DLL中,客戶應用程序調用的openGL函數均在此動態鏈接庫中處理,然后傳給服務器WINSRV.DLL,處理后再傳給Win32的設備驅動接口,這樣視頻顯示驅動就能處理顯示了。openGL采用渲染描述表(Render Context)的繪圖方式,與Windows的GDI繪圖方式不同。一種實現方式如下:
1) 加入openGL頭文件;設置全局變量。
2) 在視圖類的PreCreateWindow方法中設置窗口類型風格支持openGL繪圖:cs.style=WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS。
3) 在視圖類的OnCreate方法中設置像素格式,明確繪制風格、顏色模式、顏色深度等重要信息;設置openGL操作所必須的渲染描述表RC與DC的關聯;還可以設置投影變換和視口變換。
4) 改寫OnSize方法。該方法在視圖尺寸發生變化的時候激發,此時要通知openGL進行改變圖形大小等操作,主要是設置glViewport函數。
5) 改造OnDraw函數。在這個函數中完成每次的屏幕繪制,包括三維幾何變換和顏色、光照和紋理信息的處理。
6) 若要獲取鼠標的Windows坐標,進行交互式繪圖,可以改寫OnLButtonDown函數,將鼠標位置參數轉換為視景體中的坐標位置,然后調用OnDraw函數繪制。
7) 在OnDestroy函數中釋放渲染描述表RC等資源。
5 結束語
本文重坐標變換的角度探討了openGL繪制三維圖形的過程,推導了Windows坐標和openGL坐標相互轉換關系,并提供了一種MFC繪制openGL圖形的方法。這些方法在筆者進行的人臉建模中得到了應用,方便了坐標拾取,實現了鼠標點選和微調特征點。總之,本文提出的方法提供了openGL坐標反饋機制,拓寬了openGL繪圖應用,方便了交互圖形編程。
參考文獻:
[1] 楊欽,徐永安,瞿紅英.計算機圖形學[M].北京:清華大學出版社,2005.
[2] 僧德文,李仲學,李春明,等.基于openGL的真實感圖形繪制技術及應用[J].計算機應用研究,2005(3):173-175.
[3] 林夏菲,陳磊,熊輝.openGL中關于坐標使用常見問題的分析[J].電腦知識與技術,2008,2(1):130-131,137.
[4] 高美真,黃嬌青.openGL中的圖形變換[J].焦作師范高等專科學校學報,2006,22(2):51-53.
[5] 蒲瑋.openGL與Windows坐標轉換技術的研究[J].電腦開發與應用,2008,21(1):8-10.
[6] Richard S W,Jr Benjamin L.OpenGL超級寶典[M].3版.徐波,譯.北京:人民郵電出版社,2005.
[7] 徐明亮,盧紅星,王琬.openGL游戲編程[M].北京:機械工業出版社,2008.