青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

doing5552

記錄每日點(diǎn)滴,不枉人生一世

  C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
  73 Posts :: 0 Stories :: 94 Comments :: 0 Trackbacks

公告

常用鏈接

留言簿(24)

我參與的團(tuán)隊(duì)

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 456264
  • 排名 - 49

最新隨筆

最新評論

閱讀排行榜

評論排行榜

亂彈OpenGL中的矩陣變換(上)


在前面的日志(Shadow Volume 陰影錐技術(shù)之探Ⅲ )中,自己稍微提及了NEHE的"3D矩陣求逆"方法之高,并談了談自己的一點(diǎn)拙略理解。呵呵,然后,既然如此,一不做二不休,在本篇中得繼續(xù)亂彈一下下,關(guān)于OpenGL矩陣的理解。因?yàn)槲覍?shí)在不知道會不會在哪兒就把你忽悠+誤導(dǎo)了(但還是期盼你的信任),請看官自重哈哈。
這里有一句,我認(rèn)為,最能夠消解頭腦中的云霧的話:OpenGL中所有的變換,都是在變換坐標(biāo)系。
你還好嗎?你還能看見你眼前書桌上那個(gè)蘋果嗎?你把它向右邊移動10厘米看看?移好了嗎?想一想,假如你眼前就是OpenGL的一個(gè)渲染窗口的話,蘋果是不是往x軸正方向移動了10單位(假設(shè)單位:厘米)?恩,你現(xiàn)在所感受到的真實(shí)告訴你:蘋果確實(shí)不再在原位置,而是向右移了10厘米到了一個(gè)新的位置。我想說的是,當(dāng)你完全邁進(jìn)3D圖形學(xué)殿堂后,請不要再那么輕易相信的眼睛所感受到的真實(shí)——它是真實(shí),但不是真實(shí)的全部。在你剛才一瞬間想象出的OpenGL渲染窗口里,蘋果沒有移動,它一直在那里,一直....而移動的是整個(gè)空間,整個(gè)世界,包括書桌,包括你,包括你的眼睛!
在OpenGL的那個(gè)世界中,最初存在著幾個(gè)重疊的空間。有模型空間,有世界空間,視圖空間,屏幕空間等。每個(gè)空間實(shí)質(zhì)就是一個(gè)坐標(biāo)系(統(tǒng))——坐標(biāo)系統(tǒng)當(dāng)然就有坐標(biāo)軸。在最初的這個(gè)時(shí)刻,也許整個(gè)OpenGL世界也就只有這一套坐標(biāo)軸了:恩,一套。世界永遠(yuǎn)只有一個(gè),但是依附于這個(gè)世界的空間則平行地同時(shí)存在——實(shí)體(例如坐標(biāo)軸,蘋果)唯一,而實(shí)體的表示(各個(gè)空間中對應(yīng)的坐標(biāo)軸,蘋果)則多樣。我是這么理解的,OpenGL世界。
最初的OpenGL世界只有一套看不見的坐標(biāo)軸,然后,用戶說:蘋果!于是世上就有了蘋果。蘋果輕輕地出現(xiàn)在映射著這個(gè)世界的各個(gè)空間中——就在那個(gè)萬物之源的坐標(biāo)原點(diǎn)上。原點(diǎn)與蘋果的“中心”對應(yīng)(當(dāng)然“中心”不一定指蘋果中間,它由上帝...不,用戶在制造這個(gè)蘋果時(shí)決定。確切地說,我們在畫物件(或者直接叫:模型)時(shí)給予這些東西的各個(gè)glVertex3頂點(diǎn)(坐標(biāo)x,y,z),它們的存在必然以位置(0,0,0)為標(biāo)尺——這個(gè)位置就是此物件的“中心”)。就在蘋果出現(xiàn)的此瞬間,模型空間(Model-Coordination,也稱Local-Corrdination)安靜了,此刻的整個(gè)世界的一切如同屏幕截圖般被保存起來,儲存在模型空間——永遠(yuǎn)以當(dāng)前這個(gè)“中心”為原點(diǎn),以當(dāng)前這些坐標(biāo)(x,y,z)為蘋果各頂點(diǎn)的"模型坐標(biāo)系坐標(biāo)"。
 
//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}

