OpenGLES Android篇零基礎系列(二):OpenGL各座標系及模型矩陣(ModelViewMatrix),投影矩陣(ProjectionMatrix)等的深入理解
上一篇我們粗略的介紹了下GLES20 中 GLSurfaceView以及Render介面的使用。
對於三角形頂點座標的定義並沒有做出註釋,其實在官方的ApiDemo中,它也是赤裸裸的,一個註釋都沒有,且程式碼寫得一點都不敢恭維,不知道那位同行現在是不是還在google裡面。下面貼出一小段官方的ApiDemo中的程式碼,一起鑑賞鑑賞:
private static final int FLOAT_SIZE_BYTES = 4;
private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
-1.0f, -0.5f, 0, 0.0f, 0.5f,
1.0f, -0.5f, 0, 1.0f, 0.5f,
0.0f, 1.0f, 0, 0.0f, 1.0f };
如上,你們能看懂嗎?在定義三角形頂點座標資料時,僅僅只是簡單粗暴的註釋X,Y,Z,U,V,其中X,Y,Z好理解,可這U,V又是什麼呢?X,Y,Z,U,V它們之間又有什麼聯絡呢?
如果僅僅只是想從ApiDemo裡面去研究,去搞懂它們是什麼,怎麼用,那估計不是一天兩天的事,還得從浩瀚的網路中去查詢。
正文:座標系
OpenGL有6種座標系,分別如下:
- 1,物體或模型座標系(Object or model coordinates);
- 2,世界座標系(World coordinates)
- 3,眼座標或相機座標(Eye (or Camera) coordinates)
- 4,裁剪座標系(Clip coordinates)
- 5,標準裝置座標系(Normalized device coordinates)
- 6,螢幕座標系(Window (or screen) coordinates)
除了上面6種外,OpenGL還存在一種假想座標系紋理座標系,這個座標系是不存在的,它其實是一系列變換矩陣的結果,比如它能使頂點從物體或模型座標系變換到世界座標系。
從object coordainates到world coordinates再到camera coordinate的變換,在OpenGL中統一稱為model-view轉換,初始化的時候,object coordinates和world coordinates還有camera coordinates座標重合在原點,變換矩陣都為Identity,所以在OpenGL中用glLoadIdentity()初始化變換矩陣棧。model-view matix轉換points,vectorsd到camera座標系。
OpenGL 的重要功能之一就是將三維的世界座標經過變換、投影等計算,最終算出它在顯示裝置上對應的位置,這個位置就稱為裝置座標。在螢幕、印表機等裝置上的座標是二維座標。值得一提的是,OpenGL可以只使用裝置的一部分進行繪製,這個部分稱為視區或視口(viewport)。投影得到的是視區內的座標(投影座標),從投影座標到裝置座標的計算過程就是裝置變換了。
我們在OpenGL ES中常用到的幾種座標系:世界座標系、物體座標系、裝置座標系、眼座標系當然還有假想的紋理座標系
一、螢幕座標系
對於移動裝置來說,我們都知道,左上角為座標原點,向右為X軸,向下為Y軸。如下圖(圖畫的醜了點,先忍忍啊^_^):
二、世界座標系
這個世界座標系是針對OpenGL來說明的。即三維座標系X,Y,Z.
它有一個漂亮的學名:右手笛卡爾座標系統,這個座標系常用來描述物體及光源的位置。
在移動裝置中,螢幕中心為座標三點,水平向右為X軸,在原點垂直X軸向上為Y軸,在原點垂直X,Y軸指向螢幕外為Z軸(正面對手機螢幕,直戳你眼睛的就是Z軸),同樣如下圖:
將物體放到場景中也就是將物體平移到特定位置、旋轉一定角度,這些操作就是座標變換。OpenGL中提供了glTranslate*/glRotate*/glScale*三條座標變換命令,利用OpenGL的矩陣運算命令,則可以實現任意複雜的座標變換。
在這裡還要提一個重要的概念:座標變換矩陣棧(ModelView)
座標變換矩陣棧
用來儲存一系列的變換矩陣,棧頂就是當前座標的變換矩陣,進入OpenGL管道的每個座標(齊次座標)都會先乘上這個矩陣,結果才是對應點在場景中的世界座標。OpenGL中的座標變換都是通過矩陣運算完成的。
如圖:
ModelViewMatrix:模型矩陣
ProjectionMatrix:投影矩陣
三、紋理座標系
通過上一節,我們知道,紋理是圖片,視訊等的一種渲染方式,圖片只有通過紋理才能載入到GLES中。
因此紋理座標系是指圖片,視訊等在手機螢幕上的座標系,即U,V也有叫ST。該座標系是一種假想座標系,並不真正存在的,只是變換矩陣的結果。下面就統一叫UV座標系。
當應用初始化時,UV座標系與三維座標系(世界座標系)重合。
我們要注意的是,在OpenGL繪製過程中,它是可以選擇繪製模式的,比如:點,線,面,且都是座標集合裡面進行順序繪製的。i.e.:
private final float[] mTriangleVerticesData = {
// X, Y, Z,
-1.0f, -0.5f, 0, //1
1.0f, -0.5f, 0, //2
0.0f, 1.0f, 0, //3
};
當我們以紋理的形式載入一個圖片到OpenGL中時,如何讓它顯示在世界座標系中呢?這時就用到了紋理貼圖的方式(即根據在世界座標系中繪製頂點的先後順序,把UV座標系中的座標與其一一對應),畫圖更加直接(從網上copy的圖,在此感謝):
四、物體座標系
物體座標系是以物體的某一個點為原點來建立的三維座標系(世界座標系)。僅針對該物體。物體放到場景中時,各部分經歷的座標變換矩陣相同,相對位置不變,所以可視為一個整體
五、眼座標系或相機座標系
以視點為原點,以視線的方向為Z+軸正方向的座標系中的方向。OpenGL管道會將世界座標先變換到眼座標,然後進行裁剪,只有在視線範圍(視見體)之內的場景才會進入下一階段的計算。
六、裁剪座標系
由眼座標可知,OpenGL管道首先會將目標從世界座標變換到眼座標,然後對視線範圍外的部分進行裁剪。
裁剪過程中用到投影變換矩陣棧(ProjectionMatrix),棧頂矩陣就是當前投影變換矩陣,負責將場景各座標變換到眼座標,由所得到的結果是裁剪後的場景部分,稱為裁剪座標
我們上面說到了ModelViewMatrix 與ProjectionMatrix兩個矩陣棧,那矩陣棧是怎麼切換的呢?
用函式:glMatrixMode(GL_MODELVIEWING或GL_PROJECTION);本命令執行後引數所指矩陣棧就成為當前矩陣棧,以後的矩陣棧操縱命令將作用於它。
緊接著glMatrixMode()就是初始化矩陣,我們在上面也講到,所有矩陣都為Identity,所以用方法glLoadIdentity()初始化矩陣。