小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

OpenGL學(xué)習(xí)腳印: 關(guān)于gluLookAt函數(shù)的理解

 方海龍的書館 2014-10-28

OpenGL學(xué)習(xí)腳印: 關(guān)于gluLookAt函數(shù)的理解

寫在前面

               本節(jié)借助gluLookAt函數(shù),推導(dǎo)世界坐標(biāo)轉(zhuǎn)換到照相機坐標(biāo)的一種方法,重點在于理解UVN相機坐標(biāo)系,以及變換矩陣的推導(dǎo)。限于筆者水平,如果錯誤請糾正我。



              gluLookAt函數(shù)提供給用戶完成模式變換(model-view transformation)中,在將模型坐標(biāo)系轉(zhuǎn)換都世界坐標(biāo)系后,進行世界坐標(biāo)系到照相機坐標(biāo)系的轉(zhuǎn)換。實際上,照相機的定位也是在世界坐標(biāo)系下定義的,這里的轉(zhuǎn)換,可以理解為:  從照相機的角度解釋世界坐標(biāo)系中物體的坐標(biāo)。通過構(gòu)造一個UVN坐標(biāo)系來簡化這一轉(zhuǎn)換。

              先直觀感受下UVN,UVN坐標(biāo)系中的照相機模型如下圖所示:

 

             借助下圖正式定義UVN相機坐標(biāo)系:


               與UVN相關(guān)的概念包括:

  •            相機位置,或者叫做視點(eyepoint):  觀察參考點 (View Reference Point)
  •            相機鏡頭方向,通過觀察平面的法向量指定:   觀察平面法向量VPN (View Plane Normal)
  •            相機頂部正朝向:VUV (View Up Vector)

     形象的表達(dá)為:


    gluLookAt函數(shù)原型為:

   

  1. void gluLookAt(GLdouble eyeX,  GLdouble eyeY,  GLdouble eyeZ,   
  2.   
  3.                                GLdouble centerX,  GLdouble centerY,  GLdouble centerZ,  
  4.   
  5.                               GLdouble upX,  GLdouble upY,  GLdouble upZ);  


官網(wǎng)關(guān)于此函數(shù)的描述:

gluLookAt        通過指定一個視點、表面場景中心的參考點以及up向量來構(gòu)造一個視變換矩陣。

這個矩陣將代表場景中心的參考點映射到-Z軸,視點映射成為原點。當(dāng)使用一個特定的投影矩陣時,場景的中心就映射到視口的中心。類似地,由up向量描述的方向投影到投影平面成為+y軸,這樣它在視口中向上指向。up向量必須不能與從視點到參考點的直線平行。
       
那么如何確定u-v-n坐標(biāo)系呢?計算公式如下:



     這里需要注意: OpenGL中使用的相機坐標(biāo)系是右手坐標(biāo)系,UVN坐標(biāo)系是左手坐標(biāo)系。在構(gòu)造實際變換矩陣的過程中,OpenGL

需要將-n軸翻轉(zhuǎn)為相機坐標(biāo)系的+z軸,uv軸定位相機坐標(biāo)系的+x和+y軸。這與推導(dǎo)相機變換矩陣一文最后的結(jié)果矩陣有所不同。


      如何構(gòu)造視變換矩陣?

     視變換就是在相機坐標(biāo)系下解釋世界坐標(biāo)系下的點。而這個變換矩陣的構(gòu)造,可以看做將相機坐標(biāo)系變換到與原來的世界坐標(biāo)系重合。而將世界坐標(biāo)系變換到與相機坐標(biāo)系重合,可以看做是這個所求變換的逆過程。

    將世界坐標(biāo)系變換到與相機坐標(biāo)系重合,實際上進行了兩個步驟:  第一步將世界坐標(biāo)系旋轉(zhuǎn)一定角度記作變換R,再將世界坐標(biāo)系平移到視點位置記作T,那么這個變換矩陣記為M=TR。要將世界坐標(biāo)系的點變換到照相機坐標(biāo)系下,需要使用矩陣M的逆矩陣,即: inverse(M)=inverse(R)*inverse(T)。即所求變換矩陣為inverse(M)。

平移矩陣的逆矩陣形式簡單,就是取平移量(eyex,eyey,eyez)的相反數(shù),即:

那么現(xiàn)在的關(guān)鍵是如何求出旋轉(zhuǎn)矩陣R?