當(dāng)然,蘋果出現(xiàn)在模型空間坐標(biāo)系統(tǒng)原點(diǎn),必然也就出現(xiàn)在其他空間坐標(biāo)系統(tǒng)的原點(diǎn),此時(shí)各空間的坐標(biāo)系是重合的,只不過模型空間被固定了,其他空間還沒而已。蘋果怎么移動到別處呢?恩,編程的時(shí)候可以這么問,但當(dāng)你正在了解OpenGL世界的時(shí)候(如現(xiàn)在),這個(gè)問法很不靠譜。你看上面的代碼(glVertex3f(A); glVertex3f(B)....)這里點(diǎn)A,B...不是給定了嗎?就算是變量,在“畫點(diǎn)”的時(shí)刻變量的值也是給定的呀。是的,變的不該是蘋果,而是坐標(biāo)系,準(zhǔn)確地理解,是世界空間(World-Coordination)的那個(gè)坐標(biāo)系要變,在原先與模型空間坐標(biāo)系重合的基礎(chǔ)上變。這個(gè)變的過程,叫模型變換(Model-Translation)。具體來說就是用一個(gè)表示“轉(zhuǎn)動/移動/縮放”的矩陣左乘蘋果的各個(gè)頂點(diǎn)坐標(biāo),得出的結(jié)果(是一些不同的坐標(biāo))作為蘋果對應(yīng)頂點(diǎn)在世界空間坐標(biāo)系中的位置坐標(biāo)。誒?蘋果變了嗎?可以這么說,蘋果的“坐標(biāo)”還是原來那些A.B...但對應(yīng)于世界坐標(biāo)系的“位置”變化了。
這里確實(shí)是很容易迷糊,默念吧:OpenGL中所有的變換,都是在變換坐標(biāo)系。不是蘋果右移了10厘米,而是世界坐標(biāo)系左移了10厘米!假設(shè)蘋果中心最初恰就是出現(xiàn)在模型空間并與模型坐標(biāo)系原點(diǎn)重合,然后考慮以此為初狀態(tài)的世界空間,在用戶做了模型變換(向蘋果中心點(diǎn)所在之坐標(biāo)(0,0,0),左乘一個(gè)表示右移10厘米的模型變換矩陣)后,這個(gè)坐標(biāo)由(0,0,0)變成(10,0,0),相當(dāng)于坐標(biāo)系原來的虛擬坐標(biāo)(10,0,0)變成現(xiàn)在的(0,0,0)。看,坐標(biāo)系(由無限的虛擬坐標(biāo)構(gòu)成)左移10厘米!我想說,這才是模型變換(Model-Translation)的真正所為。與之前一樣,當(dāng)一切變換完成,結(jié)果被截屏存入世界空間。世界空間的動蕩結(jié)束,從此定型。
 
//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換”
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣
 
//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換”
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣

//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
接下來發(fā)生的事情跟之前一樣,只是從模型空間---(模型變換)---》世界空間的關(guān)系,改成世界空間---(視圖變換 View Translation)---》視圖空間的關(guān)系而已。請好好再模擬一次:一模一樣的過程,這次的移動所需要的左乘矩陣(左乘剛才保存的模型轉(zhuǎn)換結(jié)果嘛)由相機(jī)(眼睛,視線)的設(shè)置提供,結(jié)果存入視圖空間而已。
 
//3.用戶創(chuàng)世第3天,說:我是主角! 于是他擁有了第一人稱視覺,結(jié)果存視圖空間
glMatrixMode(GL_VIEW);//表示接下來要作“視圖轉(zhuǎn)換” 
gluLookat(eye,look,up)//也相當(dāng)于一個(gè)平移矩陣 
 
//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間 
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換” 
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣 
 
//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述  
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//3.用戶創(chuàng)世第3天,說:我是主角! 于是他擁有了第一人稱視覺,結(jié)果存視圖空間
glMatrixMode(GL_VIEW);//表示接下來要作“視圖轉(zhuǎn)換”
gluLookat(eye,look,up)//也相當(dāng)于一個(gè)平移矩陣

//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換”
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣

//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
噢,接下來是:視圖空間---(投影變換)---》屏幕空間。投影變換的變換手法與之前的不同,屏幕空間以視圖空間結(jié)果為基礎(chǔ),先用一個(gè)平頭錐體(視景錐)把視線范圍外的空間割了(裁剪),再把投影到一個(gè)可以覆蓋渲染屏幕窗口的矩形上(具體做法是,XYZ除以隱含的齊次坐標(biāo)W,然后舍棄深度Z),保存為屏幕空間——一個(gè)平面,讓用戶所能感悟到這一切不過顯示器屏幕一部分像素的把戲。當(dāng)然,最后的坐標(biāo)還要隱映射為渲染窗口的客戶區(qū)坐標(biāo)(原點(diǎn)在窗口左上角,Y軸下X軸右的平面坐標(biāo)),算是走出了OPENGL世界。
 
