write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
提要
在前文(系列文章(7),以下簡稱XO7,系列其他文章類似)中的照相機比喻中提到了4種3D變換,如下:
1.確定照相機的位置的過程對應于“視圖變換”(Viewing Transformations)
2.確定物體位置的過程對應于“模型變換”(Modeling Transformations)
3.確定照相機放大倍數的過程對應于“投影變換”(Projection Transformations)
4.確定照片大小的過程對應于“視口變換”(Viewport Transformations)
XO7中我們講的是第一種變換視圖變換,即改變觀察者本身的位置,視角等的變換效果,XO8中講的是第二種變換模型變換,XO9中講的是投影變換,本文開始講解最后一個變換,視口變換。
視口變換
此變換應該算是4種變換中最簡單的了,在照相機比喻中我說他是確認照片大小,在實際中,確認的是繪制的區域,當然,我們以前沒有設定視口變換前,默認是占據整個窗口的客戶區的。只有一個關鍵函數glViewport,而且較易理解:
glViewport — set the viewport
C Specification
void glViewport( GLint x,
GLint y,
GLsizei width,
GLsizei height);
Parametersx, y
Specify the lower left corner of the viewport rectangle,
in pixels. The initial value is (0,0).
width, heightSpecify the width and height
of the viewport.
When a GL context is first attached to a window,
width and height are set to the dimensions of that
window.
無論前面進行了多少處理,最終的圖像將映射到這個矩形中,默認情況時占據整個窗口的客戶區,在前面的所有例子中,(七巧板的例子除外)我們沒有接觸到視口變換,那么默認就是窗口創建那一瞬間的大小,我們可以嘗試改變窗口大小,發現事實上圖形沒有變大,并且,位置也不再居中了,這個時候我們就需要進行視口變換,調整視口。這里,因為以前有七巧板的例子了,也有原來沒有使用的例子,我就不提供新的此用途的例子了,僅僅看兩個例子的區別。
未在窗口改變時重新設定視口的情況:
正常情況:
窗口縮小時:圖像偏移了。
窗口放大時:圖像不居中。
看七巧板中的例子:
因為有以下代碼:
void ReShape ( unsigned auWidth , unsigned auHeight ) { glViewport (0, 0, auWidth , auHeight ); }
// FUNCTIONS ////////////////////////////////////////////// LRESULT CALLBACK WindowProc ( HWND hwnd , UINT msg , WPARAM wparam , LPARAM lparam ) { // this is the main message handler of the system PAINTSTRUCT ps ; // used in WM_PAINT HDC hdc ; // handle to a device context // what is the message switch ( msg ) { case WM_CREATE : { // do initialization stuff here // return success return (0); } break ; case WM_PAINT : { // simply validate the window hdc = BeginPaint ( hwnd ,& ps ); // end painting EndPaint ( hwnd ,& ps ); // return success return (0); } break ; case WM_DESTROY : { // kill the application, this sends a WM_QUIT message PostQuitMessage (0); // return success return (0); } break ; case WM_SIZE : { ReShape ( LOWORD ( lparam ), HIWORD ( lparam )); } default : break ; } // end switch // process any messages that we didn't take care of return ( DefWindowProc ( hwnd , msg , wparam , lparam )); } // end WinProc
注意reshape的作用,此時,窗口大小改變時,會重新設定視口,這樣,圖形將會隨著窗口大小改變而改變(這是大部分情況下我們需要的)
正常情況下:
窗口縮?。簣D形還是居中,因為縱橫比的改變,導致圖形縱橫比也改變了。
窗口放大時:圖形還是居中,因為縱橫比的改變,導致圖形縱橫比也改變了。
上述七巧板的例子中,很好的演示了glViewport的作用,源代碼在以前就已經提供了,這里不再說了。但是,我們會發現一個問題,就是窗口縱橫比改變的時候,圖形實際也改變了縱橫比導致變形了,這樣不太符合大部分情況下我們的想法,我們可以通過控制窗口的縱橫比來控制這一點,(大部分情況下)或者直接通過控制glViewport參數的縱橫比也可以達到保證圖像不扭曲的目的。(但是圖形可能移位)
屏幕分割
玩過真三國無雙系列的玩家們不知道在同一臺機器上與戰友們浴血奮斗過沒有,我是有過,顯示時,一個玩家在上面,一個在下面,在同一臺機器上不需要通過網絡就能享受聯機的樂趣,的確很有意思,事實上,我們通過視口變換連續繪制圖形兩次就能達到這樣的效果(我不知道真三國是否也是通過這樣的技術實現的),比如上述的七巧板的例子吧,我們想在屏幕上繪制4次,讓四個人同時玩,進行對戰,那么我們就可以這樣做:
void ReShape ( unsigned auWidth , unsigned auHeight ) { WindowWidth = auWidth ; WindowHeight = auHeight ; } // All Scene Show code void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // left bottom glViewport (0, 0, WindowWidth /2, WindowHeight /2); gTriBTop . Draw (); gTriBRight . Draw (); gTriSLeft . Draw (); gRectangle . Draw (); gTriSMid . Draw (); gTriMLeft . Draw (); gParal . Draw (); // right bottom glViewport ( WindowWidth /2, 0, WindowWidth /2, WindowHeight /2); gTriBTop . Draw (); gTriBRight . Draw (); gTriSLeft . Draw (); gRectangle . Draw (); gTriSMid . Draw (); gTriMLeft . Draw (); gParal . Draw (); // left top glViewport (0 , WindowHeight /2, WindowWidth /2, WindowHeight /2); gTriBTop . Draw (); gTriBRight . Draw (); gTriSLeft . Draw (); gRectangle . Draw (); gTriSMid . Draw (); gTriMLeft . Draw (); gParal . Draw (); // right top glViewport ( WindowWidth /2 , WindowHeight /2, WindowWidth /2, WindowHeight /2); gTriBTop . Draw (); gTriBRight . Draw (); gTriSLeft . Draw (); gRectangle . Draw (); gTriSMid . Draw (); gTriMLeft . Draw (); gParal . Draw (); glFlush (); }
顯示效果:
注意上述代碼中,我們的具體的顯示代碼只有一份,顯示代碼中并不知道自己繪制了幾份,繪制在什么地方,這也就是OpenGL這樣設計的好處,本身圖形的繪制很簡單,在原點附近繪制一個標準的圖形而已,一種又一種變換后,卻可以產生于原來圖形千差萬別的圖形,這一點有點像設計模式中的decorator模式.
為節省篇幅僅貼出關鍵片段,完整源代碼見我博客源代碼的2009-10-29/JTFourTangram 目錄,獲取方式見文章最后關于獲取博客完整源代碼的說明。
呵呵,相當happy吧,同一臺機子,4個人同時玩七巧板,(事實上,什么游戲都可以借鑒),什么?就一個鼠標沒有辦法操作?暈哪,你不會插四個鼠標?插四個鼠標也沒有用?呵呵,推薦你看看我以前寫的關于多鼠標的東西,4個人用4個鼠標同時玩,不是什么不可能的^^以前魔獸好像有個4國戰爭的游戲地圖很流行,要是額外設計,我們可以在同一臺機器上玩^^發揮大家的創意吧。
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機械工業出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個面向對象的框架,作為演示程序來說,這樣的框架非常合適。也有 中文版 ,各取所需吧。
4. 《OpenGL入門學習》 ,eastcowboy著,這是我在網上找到的一個比較好的教程,較為完善,而且非常通俗。這是第一篇的地址: http://bbs.pfan.cn/post-184355.html
本OpenGL系列其他文章
1. 《 Win32 OpenGL 編程(1)Win32下的OpenGL編程必須步驟 》
2. 《 Win32 OpenGL編程(2) 尋找缺失的OpenGL函數 》
3. 《 Win32 OpenGL編程(3) 基本圖元(點,直線,多邊形)的繪制 》
4. 《 Win32 OpenGL編程(4) 2D圖形基礎(顏色及坐標體系進階知識) 》
5. 《 Win32 OpenGL編程(5)頂點數組詳細介紹 》
6.《 Win32 OpenGL編程(6) 踏入3D世界 》
7.《 Win32 OpenGL編程(7) 3D視圖變換——真3D的關鍵 》
8.《 Win32 OpenGL編程(8) 3D模型變換及其組合應用 》
9.《 Win32 OpenGL編程(9) 投影變換 》
應用舉例:《 Win32 OpenGL編程系列 2D例子 -- 七巧板圖形繪制 》
完整源代碼獲取說明
由于篇幅限制,本文一般僅貼出代碼的主要關心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發表的日期分目錄存放,請直接使用Mercurial克隆下庫:
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見《 分布式的,新一代版本控制系統Mercurial的介紹及簡要入門 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創文章作者保留版權 轉載請注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
