Android OpenGL ES學習筆記之圖形變換

一、概念

在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);

即側着頭看,效果如下

這裏寫圖片描述


五、結束

圖形的變換就介紹到這,下一篇講解如何給圖形添加顏色。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章