//4.用戶創(chuàng)世第4天,說:到顯示屏來吧! 世界便是"平"的了.最后得屏幕空間
glViewport(0,0,width,height);//設(shè)置那個(gè)"視景區(qū)矩形"大小
glMatrixMode(GL_PROJECTION));//表示接下來要作“投影轉(zhuǎn)換” 
gluPerspective(fov,aspect,near,far);//視景體應(yīng)用
 
//3.用戶創(chuàng)世第3天,說:我是主角! 于是他擁有了第一人稱視覺,結(jié)果存視圖空間 
glMatrixMode(GL_VIEW);//表示接下來要作“視圖轉(zhuǎn)換”  
gluLookat(eye,look,up)//也相當(dāng)于一個(gè)平移矩陣  
 
//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間  
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換”  
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣  
 
//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述   
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//4.用戶創(chuàng)世第4天,說:到顯示屏來吧! 世界便是"平"的了.最后得屏幕空間
glViewport(0,0,width,height);//設(shè)置那個(gè)"視景區(qū)矩形"大小
glMatrixMode(GL_PROJECTION));//表示接下來要作“投影轉(zhuǎn)換”
gluPerspective(fov,aspect,near,far);//視景體應(yīng)用

//3.用戶創(chuàng)世第3天,說:我是主角! 于是他擁有了第一人稱視覺,結(jié)果存視圖空間
glMatrixMode(GL_VIEW);//表示接下來要作“視圖轉(zhuǎn)換” 
gluLookat(eye,look,up)//也相當(dāng)于一個(gè)平移矩陣 

//2.用戶創(chuàng)世第2天,說:蘋果右移! 于是世界坐標(biāo)系便左移了,結(jié)果存入世界空間 
glMatrixMode(GL_MODEL);//表示接下來要作“模型轉(zhuǎn)換” 
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣 

//1.用戶創(chuàng)世第1天,說:蘋果! 世上便有了蘋果---蘋果在模型空間(local 空間)被永恒描述  
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}

事實(shí)上OpenGL的glMatrixMode函數(shù)里沒有GL_MODEL和GL_VIEW這兩種設(shè)值。上面提到過,模型變換和視圖變換其實(shí)是同一種處理,而且視圖變換只由相機(jī)控制,有則有,無則默認(rèn)。因此OpenGL直接就用GL_MODELVIEW一起轉(zhuǎn)換了。簡潔是簡潔,但是這樣一來用戶就不知道世界空間里的坐標(biāo)系什么時(shí)候改變了,也難得到物體在世界坐標(biāo)系下的位置坐標(biāo)了(事實(shí)上還是有辦法的,不過搞復(fù)雜了,見以后的博文啦)。
 
glViewport(0,0,width,height);//設(shè)置那個(gè)"視景區(qū)矩形"大小 
 
glMatrixMode(GL_PROJECTION));//表示接下來要作“投影轉(zhuǎn)換”  
glLoadIdentity();
gluPerspective(fov,aspect,near,far);//視景體應(yīng)用 
 
gluLookat(eye,look,up)//控制整個(gè)視景體   
 
glMatrixMode(GL_MODELVIEW);//表示接下來要作“模型視圖轉(zhuǎn)換”  
glLoadIdentity(); 
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣   
 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
........
glViewport(0,0,width,height);//設(shè)置那個(gè)"視景區(qū)矩形"大小

glMatrixMode(GL_PROJECTION));//表示接下來要作“投影轉(zhuǎn)換” 
glLoadIdentity();
gluPerspective(fov,aspect,near,far);//視景體應(yīng)用

gluLookat(eye,look,up)//控制整個(gè)視景體  

glMatrixMode(GL_MODELVIEW);//表示接下來要作“模型視圖轉(zhuǎn)換” 
glLoadIdentity();
glTranslatef(10,0,0);//相當(dāng)于一個(gè)平移矩陣  
 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
........
此外,每次變換不是以之前保存的那個(gè)空間的位置信息為基礎(chǔ)嗎?這要用到glLoadIdentity()函數(shù),初始化當(dāng)前矩陣,為什么?還是看下篇吧:

本文來源于ZwqXin http://www.zwqxin.com/ , 轉(zhuǎn)載請注明
原文地址:http://www.zwqxin.com/archives/opengl/opengl-matrix-what.html


