write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
提要
在前文(系列文章(7),以下簡(jiǎn)稱XO7,系列其他文章類似)中的照相機(jī)比喻中提到了4種3D變換,如下:
1.確定照相機(jī)的位置的過(guò)程對(duì)應(yīng)于“視圖變換”(Viewing Transformations)
2.確定物體位置的過(guò)程對(duì)應(yīng)于“模型變換”(Modeling Transformations)
3.確定照相機(jī)放大倍數(shù)的過(guò)程對(duì)應(yīng)于“投影變換”(Projection Transformations)
4.確定照片大小的過(guò)程對(duì)應(yīng)于“視口變換”(Viewport Transformations)
XO7中我們講的是第一種變換視圖變換,即改變觀察者本身的位置,視角等的變換效果,XO8中講的是第二種變換模型變換,XO9中講的是投影變換,本文開(kāi)始講解最后一個(gè)變換,視口變換。
視口變換
此變換應(yīng)該算是4種變換中最簡(jiǎn)單的了,在照相機(jī)比喻中我說(shuō)他是確認(rèn)照片大小,在實(shí)際中,確認(rèn)的是繪制的區(qū)域,當(dāng)然,我們以前沒(méi)有設(shè)定視口變換前,默認(rèn)是占據(jù)整個(gè)窗口的客戶區(qū)的。只有一個(gè)關(guān)鍵函數(shù)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.
無(wú)論前面進(jìn)行了多少處理,最終的圖像將映射到這個(gè)矩形中,默認(rèn)情況時(shí)占據(jù)整個(gè)窗口的客戶區(qū),在前面的所有例子中,(七巧板的例子除外)我們沒(méi)有接觸到視口變換,那么默認(rèn)就是窗口創(chuàng)建那一瞬間的大小,我們可以嘗試改變窗口大小,發(fā)現(xiàn)事實(shí)上圖形沒(méi)有變大,并且,位置也不再居中了,這個(gè)時(shí)候我們就需要進(jìn)行視口變換,調(diào)整視口。這里,因?yàn)橐郧坝衅咔砂宓睦恿?,也有原?lái)沒(méi)有使用的例子,我就不提供新的此用途的例子了,僅僅看兩個(gè)例子的區(qū)別。
未在窗口改變時(shí)重新設(shè)定視口的情況:
正常情況:
窗口縮小時(shí):圖像偏移了。
窗口放大時(shí):圖像不居中。
看七巧板中的例子:
因?yàn)橛幸韵麓a:
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的作用,此時(shí),窗口大小改變時(shí),會(huì)重新設(shè)定視口,這樣,圖形將會(huì)隨著窗口大小改變而改變(這是大部分情況下我們需要的)
正常情況下:
窗口縮?。簣D形還是居中,因?yàn)榭v橫比的改變,導(dǎo)致圖形縱橫比也改變了。
窗口放大時(shí):圖形還是居中,因?yàn)榭v橫比的改變,導(dǎo)致圖形縱橫比也改變了。
上述七巧板的例子中,很好的演示了glViewport的作用,源代碼在以前就已經(jīng)提供了,這里不再說(shuō)了。但是,我們會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,就是窗口縱橫比改變的時(shí)候,圖形實(shí)際也改變了縱橫比導(dǎo)致變形了,這樣不太符合大部分情況下我們的想法,我們可以通過(guò)控制窗口的縱橫比來(lái)控制這一點(diǎn),(大部分情況下)或者直接通過(guò)控制glViewport參數(shù)的縱橫比也可以達(dá)到保證圖像不扭曲的目的。(但是圖形可能移位)
屏幕分割
玩過(guò)真三國(guó)無(wú)雙系列的玩家們不知道在同一臺(tái)機(jī)器上與戰(zhàn)友們?cè)⊙獖^斗過(guò)沒(méi)有,我是有過(guò),顯示時(shí),一個(gè)玩家在上面,一個(gè)在下面,在同一臺(tái)機(jī)器上不需要通過(guò)網(wǎng)絡(luò)就能享受聯(lián)機(jī)的樂(lè)趣,的確很有意思,事實(shí)上,我們通過(guò)視口變換連續(xù)繪制圖形兩次就能達(dá)到這樣的效果(我不知道真三國(guó)是否也是通過(guò)這樣的技術(shù)實(shí)現(xiàn)的),比如上述的七巧板的例子吧,我們想在屏幕上繪制4次,讓四個(gè)人同時(shí)玩,進(jìn)行對(duì)戰(zhàn),那么我們就可以這樣做:
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這樣設(shè)計(jì)的好處,本身圖形的繪制很簡(jiǎn)單,在原點(diǎn)附近繪制一個(gè)標(biāo)準(zhǔn)的圖形而已,一種又一種變換后,卻可以產(chǎn)生于原來(lái)圖形千差萬(wàn)別的圖形,這一點(diǎn)有點(diǎn)像設(shè)計(jì)模式中的decorator模式.
為節(jié)省篇幅僅貼出關(guān)鍵片段,完整源代碼見(jiàn)我博客源代碼的2009-10-29/JTFourTangram 目錄,獲取方式見(jiàn)文章最后關(guān)于獲取博客完整源代碼的說(shuō)明。
呵呵,相當(dāng)happy吧,同一臺(tái)機(jī)子,4個(gè)人同時(shí)玩七巧板,(事實(shí)上,什么游戲都可以借鑒),什么?就一個(gè)鼠標(biāo)沒(méi)有辦法操作?暈?zāi)模悴粫?huì)插四個(gè)鼠標(biāo)?插四個(gè)鼠標(biāo)也沒(méi)有用?呵呵,推薦你看看我以前寫的關(guān)于多鼠標(biāo)的東西,4個(gè)人用4個(gè)鼠標(biāo)同時(shí)玩,不是什么不可能的^^以前魔獸好像有個(gè)4國(guó)戰(zhàn)爭(zhēng)的游戲地圖很流行,要是額外設(shè)計(jì),我們可以在同一臺(tái)機(jī)器上玩^^發(fā)揮大家的創(chuàng)意吧。
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊(cè)
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機(jī)械工業(yè)出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關(guān)的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個(gè)面向?qū)ο蟮目蚣?,作為演示程序?lái)說(shuō),這樣的框架非常合適。也有 中文版 ,各取所需吧。
4. 《OpenGL入門學(xué)習(xí)》 ,eastcowboy著,這是我在網(wǎng)上找到的一個(gè)比較好的教程,較為完善,而且非常通俗。這是第一篇的地址: http://bbs.pfan.cn/post-184355.html
本OpenGL系列其他文章
1. 《 Win32 OpenGL 編程(1)Win32下的OpenGL編程必須步驟 》
2. 《 Win32 OpenGL編程(2) 尋找缺失的OpenGL函數(shù) 》
3. 《 Win32 OpenGL編程(3) 基本圖元(點(diǎn),直線,多邊形)的繪制 》
4. 《 Win32 OpenGL編程(4) 2D圖形基礎(chǔ)(顏色及坐標(biāo)體系進(jìn)階知識(shí)) 》
5. 《 Win32 OpenGL編程(5)頂點(diǎn)數(shù)組詳細(xì)介紹 》
6.《 Win32 OpenGL編程(6) 踏入3D世界 》
7.《 Win32 OpenGL編程(7) 3D視圖變換——真3D的關(guān)鍵 》
8.《 Win32 OpenGL編程(8) 3D模型變換及其組合應(yīng)用 》
9.《 Win32 OpenGL編程(9) 投影變換 》
應(yīng)用舉例:《 Win32 OpenGL編程系列 2D例子 -- 七巧板圖形繪制 》
完整源代碼獲取說(shuō)明
由于篇幅限制,本文一般僅貼出代碼的主要關(guān)心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發(fā)表的日期分目錄存放,請(qǐng)直接使用Mercurial克隆下庫(kù):
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見(jiàn)《 分布式的,新一代版本控制系統(tǒng)Mercurial的介紹及簡(jiǎn)要入門 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創(chuàng)文章作者保留版權(quán) 轉(zhuǎn)載請(qǐng)注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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