【附源碼】【Android 3D OpenGL】開發之四——投影中的正交與透視【MacroCheng原創】

【附源碼】【Android 3D OpenGL】開發之四——投影中的正交與透視【MacroCheng原創】

一、正交與透視

1.1、正交Orthographic (無消失點投影)

正交視圖無法看到一個物體是遠離自己還是正在我們面前。爲什麼?因爲它不會根據距離收縮。所以如果你如果你畫一個固定大小的物體在視點前面,同時畫一個同樣大小的物體在第一個物體的遠後方,你無法說那個物體是第一個。因爲兩個都是一樣的大小,根距離無關。他們不會隨着距離而收縮。

1.2、透視Perspective (有消失點投影)

    透視視圖和我們從眼睛看到的視圖是一樣的。例如,一個高個子的人站在你面前,你看上去是很高的。如果這個人站在100米以外,他甚至還沒有你的拇指大。他看上去會隨着距離而縮小,但是我們實際上都知道,它依然是個高個子。這種效果叫做透視。上面例子中提到的兩個物體,第二個物體將會顯示地更小,所以我們可以區分哪個是離我們近的物體,那個是離我們遠的物體。

 

二、關鍵方法說明

2.1、glMatrixMode(GL_PROJECTION)

指明接下來的兩行代碼將影響projection matrix(投影矩陣)。投影矩陣負責爲我們的場景增加透視。

2.2、glMatrixMode(GL_MODELVIEW)

指明任何新的變換將會影響 modelview matrix(模型觀察矩陣)。模型觀察矩陣中存放了我們的物體訊息。

2.3、gl.glOrthof()

    設置我們的視點來做orthographic view。這些參數是爲邊界設定,順序是這樣的:left, right, bottom, top, zNear, zFar

2.4glFrustumf()

    glFrustumf()函數的參數和glOrthof()的參數略有不同。因爲我們沒有縮小物體,但是我們定義的錐體將被漏斗狀切開。

 

三、正交和透視效果對比

3.1、正交圖片

跟只有一個金字塔看起來效果是一摸一樣的,但是其實我們有建立10個金字塔的,看下面透視效果就知道了。

3.2、正交的核心語句

gl.glOrthof(-1,1,-1/ratio,1/ratio,0.01f,100.0f);

//gl.glFrustumf(-size, size, -size / ratio, size / ratio, 0.01f, 100.0f);

3.3、透視圖片

3.4、透視核心語句

//gl.glOrthof(-1,1,-1/ratio,1/ratio,0.01f,100.0f);

gl.glFrustumf(-size, size, -size / ratio, size / ratio, 0.01f, 100.0f);

 

四、OpenGLRenderer.java

因爲其他的都沒動,就動了這個類,所以僅貼出這個類得代碼

package com.macrocheng.opengl3d01;

 

import javax.microedition.khronos.egl.EGLConfig;

import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;

 

public class OpenGLRenderer implements GLSurfaceView.Renderer {

    private static final String LOG = OpenGLRenderer.class.getSimpleName();

    private float red = 0.9f;

    private float green = 0.2f;

    private float blue = 0.2f;

   

    private Triangle tr;

   

    private float xAngle;

    private float yAngle;

   

    private Pyramid py;

   

    private float _width = 320f ;

    private float _height = 480f ;

   

    @Override

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        // TODO Auto-generated method stub

        //tr = new Triangle();

        /**

         * 指明接下來的兩行代碼將影響projection matrix(投影矩陣)。

         * 投影矩陣負責爲我們的場景增加透視。

         */

        gl.glMatrixMode(GL10.GL_PROJECTION);

       

        float size = 0.01f*(float)Math.tan(Math.toRadians(45.0)/2);

        float ratio = _width/_height;

        gl.glOrthof(-1,1,-1/ratio,1/ratio,0.01f,100.0f);

        //gl.glFrustumf(-size, size, -size / ratio, size / ratio, 0.01f, 100.0f);

        gl.glViewport(0, 0, (int)_width, (int)_height);

        /**

         * 指明任何新的變換將會影響 modelview matrix(模型觀察矩陣)。

         * 模型觀察矩陣中存放了我們的物體訊息。

         */

        gl.glMatrixMode(GL10.GL_MODELVIEW);