本篇文章承接上文:亂彈OpenGL中的矩陣變換(上) 。上篇中,我嘗試從一種不太成熟的OpenGL世界觀(注意,或許也是3D渲染世界的世界觀)來認(rèn)識這個(gè)OpenGL世界,向自己澄清了一些概念(盡管不夠高清)。這里我想繼續(xù)從矩陣數(shù)學(xué)的角度想一想:究竟模型位置怎么在世界中各個(gè)空間的坐標(biāo)系統(tǒng)中“轉(zhuǎn)換”?——ZwqXin
OpenGL中的坐標(biāo)系是右手坐標(biāo)系,矩陣按列優(yōu)先存儲。這很讓人混亂,因?yàn)榫€代里接觸的都是行優(yōu)先存儲,突然就這么column-major了.....最初還竊認(rèn)為該不該從向量角度讓頭腦清晰,后來看別人文章說這跟向量沒啥關(guān)系,完全是一種規(guī)范:如同右手坐標(biāo)系,只是一種規(guī)范。好吧,列就列啦:
mt0     mt4     mt8     mt12
mt1     mt5     mt9     mt13
mt2     mt6     mt10   mt14
mt3     mt7     mt11   mt15
有點(diǎn)怪是不?當(dāng)然啦,連C語言學(xué)2維數(shù)組時(shí)都是row-major的,OpenGL卻是先一豎下來,再來下一豎(column-major)...(考慮一塊內(nèi)存,第一個(gè)格子存mt0,第二存mt1.....)這就是OpenGL矩陣存儲方式。上篇提到,模型變換(Mode-Translation),視圖變換(View-Translation)乃至投影變換,這些決定了各個(gè)空間之不同的"針對坐標(biāo)系的變換",實(shí)質(zhì)產(chǎn)生出來的是一個(gè)左乘矩陣,這些矩陣就是這樣存儲的。如果你看過任何一本3D圖形學(xué)的入門書前兩章,那你應(yīng)該知道模型變換(在OpenGL中反映為glTranslate,glScale,glRotate)所使用的矩陣。譬如我這里先讓蘋果繞z軸逆轉(zhuǎn)個(gè)角度Θ,再讓它變成原大小的A倍,再右移10單位:(P.S.翻譯成OpenGL世界的語言:在模型空間坐標(biāo)系確定的位置基礎(chǔ)上,讓世界空間坐標(biāo)系繞z軸順轉(zhuǎn)角度Θ,坍縮成原來一半大小,并左移10單位,注意是坍縮后1單位表示的長度跟之前的不一樣了。)
 
A*cosΘ-sinΘ0  10 
sinΘA*cosΘ00
00A*1   0
0001
   X
*     y     =   M * P(point of Apple)
      z
      1
 其中M是變換矩陣,點(diǎn)P(x,y,z,1)是蘋果的其中一個(gè)點(diǎn)的坐標(biāo)(記得嗎?這個(gè)坐標(biāo)是在模型空間確定的并且不變),它是一個(gè)豎向量形式的點(diǎn)。為什么是豎向量呢,因?yàn)镺penGL矩陣的左乘:(4X4)*(4X1)=(4X1)嘛,這是線形代數(shù)知識,(A行數(shù)XA列數(shù))*(B行數(shù)XB列數(shù))中,只有A列數(shù)=B行數(shù),這兩個(gè)矩陣(向量)才可以相乘。那為什么要左乘?因?yàn)镺penGL(點(diǎn))向量是列向量!哈哈,不是忽悠,這根本就是“規(guī)范問題”,譬如D3D就全采取相反的,不多說。最后,思考者應(yīng)該已經(jīng)把上面那個(gè)矩陣跟再上面那個(gè)“模板”對應(yīng)起來了吧(OPENGL在內(nèi)存中把相乘的結(jié)果——這16個(gè)數(shù)按mt0=A*cosΘ, mt1=sinΘ, mt2=0, mt3=0, mt4=-sinΘ, mt5=A*cosΘ, mt6=0......這樣的豎的順序存放)。再譬如我在之前的ShadowVolume Demo中就這樣定義了一個(gè)4X4矩陣類,并這樣定義了一個(gè)矩陣(就是上面的mt嘛)左乘某點(diǎn)向量的方法:
 
class CMatrix16