上面我們構(gòu)造的UVN坐標(biāo)系u-v-n3個基向量可以構(gòu)造成矩陣:


注意這里對n軸進行了翻轉(zhuǎn),構(gòu)成右手照相機坐標(biāo)系。

怎么看這個矩陣A呢,矩陣A實際上代表的就是一個旋轉(zhuǎn)矩陣(從矩陣形式上看出)。

旋轉(zhuǎn)矩陣的一個特點就是它是正交矩陣,即有inverse(A) = transpose(A).(A^-1 = A^T)

很多教材和博客都說,這里A矩陣可以看做是將世界坐標(biāo)系轉(zhuǎn)換到與照相機坐標(biāo)系重合時的旋轉(zhuǎn)矩陣,這一點怎么理解呢?

個人理解,矩陣A第四列為0,0,0,1,可以看做是世界坐標(biāo)系和照相機坐標(biāo)系原點重合;根據(jù)《OpenGL學(xué)習(xí)腳印: 理解坐標(biāo)系及坐標(biāo)變換(上) 》中所講,矩陣前3列即變換后的基向量,那么這個基向量(都是單位向量)是如何計算出來的呢?就是通過旋轉(zhuǎn)原來的世界坐標(biāo)系的基向量來構(gòu)造的。因此,可以說矩陣A代表的就是將世界坐標(biāo)系旋轉(zhuǎn)到與相機坐標(biāo)系重合時的旋轉(zhuǎn)矩陣R,即R = A。

則inverse(R) = inverse(A) = transpose(A)      即為:


所以gluLookAt所求變換矩陣inverse(M)為:




gluLookAt的默認(rèn)值是(0, 0, 0, 0, 0,-1, 0, 1, 0);通過計算可得出:u=(1,0,0),v=(0,1,0),n=(0,0,-1),這樣構(gòu)成的矩陣M^-1即為單位矩陣。


下面通過代碼來驗證下結(jié)論。代碼繪制一個立方體,設(shè)置為透視投影,并通過gluLookAt設(shè)置相機方位來查看立方體。

