• <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>

            doing5552

            記錄每日點滴,不枉人生一世

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

            公告

            常用鏈接

            留言簿(24)

            我參與的團隊

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 454869
            • 排名 - 48

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

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


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

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

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

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

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

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

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

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

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

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

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

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

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


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

               };

            };
            然后,我們回頭看之前那條式子,得出的結果是(A*cosΘ*x - sinΘ*y + 10,sinΘ*x + A*cosΘ*y,A*z,1),這是點P的新位置,注意,再說一次,是“位置”而不是“坐標”,點P坐標依然是(x,y,z,1)。(當然,你還可以用這樣的概念來區分。)我姑且把結果記作(MP),所有點的結果構成了蘋果在世界空間的位置。好了,看看代碼:
             
            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() ;
            請從下往上看。你問為什么順序是倒著的呢?這跟上篇遺留下來的問題很相似。現在經過模型變換來到了世界空間,接下來是視圖變換了。設當前相機得出的左乘矩陣為V,那么下一步,相似地,就是V*(MP)=(VMP)。上篇說過,OpenGL把模型變換和視圖變換合并為“模型視圖變換”,也就是說,OpenGL只生成一個左乘矩陣VM,上面的兩步乘法,在OpenGL中其實一步到位: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() ;
            接下來由視景體設置,視口設置,投影處理得出的左乘矩陣是J,那么相似地,我們繼續左乘:J*(VMP)=(JVMP),來到屏幕空間——OpenGL世界的出口(之后的往窗口坐標系映射等等已經不算OpenGL的工作了)。
             
            glViewport(0,0,width,height);//設置視口(視窗)大小
              
            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);//設置視口(視窗)大小
             
            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() ;
            是不是回到了上篇的結尾呢?恩,我從矩陣意義上再梳理了一次流程。然后,可以回答為什么代碼是倒過來寫的了吧?——這說明你很清楚,代碼是按順序從上往下執行的。沒錯,OpenGL中執行這些代碼也是從上往下執行的。所以你看看吧,這次要從上往下看:第1句:視窗設置,沒什么,它只剔除,不直接產生矩陣(而且還得在下面投影變換處發揮作用);第2句:接下來要作投影變換啦;第3句:glLoadIdentity(),哈哈!這才是重點——無論眼前的是什么,它都能把它初始化成一個單位矩陣!而這里的這個單位矩陣,是一切的開端,它確實就是一個單位矩陣(I)了,后面第4句視景體的設置產生的投影變換矩陣(J)右乘它:J= I*J;接下來第5句相機設置,第6句表示模型視圖變換的開始,第7句又一個glLoadIdentity(),繼續右乘:J= I*J*I,這有什么用啊?呵呵,因為接下來“模型視圖變換”產生的矩陣VM要繼續右乘這個結果,直接讓兩個變換矩陣相乘可以是可以,那么如果沒有投影變換呢?呵呵,這是有可能的,先不說平時我們渲染,就我們哪天突然要在模型空間搞事(譬如上次ShadowVolumeDemo那樣“回光返照”),單單應用“模型視圖變換”就關聯不到最初那個glLoadIdentity()了。所以讓一個glLoadIdentity()在作變換前出現是好的:VM = I*VM,實際上所有變換前加一個glLoadIdentity()是好習慣。
            好吧,整理一下:假設把蘋果旋轉,放大,移動的相應變換矩陣是R,S,T,相機那個是L,那么這里就是 VM =L*T*S*R,也是倒過來的吧呵呵。按代碼順序的話右乘起來是這樣的:(JVM)= I*J*I*VM =I *J*I*L*S*T,等式右邊項是嚴格按照相應代碼順序來右乘的。為什么這里變右乘了?事實上我們說OpenGL的矩陣左乘規范,它跟代碼順序是兩碼事,矩陣左乘是從邏輯上來說的(也就是上篇和本篇我在開講代碼執行順序前講述的那些故事的邏輯,是屬于OpenGL世界的邏輯),代碼順序是屬于編譯器的哦。好了,這個(JVM)就是要把處于模型空間的物體轉移到屏幕上來——這時候它才和蘋果的頂點相乘:(JVMP)=(JVM)*P,看好了,也是右乘,當然的了——結果是,蘋果那么多頂點在一次渲染周期內只被“用”了一次!要知道,得出(JVM)結果的計算只有那么幾個矩陣相乘運算,但是蘋果N個頂點就有N個(JVM)*P的相乘運算哦!如果代碼執行順序相反你覺得會怎樣?“幾個N相乘”這么多次運算哦!
             
             
            這里還有概念要澄清:
            1.我說了,蘋果也好,其他任何畫出來的“東西”也好,它們坐標是在給出頂點坐標的時候就確定在模型空間的了,變換的是位置,也許說它們變換了還不對——因為真正被變換的是坐標系:你上面也看到了,蘋果的坐標是最后右乘上去的,之前一直變換的是最初那個單位矩陣,單位矩陣的變換也代表了最初各空間重合的OpenGL世界的坐標系——上篇說過,它的變換是反著模型的(當然也反著單位矩陣),這里也不妨說,它受變換的階段順序都是反著模型的——而且它是按照編譯器執行順序變換出來的,是真正的,真實存在的變換:OpenGL中所有的變換,都是在變換坐標系。

            2.說法問題,“坐標”和“位置”,一路看下來你也知道,我不把它們當一回事(不想再羅嗦了恩)。但是更通常的叫法(雖然容易引起歧義但說得廣泛),是把“坐標”(固定于模型空間的那個,模型剛剛在世界出現時候的位置- -看,又羅嗦了)稱為“局部坐標(Local-Coordinate)”,把世界空間里面那個“位置”叫“世界坐標(World-Coordinate)”,也有直接簡稱它為坐標的(這樣的明顯不是高手),因為它最能被感知,也許你在了解什么模型空間模型變換等等等等這些概念前,唯一認識的就是世界坐標——它就標識著3D渲染窗口里那個虛擬3D世界不是么?恩,所以說世界空間是OpenGL世界中近乎“正常”的空間,類比一下,如果把我們人類所生活的空間叫“世界空間”的話,小說中描繪的到處扭曲的異次元空間就叫“模型空間”呀“屏幕空間”呀之類的了(笑)。遺憾的是OpenGL不直接給我們提供這個空間中各物體的坐標系位置呢~不怕,我們還有逆矩陣!
            3.等有緣的你來發挖啦!錯誤啦認識問題啦,隨便提。這里是ZwqXin: www.zwqxin.com, 我的3D旅途記錄簿。(紀念今天2009.2.5.BLOG上軌道啦。)
            最后...還有glPushMatrix()和glPopMatrix()呢?相信大家用得很多,也知道用處:在它們之外的東西不受它們里面的那些模型變換代碼影響。譬如下面這里,蘋果跟上面一樣也是做那些變換。可是橙呢?旋轉和放大對它無影響,它只是受到移動了(OpenGL世界說法是,對應坐標系移動了)。
             
            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() ;
            不知道我的講解有沒有人滿意。我自己倒是滿意了。哈哈。后面我還會有文章說說逆矩陣運算的問題和作用,并贊NEHE,有興趣的不妨CLICK一CLICK:

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




             


             

            posted on 2009-04-23 16:33 doing5552 閱讀(2110) 評論(0)  編輯 收藏 引用
            久久国产精品成人免费| 久久久久亚洲精品天堂| 精品久久人人爽天天玩人人妻| 伊人久久大香线蕉影院95| 亚洲国产精品久久久久婷婷软件 | 日本精品久久久久中文字幕8| 亚洲综合久久综合激情久久| 一本色道久久综合狠狠躁篇| 亚洲αv久久久噜噜噜噜噜| 亚洲国产二区三区久久| 亚洲国产另类久久久精品黑人| 一本大道久久a久久精品综合| 狠狠色丁香婷婷久久综合五月| 成人妇女免费播放久久久| 伊人久久成人成综合网222| 无码伊人66久久大杳蕉网站谷歌| 久久精品国产99国产精品导航| 久久精品国产亚洲AV无码娇色| 久久无码一区二区三区少妇| 久久精品国产亚洲av影院| 欧美激情精品久久久久久久九九九| 日韩精品无码久久久久久| 亚洲午夜久久久| 日本三级久久网| 久久天天躁狠狠躁夜夜96流白浆| 99久久夜色精品国产网站| 国产高潮国产高潮久久久91 | 国产欧美久久久精品| 亚洲AV无码久久| 久久国语露脸国产精品电影| 色综合久久久久综合99| 久久精品国产精品亜洲毛片| 久久免费高清视频| av无码久久久久不卡免费网站| 国产激情久久久久久熟女老人 | 99久久er这里只有精品18| 亚洲va久久久噜噜噜久久| 亚洲国产精品无码久久久蜜芽| 色综合久久无码五十路人妻| 亚洲欧洲日产国码无码久久99| 亚洲va久久久噜噜噜久久狠狠|