public:
    float mt[16];
 
   inline CVector4D operator*(CVector4D & vec4) { 
return CVector4D(mt[0] * vec4.x + mt[4] * vec4.y + mt[8] * vec4.z + mt[12] * vec4.w ,
     mt[1] * vec4.x + mt[5] * vec4.y + mt[9] * vec4.z + mt[13] * vec4.w ,
    mt[2] * vec4.x + mt[6] * vec4.y + mt[10]* vec4.z + mt[14] * vec4.w ,
     mt[3] * vec4.x + mt[7] * vec4.y + mt[11]* vec4.z + mt[15] * vec4.w );       
 
   };
 
};
class CMatrix16
{
public:
 float mt[16];

   inline CVector4D operator*(CVector4D & vec4) {
return CVector4D(mt[0] * vec4.x + mt[4] * vec4.y + mt[8] * vec4.z + mt[12] * vec4.w ,
  mt[1] * vec4.x + mt[5] * vec4.y + mt[9] * vec4.z + mt[13] * vec4.w ,
 mt[2] * vec4.x + mt[6] * vec4.y + mt[10]* vec4.z + mt[14] * vec4.w ,
  mt[3] * vec4.x + mt[7] * vec4.y + mt[11]* vec4.z + mt[15] * vec4.w );  

   };

};
然后,我們回頭看之前那條式子,得出的結(jié)果是(A*cosΘ*x - sinΘ*y + 10,sinΘ*x + A*cosΘ*y,A*z,1),這是點(diǎn)P的新位置,注意,再說一次,是“位置”而不是“坐標(biāo)”,點(diǎn)P坐標(biāo)依然是(x,y,z,1)。(當(dāng)然,你還可以用這樣的概念來區(qū)分。)我姑且把結(jié)果記作(MP),所有點(diǎn)的結(jié)果構(gòu)成了蘋果在世界空間的位置。好了,看看代碼:
 
glMatrixMode(GL_MODEL);
glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
  
DrawApple() ;
glMatrixMode(GL_MODEL);
glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
 
DrawApple() ;
請從下往上看。你問為什么順序是倒著的呢?這跟上篇遺留下來的問題很相似。現(xiàn)在經(jīng)過模型變換來到了世界空間,接下來是視圖變換了。設(shè)當(dāng)前相機(jī)得出的左乘矩陣為V,那么下一步,相似地,就是V*(MP)=(VMP)。上篇說過,OpenGL把模型變換和視圖變換合并為“模型視圖變換”,也就是說,OpenGL只生成一個(gè)左乘矩陣VM,上面的兩步乘法,在OpenGL中其實(shí)一步到位:VM*P=(VMP)。我們來到了視圖空間。真正代碼在此:
 
gluLookat(eye,look,up);
 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();  
 
glTranslatef(10,0,0); 
glScalef(A,A,A); 
glRotatef(Θ, 0,0,1) 
   
DrawApple() ;
gluLookat(eye,look,up);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 

glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
  
DrawApple() ;
接下來由視景體設(shè)置,視口設(shè)置,投影處理得出的左乘矩陣是J,那么相似地,我們繼續(xù)左乘:J*(VMP)=(JVMP),來到屏幕空間——OpenGL世界的出口(之后的往窗口坐標(biāo)系映射等等已經(jīng)不算OpenGL的工作了)。
 
glViewport(0,0,width,height);//設(shè)置視口(視窗)大小
  
glMatrixMode(GL_PROJECTION));  
glLoadIdentity(); 
gluPerspective(fov,aspect,near,far);
 
gluLookat(eye,look,up); 
 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();   
 
glTranslatef(10,0,0);  
glScalef(A,A,A);  
glRotatef(Θ, 0,0,1)  
    
DrawApple() ;
glViewport(0,0,width,height);//設(shè)置視口(視窗)大小
 
glMatrixMode(GL_PROJECTION)); 
glLoadIdentity();
gluPerspective(fov,aspect,near,far);

gluLookat(eye,look,up);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();  

glTranslatef(10,0,0); 
glScalef(A,A,A); 
glRotatef(Θ, 0,0,1) 
   
DrawApple() ;
是不是回到了上篇的結(jié)尾呢?恩,我從矩陣意義上再梳理了一次流程。然后,可以回答為什么代碼是倒過來寫的了吧?——這說明你很清楚,代碼是按順序從上往下執(zhí)行的。沒錯(cuò),OpenGL中執(zhí)行這些代碼也是從上往下執(zhí)行的。所以你看看吧,這次要從上往下看:第1句:視窗設(shè)置,沒什么,它只剔除,不直接產(chǎn)生矩陣(而且還得在下面投影變換處發(fā)揮作用);第2句:接下來要作投影變換啦;第3句:glLoadIdentity(),哈哈!這才是重點(diǎn)——無論眼前的是什么,它都能把它初始化成一個(gè)單位矩陣!而這里的這個(gè)單位矩陣,是一切的開端,它確實(shí)就是一個(gè)單位矩陣(I)了,后面第4句視景體的設(shè)置產(chǎn)生的投影變換矩陣(J)右乘它:J= I*J;接下來第5句相機(jī)設(shè)置,第6句表示模型視圖變換的開始,第7句又一個(gè)glLoadIdentity(),繼續(xù)右乘:J= I*J*I,這有什么用啊?呵呵,因?yàn)榻酉聛?#8220;模型視圖變換”產(chǎn)生的矩陣VM要繼續(xù)右乘這個(gè)結(jié)果,直接讓兩個(gè)變換矩陣相乘可以是可以,那么如果沒有投影變換呢?呵呵,這是有可能的,先不說平時(shí)我們渲染,就我們哪天突然要在模型空間搞事(譬如上次ShadowVolumeDemo那樣“回光返照”),單單應(yīng)用“模型視圖變換”就關(guān)聯(lián)不到最初那個(gè)glLoadIdentity()了。所以讓一個(gè)glLoadIdentity()在作變換前出現(xiàn)是好的:VM = I*VM,實(shí)際上所有變換前加一個(gè)glLoadIdentity()是好習(xí)慣。
好吧,整理一下:假設(shè)把蘋果旋轉(zhuǎn),放大,移動的相應(yīng)變換矩陣是R,S,T,相機(jī)那個(gè)是L,那么這里就是 VM =L*T*S*R,也是倒過來的吧呵呵。按代碼順序的話右乘起來是這樣的:(JVM)= I*J*I*VM =I *J*I*L*S*T,等式右邊項(xiàng)是嚴(yán)格按照相應(yīng)代碼順序來右乘的。為什么這里變右乘了?事實(shí)上我們說OpenGL的矩陣左乘規(guī)范,它跟代碼順序是兩碼事,矩陣左乘是從邏輯上來說的(也就是上篇和本篇我在開講代碼執(zhí)行順序前講述的那些故事的邏輯,是屬于OpenGL世界的邏輯),代碼順序是屬于編譯器的哦。好了,這個(gè)(JVM)就是要把處于模型空間的物體轉(zhuǎn)移到屏幕上來——這時(shí)候它才和蘋果的頂點(diǎn)相乘:(JVMP)=(JVM)*P,看好了,也是右乘,當(dāng)然的了——結(jié)果是,蘋果那么多頂點(diǎn)在一次渲染周期內(nèi)只被“用”了一次!要知道,得出(JVM)結(jié)果的計(jì)算只有那么幾個(gè)矩陣相乘運(yùn)算,但是蘋果N個(gè)頂點(diǎn)就有N個(gè)(JVM)*P的相乘運(yùn)算哦!如果代碼執(zhí)行順序相反你覺得會怎樣?“幾個(gè)N相乘”這么多次運(yùn)算哦!
 
 
這里還有概念要澄清:
1.我說了,蘋果也好,其他任何畫出來的“東西”也好,它們坐標(biāo)是在給出頂點(diǎn)坐標(biāo)的時(shí)候就確定在模型空間的了,變換的是位置,也許說它們變換了還不對——因?yàn)檎嬲蛔儞Q的是坐標(biāo)系:你上面也看到了,蘋果的坐標(biāo)是最后右乘上去的,之前一直變換的是最初那個(gè)單位矩陣,單位矩陣的變換也代表了最初各空間重合的OpenGL世界的坐標(biāo)系——上篇說過,它的變換是反著模型的(當(dāng)然也反著單位矩陣),這里也不妨說,它受變換的階段順序都是反著模型的——而且它是按照編譯器執(zhí)行順序變換出來的,是真正的,真實(shí)存在的變換:OpenGL中所有的變換,都是在變換坐標(biāo)系。

