標籤:opengl 座標變換
座標變換是深入理解三維世界的基礎,非常重要。學習這部分首先要清楚幾個概念:視點變換、模型變換、投影變換、視口變換。
在現實世界中,所有的物體都具有三維特徵,但電腦本身只能處理數字,顯示二維的圖形,因此我們要將三維物體用二維資料表示出來,這一聯絡的點就是座標。在OpenGL三維空間中座標的形式有兩種:全局座標系和局部座標系。
①全局座標系:始終固定不變。舉例,以太陽系中心太陽為中心原點,建立全局座標系的話,地球繞太陽的公轉運動是全局座標的變換。
②局部座標系:物體本身的中心。地球的自傳就是局部座標系下的旋轉變換,縮放也是局部座標系下的變換。
三維物體到二維映像的轉換是通過視點變換、模型變換、投影變換、視口變換來實現的,這點類似於用照相機拍照的過程。
(1)視點變換-->選擇觀察點,對準物體
(2)模型變換-->調整物體(即模型),包括旋轉、縮放、平移
(3)投影變換-->將物體進行投影放大或縮小,投影到二維畫布或者叫底片上,形成二維映像
(4)視口變換-->最終決定產生的二維映像到底顯示在螢幕的什麼位置和顯示視窗的大小,可以理解對映像進行縮放。
投影變換和矩陣棧的操作稍微複雜點,放在下一篇,由於視口變換是針對投影變換形成的二維映像做操作的,所以和投影變換一起放到下一篇,這裡先介紹其他兩種變換。
首先,先瞭解在OpenGL中是怎麼變換的:
OpenGL中的各種轉換是通過矩陣運算實現的,無論是移動、旋轉還是縮放大小,都是通過在當前矩陣的基礎上乘以一個新的矩陣來達到目的。假設當前矩陣為C(即目前棧頂的矩陣,如果之前沒有做過變換,棧頂矩陣預設為單位矩陣),旋轉變換命令構成的矩陣為R,則發出轉換命令後,產生的新的當前矩陣為CR,這個矩陣再乘以頂點座標v,從而構成新的頂點座標(CR)v,這樣就完成了旋轉變換,且當前矩陣變為CR,。如果是連續做多種變換,例如上面的旋轉變換之後繼續做移動變換T,則產生新的當前矩陣為CRT,用這個總變換矩陣乘以頂點座標v,得到最終的頂點座標(CRT)v,由於矩陣乘法的結合率, (CRT)v = (C(R(Tv))),從而看出,程式中繪製頂點前的最後一個變換命令最先作用於頂點之上。這同時也說明,OpenGL編程中,實際的變換順序與指定的順序是相反的,即實際上是先進行移動,然後進行旋轉。
實體繪製
在講變換之前,首先需要知道OpenGL中繪製三維物體的具體函數,以便理解給予的程式執行個體。OpenGL中的實體繪製函數主要在glut庫中(glut是工具 + 生產力庫,gl是核心庫,glu是對gl的部分封裝)。以下列出部分常用的實體繪製函數,並給與代碼執行個體:
//以下所有函數中,radius表示球體的半徑,slices表示球體縱向分割的數目(經線),主要是設定繪製的細密度,stacks表示球體橫向分割的數目(緯線),建立了繪製中心在模型座標原點,半徑為radius的球體void glutWireSphere(GLdouble radius, GLint slices, GLint stacks); //網狀球void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); //實心球void glutWireCube(GLdouble size); //網狀立方體void glutSolidCube(GLdouble size); //實心立方體void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); //網狀圓環void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); //實心圓環void glutWireCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks); //網狀圓錐體void glutSolidCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks); //實心圓錐體void glutWireTeapot(GLdouble size); //網狀茶壺void glutSolidTeapot(GLdouble size); //實心茶壺
使用代碼執行個體:
void display(void){ glColor3f(0.0f, 1.0f, 0.0f);//綠色 glutSolidSphere(0.5,200,200);//半徑r=0.5,細密程度橫縱200份 glFlush();}
void display(void){ glColor3f(0.0f, 1.0f, 0.0f);//綠色 glutSolidSphere(0.5,10,10);//半徑r=0.5,細密程度橫縱10份,會發現,細密程度越高越精準,這是微積分的體現。但是高精度對效能的要求高,過高則渲染效率會降低,俗話會卡 glFlush();}
樣本圖:
網狀球體:
void display(void){ glColor3f(0.0f, 1.0f, 0.0f); glutWireSphere(0.5,20,20);//網狀球體,更有立體感 glFlush();}
樣本圖:
接下來做變換,改變視圖映像。
1、視點變換
視點,可以用攝影師的觀察點來形用,三維物體則看作是被拍攝的人或物,那麼視點的變換就是攝影師在尋找拍攝視角。
OpenGL實用庫提供了gluLookAt()函數,該函數有三個變數,分別定義了視點的位置、相機瞄準方向的參考點以及相機的向上方向。
void gluLookAt( GLdouble eyex,GLdouble eyey,GLdouble eyez,//(eyex,eyey,eyez)視點的位置; GLdouble centerx,GLdouble centery,GLdouble centerz,//(centerx,centery,centerz)注視的點,和視點之間連線形成注視方向; GLdouble upx,GLdouble upy,GLdouble upz //(upx,upy,upz)向上的方向,即頭頂的方向);
視點比做人的眼睛,當眼睛看物體時,頭朝天時(站立時)看到的物體和頭朝地時(倒立時)看到的物體是不一樣的.你還可以將頭部左右傾斜從不同的角度來看物體.那麼,gluLookAt的朝上向量就是用來確定這個方向的.不過在預設情況下,頭是朝天的,即朝上向量為(0, 1, 0)。
這裡,頭頂的方向和視線的方向用參數來設定不容易理解。
向上的方向(即頭頂方向)一旦確定後,視線的範圍就確定了,和人站住不動後,所能看到的角度是有限的一樣。
還是用代碼執行個體測試來看效果,我們以茶壺為三維實體。螢幕朝外的方向是Z軸正向。
1>預設狀態下,頭頂方向:(0,1,0)
void display(void){ glColor3f(0.0f, 1.0f, 0.0f);//畫筆顏色 { glMatrixMode(GL_MODELVIEW); //gluLookAt函數的作用範圍就是模型視圖下,這裡設定是必要的 glLoadIdentity();//初始化當前矩陣為單位矩陣,不設定預設單位矩陣 gluLookAt(0,0,1, 0,0,0, 0,1,0);//頭頂方向:Y軸正向,視點位置是Z軸正向1個單位(螢幕外),沿著Z軸看向原點 glutWireTeapot(0.5);//繪製茶壺 } glFlush();}
:
2>超出視野範圍時,看不到物體了
/* 視點在Y軸正向1單位處,而頭頂的方向是Y軸正向,這時,視線看不到腳下的原點,除非低頭,而低頭的話就改變了頭頂的方向,所以如下的設定是看不到物體的! */gluLookAt(0,1,0, 0,0,0, 0,1,0);
3>俯視觀察設定
gluLookAt(0,1,0, 0,0,0, 0,0,-1);//俯視:頭朝前,視點沿Y軸俯視看向原點
:
2、模型變換
從“相對移動”的觀點來看,改變觀察點(即攝影師)的位置與方向和改變物體本身(被拍攝的對象)的位置與方向具有等效性。其實視點本身也算一種模型,也可以調用模型變換函數。
主要有三種模型變換:
(1)模型平移
void myDisplay(void){ glColor3f(0.0f, 1.0f, 0.0f); { glMatrixMode(GL_MODELVIEW); //這是沒有平移的時候預設設定,(x,y,z)平移量為0 glTranslatef(0,0,0); //畫一個茶壺:一定要先做變換在繪製,先變換是改變了矩陣棧中的當前矩陣,然後用當前矩陣對要繪製的圖形做變換 glutWireTeapot(0.5);//畫一個茶壺 } glFlush();}需要注意的是,預設情況下,我們的視點位置在(0,0,1)處(float參數下),所以如果平移的超出視點所能看到的位置,則看不到物體。如glTranslatef(0,0,2):到了視點的後腦勺處,自然看不到物體。
glTranslatef(0.5,0.5,0);//向右上方位移
(2)模型旋轉
void myDisplay(void){ glColor3f(0.0f, 1.0f, 0.0f); { glMatrixMode(GL_MODELVIEW); glRotatef(45, 0,0,1);//後三個參數確定了一個方向點,和原點連線構成旋轉的軸線,這裡是Z軸,即繞Z軸旋轉45度 glutWireTeapot(0.5); } glFlush();}
(3)模型縮放
void myDisplay(void){ glColor3f(0.0f, 1.0f, 0.0f); { glMatrixMode(GL_MODELVIEW); glScalef(1,3,0.5);//分別表示x,y,z軸的縮放比例 glutWireTeapot(0.5); } glFlush();}
OpenGl學習之座標變換(上)