Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android OpenGLES2.0(五)——繪制立方體

Android OpenGLES2.0(五)——繪制立方體

編輯:關於Android編程

上篇博客中我們提到了OpenGLES中繪制的兩種方法,頂點法和索引法。之前我們所使用的都是頂點法,這次繪制立方體使用索引法來繪制立方體。

構建立方體

上篇博客講到正方形的繪制,立方體是是由六個正方形組成,我們將這六個正方形繪制出來,立方體就繪制完畢了。既然選擇用索引法來繪制,立方體擁有八個頂點,我們先將這八個頂點列出來,放到一個數組中:

final float cubePositions[] = {
            -1.0f,1.0f,1.0f,    //正面左上0
            -1.0f,-1.0f,1.0f,   //正面左下1
            1.0f,-1.0f,1.0f,    //正面右下2
            1.0f,1.0f,1.0f,     //正面右上3
            -1.0f,1.0f,-1.0f,    //反面左上4
            -1.0f,-1.0f,-1.0f,   //反面左下5
            1.0f,-1.0f,-1.0f,    //反面右下6
            1.0f,1.0f,-1.0f,     //反面右上7
    };

正面由032和021兩個三角形組成,其他面諸如此類拆分,得到索引數組:

final short index[]={
            0,3,2,0,2,1,    //正面
            0,1,5,0,5,4,    //左面
            0,7,3,0,4,7,    //上面
            6,7,4,6,4,5,    //後面
            6,3,7,6,2,3,    //右面
            6,5,1,6,1,2     //下面
    };

如果使用單一顏色,最後繪制出來的立方體不方便看效果,所以我們來繪制多種顏色的立方體出來。定義各個頂點的顏色:

//八個頂點的顏色,與頂點坐標一一對應
float color[] = {
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
    };

繪制立方體

確定好立方體坐標和顏色後,我們需要創建頂點著色器和片元著色器,可使用與Android OpenGLES2.0(三)——等腰直角三角形和彩色的三角形中彩色三角形相同的頂點著色器和片元著色器。
接著其他的步驟與繪制三角形相同:

初始化坐標數據、索引數據、顏色數據,具體操作為將坐標數據、顏色數據分別寫入到獨自的FloatBuffer中,將索引數據寫入到ShortBuffer中 創建OpenGL2.0程序,將頂點著色器和片元著色器加入到程序中,並鏈接程序。 使用創建的OpenGLES2.0程序,寫入變換矩陣、頂點坐標數據及顏色數據。 索引法繪制出所有頂點坐標組成的三角形,得到一個立方體。

如果我們僅僅只做了以上事情,往往我們得不到一個正確的立方裡,反而會出現比較奇怪的立方體,比如這樣的:
這裡寫圖片描述