注意,為了便于觀察視變換矩陣,這里并沒有進行其他模型變換;手動計算矩陣時使用了數(shù)學(xué)庫glm來進行向量點積和叉積運算。

 

  1. //計算gluLookAt矩陣  
  2.   
  3. #include <GL/glew.h>  
  4. #include <GL/freeglut.h>  
  5. #include <glm/glm.hpp>  
  6. #include <iostream>  
  7. #pragma comment(lib,"freeglut.lib")  
  8. #pragma comment(lib,"glew32.lib")  
  9.   
  10. void userInit();  
  11. void display( void );  
  12. void keyboardAction( unsigned char key, int x, int y );  
  13. void reshape(int w,int h);  
  14.   
  15. int main( int argc, char **argv )  
  16. {  
  17.     glutInit(&argc, argv);//初始化GLUT  
  18.   
  19.     glutInitDisplayMode( GLUT_RGBA|GLUT_DOUBLE);  
  20.     glutInitWindowPosition(100,100);  
  21.     glutInitWindowSize( 512, 512 );  
  22.     glutCreateWindow( "gluLookAt demo" );  
  23.        
  24.     glewInit();//使用GLEW時,使用該函數(shù)初始化GLEW  
  25.     userInit();//自定義的初始化函數(shù)  
  26.     glutReshapeFunc(reshape);  
  27.     glutDisplayFunc( display );  
  28.     glutKeyboardFunc( keyboardAction );  
  29.     glutMainLoop();  
  30.     return 0;  
  31. }  
  32. //自定義初始化函數(shù)  
  33. void userInit()  
  34. {  
  35.      glClearColor( 0.0, 0.0, 0.0, 0.0 );  
  36.      glColor4f(0.6f,0.5f,0.0,0.0);  
  37. }  
  38. //設(shè)置視變換矩陣  
  39. void setViewMatrix(GLdouble *theMatrix,GLdouble eyex,GLdouble eyey,GLdouble eyez,  
  40.                 GLdouble targetx,GLdouble targety,GLdouble targetz,  
  41.                 GLdouble vupx,GLdouble vupy,GLdouble vupz)  
  42. {     
  43.     glm::vec3 eye(eyex,eyey,eyez),target(targetx,targety,targetz),vup(vupx,vupy,vupz);  
  44.     //構(gòu)造n軸  
  45.     glm::vec3 nvec(target-eye);  
  46.     nvec=glm::normalize(nvec);  
  47.     //構(gòu)造u軸  
  48.     vup = glm::normalize(vup);  
  49.     glm::vec3 uvec = glm::cross(nvec,vup);  
  50.     uvec=glm::normalize(uvec);  
  51.     //構(gòu)造v軸  
  52.     glm::vec3 vvec = glm::cross(uvec,nvec);  
  53.     vvec=glm::normalize(vvec);  
  54.     //設(shè)置4x4矩陣  
  55.     memset(theMatrix,0,sizeof(GLdouble)*16);  
  56.   
  57.     theMatrix[0] = uvec.x;  
  58.     theMatrix[4] = uvec.y;  
  59.     theMatrix[8] = uvec.z;  
  60.     theMatrix[12 ] = -glm::dot(eye,uvec);  
  61.   
  62.     theMatrix[1] = vvec.x;  
  63.     theMatrix[5] = vvec.y;  
  64.     theMatrix[9] = vvec.z;  
  65.     theMatrix[13] = -glm::dot(eye,vvec);  
  66.   
  67.     //注意這行數(shù)據(jù)  
  68.     theMatrix[2] = -nvec.x;  
  69.     theMatrix[6] = -nvec.y;  
  70.     theMatrix[10] = -nvec.z;  
  71.     theMatrix[14] = glm::dot(eye,nvec);  
  72.   
  73.     theMatrix[15] = 1.0;  
  74. }  
  75. void reshape(int w,int h)  
  76. {  
  77.     glViewport(0,0,GLsizei(w),GLsizei(h));  
  78.     glMatrixMode(GL_PROJECTION);  
  79.     glLoadIdentity();  
  80.     gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,10.0);  
  81.     glMatrixMode(GL_MODELVIEW);  
  82.     glLoadIdentity();  
  83.   
  84.     //gluLookAt(2.0,0.0,1.8,0.0,0.0,0.0,0.0,1.0,0.0);  
  85.   
  86.     //手動構(gòu)造視變換矩陣  
  87.     GLdouble theMatrix[16];  
  88.     setViewMatrix(theMatrix,2.0,0.0,1.8,0.0,0.0,0.0,0.0,1.0,0.0);  
  89.     glMultMatrixd(theMatrix);  
  90.   
  91.     //打印當(dāng)前模視變換矩陣內(nèi)容  
  92.     GLdouble modelViewMat[16];  
  93.     glGetDoublev(GL_MODELVIEW_MATRIX,modelViewMat);  
  94.     for(int i = 0;i<4;i++)  
  95.        for(int j=0;j<4;j++)  
  96.     {  
  97.         fprintf(stdout,"%-.4f\t",modelViewMat[i+4*j]);  
  98.         if((j+1) %4 == 0) fprintf(stdout,"\n");  
  99.     }  
  100. }  
  101. //繪制回調(diào)函數(shù)  
  102. void display( void )  
  103. {  
  104.     glClear( GL_COLOR_BUFFER_BIT);//清除顏色緩存  
  105.     glLineWidth(2.0);  
  106.     glutWireCube(1.0);  
  107.     glutSwapBuffers();  
  108. }  
  109. //鍵盤按鍵回調(diào)函數(shù)  
  110. void keyboardAction( unsigned char key, int x, int y )  
  111. {  
  112.     switch( key ) {  
  113.     case 033:  // Escape key  
  114.     case 'q': case 'Q':  
  115.         exit( EXIT_SUCCESS );  
  116.         break;  
  117.     }  
  118. }  


使用gluLookAt如下圖左右所示:

手動計算視變換矩陣,效果如下圖所示:

可以看出兩者是一樣的,二者的視變換矩陣打印出來均為:

0.6690  0.0000  -0.7433 0.0000
0.0000  1.0000  0.0000  0.0000
0.7433  0.0000  0.6690  -2.6907
0.0000  0.0000  0.0000  1.0000

至此證明了上述推導(dǎo)的矩陣確實為OpenGL中使用的視變換矩陣。


關(guān)于OpenGL gluLookAt官網(wǎng)提供了參考實現(xiàn),可以查看:  GluLookAt code;

另外關(guān)于頂部正朝向vup的理解有更好的通俗解釋,可以查看:Opengl---gluLookAt函數(shù)詳解 。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多