一、概念
在OpenGl ES中,將一個3D模型顯示到2D屏幕中有以下四個過程。
1. 視角(Viewing)變換
2. 模型(Modeling)變換
3. 投影(Projection)變換
4. 視窗(Viewport)變換
視角(Viewing)變換
相當於你拿着一臺照相機移動,從不同的位置來觀察一個人,比如下圖
模型(Modeling)變換
此時相機不動,人做移動,比如下圖
根據相對運動,可以看到視角(Viewing)變換和模型(Modeling)變換的效果是一樣的。
投影(Projection)變換
此時相機可以調整遠近距離,人不動,這樣觀察到的也會不一樣,比如下圖
視窗(Viewport)變換
按下快門之後,需要把像素按照比例轉化後顯示到屏幕上,這就是視窗(Viewport)變換,對應的就是
// Surface改變的的時候調用
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 設置窗口大小
gl.glViewport(0, 0, width , height);
}
二、視角(Viewing)變換和 模型(Modeling)變換操作
前面說了,這兩者產生的效果是一樣的,具體的有以下三種變換
- Translate 平移變換
- Rotate 旋轉變換
- Scale 縮放變換
平移變換
在平移變換之前,需調用以下代碼才能進行變換
//設置爲單位矩陣
gl.glLoadIdentity();
以上一篇繪製的三角形爲例子,沒移動前
調用glTranslatef(float x, float y, float z)方法進行平移
向右移動0.6f個x座標
//向右移動0.6f個x座標
gl.glTranslatef(0.6f, 0f, 0f);
效果
旋轉變換
調用glRotatef(float angle, float x, float y, float z)傳入4個參數,角度和x、y、z座標。此時一定要注意旋轉的角度,角度爲正表示逆時針。
PS:我發現可以用安培定則 來判斷旋轉方向,大拇指正對向量方向,捲曲手握着向量,手指彎曲的方向即爲要旋轉的方向。
//以(1f,0f,0f)空間向量旋轉60度
gl.glRotatef(60, 1f, 0f, 0f);
//以(1f,0f,0f)空間向量旋轉180度
gl.glRotatef(180, 1f, 0f, 0f);
縮放變換
調用glScalef(float x, float y, float z)進行縮放,三個參數爲縮放比例,
縮放之前的座標乘以縮放比例即可
比如:
//縮小爲原來0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);
效果:
組合變換
組合變換要注意順序,比如平移和縮放變換組合起來,先平移後縮放和先縮放後平移的效果是不一樣的。因爲每次變換所依賴的是當前矩陣
先縮放再平移
//縮小爲原來0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);
//向右移動0.6f個x座標
gl.glTranslatef(0.6f, 0f, 0f);
效果:
先平移再縮放
//向右移動0.6f個x座標
gl.glTranslatef(0.6f, 0f, 0f);
//縮小爲原來0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);
效果:
重置矩陣
如果想重置矩陣爲沒有任何變換之前,調用glLoadIdentity()
比如下面一段代碼就將矩陣重置到之前的矩陣
//向右移動0.6f個x座標
gl.glTranslatef(0.6f, 0f, 0f);
//縮小爲原來0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);
//重置矩陣
gl.glLoadIdentity();
效果圖:
保存、恢復矩陣
調用glPushMatrix保存當前矩陣,調用glPopMatrix恢復當前矩陣。
比如先保存矩陣,再重置矩陣,最後恢復矩陣,那麼矩陣沒改變。
//向右移動0.6f個x座標
gl.glTranslatef(0.6f, 0f, 0f);
//縮小爲原來0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);
//保存當前矩陣
gl.glPushMatrix();
//重置矩陣
gl.glLoadIdentity();
//恢復矩陣
gl.glPopMatrix();
效果圖
三、投影(Projection)變換操作
前面說了,投影(Projection)變換相當於相機調整遠近距離,人不動。
投影變換會定義一個視錐(viewing volume),視錐有兩個作用
- 物體如何投影到屏幕(透視投影或者正側投影)
- 裁剪場景的區域大小
OpenGL ES可以使用兩種不同的投影變換:透視投影(Perspective Projection)和正側投影(Orthographic Projection)。
透視投影(Perspective Projection)
透視投影 ,就像我們眼睛看一個物體,近大遠小。 如下圖
從照相機(View Point)望去,由left、top、bottom、right四條線組成的面(也就是near面)和最遠處的面(也就是far面)組成了一個椎體,這個椎體叫View volumn。
裁剪就是把Viewing Volume之外的都裁剪掉,這樣可以提高繪圖性能。
定義透視投影的方法如下,傳入6個參數
public void glFrustumf(float left,float right,float bottom,float top,float near,float far)
也可以用GLU.gluPerspective(fovy, aspect, zNear, zFar)方法,fovy是豎直方向也就是Y方向的夾角,aspect是near面的寬高比,即top的長度除以left長度。
後續會有例子來講如何用這個。
正側投影(Orthographic Projection)
透視投影 ,View Volumn椎體不變,一直是一個長方體,無論距離怎麼改變,投影都不變。
定義正側投影的方法如下,傳入6個參數
public void glOrthof(float left, float right,float bottom,float top,float near,float far)
四、視窗(Viewport)變換操作
就是上面寫的
按下快門之後,需要把像素按照比例轉化後顯示到屏幕上,這就是視窗(Viewport)變換,分兩步
- 設置窗口的位置和大小————glViewport(int x, int y, int width, int height)
- 設置觀察的位置和角度————GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)
設置窗口的位置和大小
這個之前講過,沒什麼好說的
// Surface改變的的時候調用
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 設置窗口大小
gl.glViewport(0, 0, width , height);
}
設置觀察的位置和角度
GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)
- eye理解爲照相機或者你的眼睛,默認位置在原點(0,0,0)
- center是觀察物體的座標,從eye到center的向量就是觀察的方向
- up默認爲Y軸正方向,可以理解爲眼睛到頭頂的方向,比如改成(0,-1,0)那就是倒立着觀察了
比如一個物體,默認gluLookAt座標
@Override
public void onDrawFrame(GL10 gl) {
......
GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f);
......
效果如下:
我改爲GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 1f, 0f, 0f);
即側着頭看,效果如下
五、結束
圖形的變換就介紹到這,下一篇講解如何給圖形添加顏色。