2.說法問題,“坐標(biāo)”和“位置”,一路看下來你也知道,我不把它們當(dāng)一回事(不想再羅嗦了恩)。但是更通常的叫法(雖然容易引起歧義但說得廣泛),是把“坐標(biāo)”(固定于模型空間的那個(gè),模型剛剛在世界出現(xiàn)時(shí)候的位置- -看,又羅嗦了)稱為“局部坐標(biāo)(Local-Coordinate)”,把世界空間里面那個(gè)“位置”叫“世界坐標(biāo)(World-Coordinate)”,也有直接簡稱它為坐標(biāo)的(這樣的明顯不是高手),因?yàn)樗钅鼙桓兄苍S你在了解什么模型空間模型變換等等等等這些概念前,唯一認(rèn)識的就是世界坐標(biāo)——它就標(biāo)識著3D渲染窗口里那個(gè)虛擬3D世界不是么?恩,所以說世界空間是OpenGL世界中近乎“正常”的空間,類比一下,如果把我們?nèi)祟愃畹目臻g叫“世界空間”的話,小說中描繪的到處扭曲的異次元空間就叫“模型空間”呀“屏幕空間”呀之類的了(笑)。遺憾的是OpenGL不直接給我們提供這個(gè)空間中各物體的坐標(biāo)系位置呢~不怕,我們還有逆矩陣!
3.等有緣的你來發(fā)挖啦!錯(cuò)誤啦認(rèn)識問題啦,隨便提。這里是ZwqXin: www.zwqxin.com, 我的3D旅途記錄簿。(紀(jì)念今天2009.2.5.BLOG上軌道啦。)
最后...還有g(shù)lPushMatrix()和glPopMatrix()呢?相信大家用得很多,也知道用處:在它們之外的東西不受它們里面的那些模型變換代碼影響。譬如下面這里,蘋果跟上面一樣也是做那些變換。可是橙呢?旋轉(zhuǎn)和放大對它無影響,它只是受到移動了(OpenGL世界說法是,對應(yīng)坐標(biāo)系移動了)。
 
glMatrixMode(GL_MODELVIEW);  
glLoadIdentity();    
  
glTranslatef(10,0,0);  
 
glPushMatrix();
  glScalef(A,A,A);   
  glRotatef(Θ, 0,0,1);       
  DrawApple() ;
glPopMatrix();
 
DrawOrange() ;
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();   
 
glTranslatef(10,0,0); 

glPushMatrix();
  glScalef(A,A,A);  
  glRotatef(Θ, 0,0,1);      
  DrawApple() ;
glPopMatrix();

DrawOrange() ;
不知道我的講解有沒有人滿意。我自己倒是滿意了。哈哈。后面我還會有文章說說逆矩陣運(yùn)算的問題和作用,并贊NEHE,有興趣的不妨CLICK一CLICK:

本文來源于ZwqXin http://www.zwqxin.com/ , 轉(zhuǎn)載請注明
原文地址:http://www.zwqxin.com/archives/opengl/opengl-matrix-what-2.html




 


 