這是因為我們沒有開啟深度測試GLES20.glEnable(GLES20.GL_DEPTH_TEST),並在繪制前清除深度緩存導致GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT)的。
加入後,我們即可得到正常的立方體:
這裡寫圖片描述
openGL裡常出現深度測試,關於深度測試內容如下:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCTxwPjxjb2RlPjxjb2RlPqOoMaOpyrLDtMrHye62yKO/PGJyIC8+DQoJye62yMbkyrW+zcrHuMPP88vYtePU2jNkysC959bQvuDA68njz/O7+rXEvuDA66Oou+bWxtf4seqjqaOsye62yLu6tObW0LTmtKLXxcO/uPbP88vYteOjqLvm1sbU2sbBxLvJz7XEo6m1xMnutsjWtaOhPGJyIC8+DQoJye62yNa1o6ha1rWjqdS9tPOjrNTywOvJ48/xu/rUvdS2oaM8YnIgLz4NCgnJ7rbI1rXKx7Tm1vzU2snutsi7urTmwO/D5rXEo6zO0sPH08PJ7rbIu7q05rXEzrvK/cC0uuLBv8nutsi7urTmtcS+q7bIoaPJ7rbIu7q05s67yv3Uvbjfo6zU8r6ryLe2yNS9uN+jrMS/x7C1xM/Uv6jSu7Djtry/ydans9YxNs67tcRaIEJ1ZmZlcqOs0rvQqbjfvLa1xM/Uv6jS0b6tv8nS1Nans9YzMs67tcRaIEJ1ZmZlcqOstavSu7Dj08MyNM67WiBCdWZmZXK+zdLRvq3X47m7wcuhozxiciAvPg0KCaOoMqOpzqrKssO00OjSqsnutsijvzxiciAvPg0KCdTasrvKudPDye62yLLiytS1xMqxuvKjrMjnufvO0sPHz8i75tbG0ru49r7gwOu9z738tcTO78zlo6zU2bvm1sa+4MDrvc/UtrXEzu/M5aOs1PK+4MDr1La1xM7vzOXS8s6quvO75tbGo6y74bDRvuDA6738tcTO78zluLK4x7X0o6zV4tH5tcTQp7n7sqKyu8rHztLDx8v5z6PN+7XEoaO2+NPQwcvJ7rbIu7qz5dLUuvOjrLvm1sbO78zltcTLs9Dyvs2yu8THw7TW2NKqwcujrLa8xNywtNXV1La9/KOoWta1o6nV/bOjz9TKvqOs1eK63LnYvPyhozxiciAvPg0KCcq1vMrJz6Os1rvSqrTm1NrJ7rbIu7qz5cf4o6zO3sLbyse38cb008PJ7rbIsuLK1KOsT3BlbkdM1NrP8cvYsbu75tbGyrG2vLvhs6LK1L2rye62yMr9vt3QtMjrtb27urPlx/jE2qOss/23x7X308PBy2dsRGVwdGhNYXNrKEdMX0ZBTFNFKcC0vfvWudC0yOuho9Xi0KnJ7rbIyv2+3bP9wcvTw9Pas6O55rXEsuLK1M3io6y7ub/J0tTT0NK70KnT0MiktcTTw82+o6yxyMjnu+bWxtL107C1yLXIoaM8YnIgLz4NCgmjqDOjqcb008PJ7rbIsuLK1DxiciAvPg0KCcq508MgZ2xFbmFibGUoR0xfREVQVEhfVEVTVCk7PGJyIC8+DQoJ1NrErMjPx+m/9srHvavQ6NKqu+bWxrXE0MLP8cvYtcR61rXT68nutsi7urPlx/jW0LbU06bOu9bDtcR61rW9+NDQsci9z6OsyOe5+7HIye62yLu6tObW0LXE1rXQoaOsxMfDtNPD0MLP8cvYtcTR1cmr1rW4/NDC1qG7urTm1tC21NOmz/HL2LXE0dXJq9a1oaM8YnIgLz4NCgm1q8rHv8nS1Mq508NnbERlcHRoRnVuYyhmdW5jKcC0ttTV4tbWxKzIz7LiytS3vcq9vfjQ0NDeuMShozxiciAvPg0KCcbk1tCyzsr9ZnVuY7XE1rW/ydLUzqpHTF9ORVZFUqOow7vT0LSmwO2jqaGiR0xfQUxXQVlTo6i0psDty/nT0KOpoaJHTF9MRVNTo6jQodPao6mhokdMX0xFUVVBTKOo0KHT2rXI09qjqaGiR0xfRVFVQUyjqLXI09qjqaGiR0xfR0VRVUFMo6i089PatcjT2qOpoaJHTF9HUkVBVEVSo6i089Pao6m78kdMX05PVEVRVUFMo6iyu7XI09qjqaOsxuTW0MSsyM/WtcrHR0xfTEVTU6GjPGJyIC8+DQoJ0ruw48C0vaujrMq508NnbERlcHRoRnVuYyhHTF9MRVFVQUwpO8C0se2079K7sOPO78zl1q685LXE1dq1srnYz7WhozxiciAvPg0KCaOoNKOpxvTTw8HLye62yLLiytSjrMTHw7TV4r7NsrvKytPD09rNrMqxu+bWxrK7zbjD987vzOWhozwvY29kZT48L2NvZGU+PC9wPg0KPC9ibG9ja3F1b3RlPg0KPGgxIGlkPQ=="具體實現">具體實現

public class Cube extends Shape{