        /**

         * 這使OpenGL ES檢查對象的z-order。

         * 如果我們沒有enable它,我們將看到最後被繪製的對象一直顯示在最前面。

         * 這意味着,及時即使這個物體本來應該被更近更大的物體遮蓋,我們依然可以看到它。

         */

        gl.glEnable(GL10.GL_DEPTH_TEST);

       

        py = new Pyramid();

        /**

         * 決定哪一面可見,讓正面可見

         */

        gl.glEnable(GL10.GL_CULL_FACE);

        /**

         * 逆時針方向的面爲前面,前面就被畫出來

         */

        gl.glFrontFace(GL10.GL_CCW);

        /**

         * 後面就不需要被畫出來

         */

        gl.glCullFace(GL10.GL_BACK);

       

        /**

         * 設置OpenGL使用vertex數組來畫

         */

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

        /**

         * 設置顏色來自數組

         */

        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);       

    }

   

    @Override

    public void onSurfaceChanged(GL10 gl, int width, int height) {

        // TODO Auto-generated method stub

        _width = width;

        _height = height;

        gl.glViewport(0, 0, width, height);

    }

   

    @Override

    public void onDrawFrame(GL10 gl) {

        // TODO Auto-generated method stub

        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        /**

         * 爲了讓顏色變化可見,我們必須調用glClear()以及顏色緩衝的Mask來清空buffer,

         * 然後爲我們的底色使用新的底色。

         */

        //gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

       

        /**

         * 我們通過glClearColor()方法爲底色定義了顏色。

         * 底色是在我們能看到的所有東西的後面,所以所有在底色後面的東西都是不可見的。

         * 可以想象這種東西爲濃霧,擋住了所有的東西。

         */

        gl.glClearColor(red, green, blue, 1.0f);

       

        //清除顏色的Buffer然後讓現實上面我們通過glClearColor來定義的顏色

        for(int i=0;i<10;i++)

        {

            /**

             *  重置當前的模型觀察矩陣

             *  近似於重置。它將所選的矩陣狀態恢復成其原始狀態

             */

            gl.glLoadIdentity();

            gl.glTranslatef(0.0f, -1f, -1.0f + -1.5f * i);

            /**

             * 旋轉,四個參數分別是旋轉度、x軸、y軸、z軸

             * 後面三個值來決定圍繞那個軸線來旋轉

             */

            gl.glRotatef(xAngle, 1f, 0f, 0f);

            gl.glRotatef(yAngle, 0f, 1f, 0f);

            /**

             * 第一個參數是大小,也是頂點的維數。我們使用的是x,y,z三維座標。

             * 第二個參數,GL_FLOAT定義buffer中使用的數據類型。

             * 第三個變量是0,是因爲我們的座標是在數組中緊湊的排列的,沒有使用offset。

             * 最後,第四個參數頂點緩衝。

             */

            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, py.getVertexBuffer());

            /**

             * 參數4表示RGBA(RGBA剛好是四個值),其餘的幾個參數大家都比較熟悉了。

             */

            gl.glColorPointer(4, GL10.GL_FLOAT, 0, py.getColorBuffer());

            /**

             * 將所有這些元素畫出來。第一個參數定義了什麼樣的圖元將被畫出來。

             * 第二個參數定義有多少個元素,

             * 第三個是indices使用的數據類型。

             * 最後一個是繪製頂點使用的索引緩衝。

             */

            gl.glDrawElements(GL10.GL_TRIANGLES, py.getNumberOfPoint(), GL10.GL_UNSIGNED_SHORT, py.getIndexBuffer());

        }

    }

   

    public float getXAngle() {

        return xAngle;

    }

 

    public float getYAngle() {

        return yAngle;

    }

 

    public void setYAngle(float angle) {

        yAngle = angle;

    }

 

    public void setXAngle(float angle) {

        xAngle = angle;

    }

 

    /**

     * 設置顏色的值

     * @param r Red值

     * @param g Green值

     * @param b Blue值

     */

    public void setColor(float r,float g,float b)

    {

        red = r;

        green = g;

        blue = b;

    }

   

    /**

     * 設置三角形的旋轉度

     * @param x x軸上的旋轉度

     * @param y y軸上的旋轉度

     */

    public void setAngle(float x,float y)

    {

        xAngle = x;

        yAngle = y;

    }

}

 

 

源碼下載地址

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