posted on 2009-04-23 16:33 doing5552 閱讀(2128) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品久久| 亚洲一区二区精品视频| 久久久久久久久岛国免费| 午夜精品福利视频| 国产亚洲精品综合一区91| 性欧美8khd高清极品| 欧美一级网站| 有码中文亚洲精品| 亚洲欧洲久久| 国产精品欧美在线| 久久岛国电影| 欧美 亚欧 日韩视频在线| 亚洲另类视频| 亚洲一区二区视频在线观看| 国产在线视频欧美| 欧美va天堂va视频va在线| 欧美激情aaaa| 午夜精品久久久久久久99樱桃| 亚洲欧美电影院| 亚洲国产欧美不卡在线观看| 一本久久综合亚洲鲁鲁| 国产亚洲精品久| 亚洲国产成人精品视频| 国产精品入口夜色视频大尺度 | 免费亚洲婷婷| 亚洲一区二区在线免费观看视频 | 欧美不卡在线| 欧美日韩亚洲激情| 美女视频黄免费的久久| 欧美日韩一区在线观看视频| 老**午夜毛片一区二区三区| 欧美日韩a区| 久久综合色综合88| 欧美午夜片在线观看| 欧美不卡一区| 国产欧美日韩不卡免费| 欧美激情在线免费观看| 国产欧美日韩三级| 亚洲人成网站精品片在线观看 | 久久免费视频观看| 亚洲欧美日韩精品| 免费观看在线综合色| 欧美在线你懂的| 欧美日本免费| 亚洲国产99| 伊人久久婷婷| 欧美一区二区久久久| 亚洲欧美日韩视频二区| 欧美国产在线电影| 欧美成人中文| 激情婷婷亚洲| 午夜一区在线| 亚洲欧美制服另类日韩| 欧美激情第10页| 欧美激情四色| 在线观看成人小视频| 小黄鸭精品密入口导航| 午夜精品免费视频| 欧美午夜激情在线| 亚洲日本中文字幕| 亚洲另类一区二区| 欧美激情一区二区在线| 亚洲黄色尤物视频| 一本在线高清不卡dvd| 免费91麻豆精品国产自产在线观看| 久久久久久久性| 好吊视频一区二区三区四区| 亚洲摸下面视频| 欧美一级二区| 国产三级精品三级| 欧美一区三区二区在线观看| 久久精品av麻豆的观看方式| 国产亚洲精品久久久久动| 亚洲欧美激情一区| 久久久久久久综合日本| 好吊色欧美一区二区三区四区| 久久久精品性| 欧美国产日韩亚洲一区| aa日韩免费精品视频一| 国产精品久久久久aaaa樱花| 亚洲淫性视频| 久久影视精品| 91久久精品日日躁夜夜躁欧美| 欧美电影在线| 亚洲性xxxx| 久久综合福利| 99精品视频一区| 国产精品免费电影| 久久亚洲精品一区二区| 亚洲精品久久久久中文字幕欢迎你| 一个色综合av| 国产亚洲精品美女| 欧美成人日韩| 亚洲一区二区黄色| 美女黄色成人网| 亚洲深夜影院| 一区一区视频| 欧美日韩综合网| 久久精品国产在热久久| 亚洲日本欧美日韩高观看| 香蕉av777xxx色综合一区| 在线看日韩欧美| 欧美无砖砖区免费| 久久久久www| 亚洲视频欧美视频| 欧美风情在线观看| 午夜亚洲激情| 亚洲精品欧美极品| 国产麻豆9l精品三级站| 欧美理论电影在线播放| 欧美在线观看视频在线| 一本久久青青| 亚洲成在人线av| 久久精品久久综合| 亚洲欧美日韩在线播放| 91久久久久久久久| 韩国精品主播一区二区在线观看| 欧美日韩精品三区| 欧美岛国在线观看| 久久精品人人爽| 亚洲综合精品四区| 夜夜嗨av一区二区三区网页| 另类专区欧美制服同性| 午夜欧美大片免费观看 | 国产精品美女久久久久久2018| 快播亚洲色图| 欧美综合77777色婷婷| 亚洲一区二区三区四区五区黄| 亚洲精品韩国| 欧美国产日韩免费| 老司机67194精品线观看| 性做久久久久久| 亚洲在线视频免费观看| 亚洲毛片av在线| 亚洲韩国青草视频| 亚洲国产另类久久精品| 精品成人免费| 一区二区在线视频播放| 国产亚洲永久域名| 国产色爱av资源综合区| 国产精品一区毛片| 国产精品色午夜在线观看| 欧美午夜宅男影院在线观看| 欧美日本国产一区| 欧美日韩成人在线| 欧美精品在线极品| 欧美日韩在线免费视频| 欧美区视频在线观看| 欧美激情综合五月色丁香| 欧美二区在线观看| 欧美另类女人| 欧美视频在线观看 亚洲欧| 欧美日韩在线视频一区二区| 国产精品v欧美精品v日韩精品| 国产精品av久久久久久麻豆网| 国产精品高潮呻吟久久av黑人| 欧美三级资源在线| 国产精品天天看| 狠狠色伊人亚洲综合成人| 激情欧美一区二区三区| 91久久久精品| 亚洲视频精选在线| 欧美一区二区视频97| 久久av一区二区三区漫画| 久久五月天婷婷| 亚洲高清视频在线观看| 一本色道久久| 久久国产手机看片| 欧美激情按摩在线| 国产精品久久国产三级国电话系列| 国产精品一区免费视频| 尤妮丝一区二区裸体视频| 日韩午夜电影| 久久精品国产999大香线蕉| 欧美jizzhd精品欧美巨大免费| 亚洲精品韩国| 欧美一级黄色网| 欧美高清在线观看| 国产日韩欧美精品一区| 亚洲高清资源综合久久精品| 亚洲视频日本| 老司机67194精品线观看| 亚洲毛片在线观看| 久久国产主播精品| 欧美日韩免费观看一区二区三区| 国产亚洲精品美女| 中文精品视频| 欧美69wwwcom| 亚洲综合三区| 欧美激情91| 永久免费毛片在线播放不卡| 亚洲视频免费观看| 牛夜精品久久久久久久99黑人| 一区二区高清在线观看| 久久午夜精品一区二区| 国产农村妇女精品| 亚洲视频在线二区| 亚洲国产成人不卡| 久久久999国产| 国产精品视频导航|