    private FloatBuffer vertexBuffer,colorBuffer;
    private ShortBuffer indexBuffer;
    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "uniform mat4 vMatrix;"+
                    "varying  vec4 vColor;"+
                    "attribute vec4 aColor;"+
                    "void main() {" +
                    "  gl_Position = vMatrix*vPosition;" +
                    "  vColor=aColor;"+
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "varying vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private int mProgram;

    final int COORDS_PER_VERTEX = 3;
    final float cubePositions[] = {
            -1.0f,1.0f,1.0f,    //正面左上0
            -1.0f,-1.0f,1.0f,   //正面左下1
            1.0f,-1.0f,1.0f,    //正面右下2
            1.0f,1.0f,1.0f,     //正面右上3
            -1.0f,1.0f,-1.0f,    //反面左上4
            -1.0f,-1.0f,-1.0f,   //反面左下5
            1.0f,-1.0f,-1.0f,    //反面右下6
            1.0f,1.0f,-1.0f,     //反面右上7
    };
    final short index[]={
            6,7,4,6,4,5,    //後面
            6,3,7,6,2,3,    //右面
            6,5,1,6,1,2,    //下面
            0,3,2,0,2,1,    //正面
            0,1,5,0,5,4,    //左面
            0,7,3,0,4,7,    //上面
    };

    float color[] = {
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            0f,1f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
            1f,0f,0f,1f,
    };

    private int mPositionHandle;
    private int mColorHandle;

    private float[] mViewMatrix=new float[16];
    private float[] mProjectMatrix=new float[16];
    private float[] mMVPMatrix=new float[16];

    private int mMatrixHandler;

    //頂點個數
    private final int vertexCount = cubePositions.length / COORDS_PER_VERTEX;
    //頂點之間的偏移量
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 每個頂點四個字節


    public Cube(View mView) {
        super(mView);
        ByteBuffer bb = ByteBuffer.allocateDirect(
                cubePositions.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(cubePositions);
        vertexBuffer.position(0);

        ByteBuffer dd = ByteBuffer.allocateDirect(
                color.length * 4);
        dd.order(ByteOrder.nativeOrder());
        colorBuffer = dd.asFloatBuffer();
        colorBuffer.put(color);
        colorBuffer.position(0);

        ByteBuffer cc= ByteBuffer.allocateDirect(index.length*2);
        cc.order(ByteOrder.nativeOrder());
        indexBuffer=cc.asShortBuffer();
        indexBuffer.put(index);
        indexBuffer.position(0);
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);
        //創建一個空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //將頂點著色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader);
        //將片元著色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader);
        //連接到著色器程序
        GLES20.glLinkProgram(mProgram);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //開啟深度測試
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //計算寬高比
        float ratio=(float)width/height;
        //設置透視投影
        Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
        //設置相機位置
        Matrix.setLookAtM(mViewMatrix, 0, 5.0f, 5.0f, 10.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        //計算變換矩陣
        Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT| GLES20.GL_DEPTH_BUFFER_BIT);
        //將程序加入到OpenGLES2.0環境
        GLES20.glUseProgram(mProgram);
        //獲取變換矩陣vMatrix成員句柄
        mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
        //指定vMatrix的值
        GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
        //獲取頂點著色器的vPosition成員句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //啟用三角形頂點的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准備三角形的坐標數據
        GLES20.glVertexAttribPointer(mPositionHandle, 3,
                GLES20.GL_FLOAT, false,
                0, vertexBuffer);
        //獲取片元著色器的vColor成員的句柄
        mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
        //設置繪制三角形的顏色
//        GLES20.glUniform4fv(mColorHandle, 2, color, 0);
        GLES20.glEnableVertexAttribArray(mColorHandle);
        GLES20.glVertexAttribPointer(mColorHandle,4,
                GLES20.GL_FLOAT,false,
                0,colorBuffer);
        //索引法繪制正方體
        GLES20.glDrawElements(GLES20.GL_TRIANGLES,index.length, GLES20.GL_UNSIGNED_SHORT,indexBuffer);
        //禁止頂點數組的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

源碼

所有的代碼全部在一個項目中,托管在Github上——Android OpenGLES 2.0系列博客的Demo

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved