1. 程式人生 > >Android OpenGL ES 繪圖 -- 基礎元素

Android OpenGL ES 繪圖 -- 基礎元素

本文章為使用OpengGL繪製-點、線、面

準備工作在之前文章中已經介紹,本文直接繪圖
在 Android 系統中可以使用一個浮點數陣列來定義一個頂點,浮點數陣列通常放在一個 Buffer(java.nio)中來提高效能。

比如:下圖中定義了四個頂點和對應的 Android 頂點定義:

預設情況下,可視區域的四個頂點分別為v0(-1,1,0);v1(-1,-1,0)v2(1,-1,0);v3(1,1,0)(注:此座標有可能不為正方形)

        // 清除螢幕和深度快取
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
                GL10.GL_DEPTH_BUFFER_BIT);
         //建立點座標(x,y,z),每三個數為一組
float vertices[] = { -0.5f, 0.5f, 0.0f, // 0, Top Left -0.5f, -0.5f, 0.0f, // 1, Bottom Left 0.5f, -0.5f, 0.0f, // 2, Bottom Right 0.5f, 0.5f, 0.0f, // 3, Top Right };

為了提高效能,通常將這些陣列存放到 java.io 中定義的 Buffer 類中:

        ByteBuffer vbb = ByteBuffer.allocateDirect
(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); FloatBuffer vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0);

有了頂點的定義,下面一步就是如何將它們傳給 OpenGL ES 庫,OpenGL ES 提供一個成為”管道 Pipeline ”的機制,這個管道定義了一些“開關”來控制 OpenGL ES 支援的某些功能,預設情況這些功能是關閉的,如果需要使用 OpenGL ES 的這些功能,需要明確告知 OpenGL “管道”開啟所需功能。因此對於我們的這個示例,需要告訴 OpenGL 庫開啟 Vertex buffer 以便傳入頂點座標 Buffer。要注意的使用完某個功能之後,要關閉這個功能以免影響後續操作:

    //設定點的大小
        gl.glPointSize(5f);
        //開啟點座標管道
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    //傳入點座標
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    //根據點座標繪點
        gl.glDrawArrays(GL10.GL_POINTS, 0, vertices.length/3);
    //關閉點座標
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    }

OpenGL繪線,需根據點來繪製,以下示例中的點資料為上繪點的座標
新增繪線順序陣列

        short[] indices = { 0, 1, 
                            2, 0, 
                            2, 3 };

為了提高效能,通常將這些陣列存放到 java.io 中定義的 Buffer 類中:

        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        ShortBuffer indexBuffer = ibb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);

開始繪製

        //開啟點座標管道
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    //傳入點座標
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        //根據點與繪線順序繪線
        gl.glDrawElements(GL10.GL_LINES, indices.length,
                GL10.GL_UNSIGNED_SHORT, indexBuffer);
    //關閉點座標
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

其中GL10.GL_LINES:

  • GL_LINES
    頂點兩兩連線,為多條線段構成。

  • GL_LINE_STRIP
    繪製一系列線段。

  • GL_LINE_LOOP
    類同上,但是首尾相連,構成一個封閉曲線。

定義面的頂點的順序很重要 在拼接曲面的時候,用來定義面的頂點的順序非常重要,因為頂點的順序定義了面的朝向(前向或是後向),為了獲取繪製的高效能,一般情況不會繪製面的前面和後面,只繪製面的“前面”。雖然“前面”“後面”的定義可以應人而易,但一般為所有的“前面”定義統一的頂點順序(順時針或是逆時針方向)。
下面程式碼設定逆時針方法為面的“前面”:

gl.glFrontFace(GL10.GL_CCW);  

開啟 忽略“後面”設定:

gl.glEnable(GL10.GL_CULL_FACE);  

明確指明“忽略“哪個面的程式碼如下:

gl.glCullFace(GL10.GL_BACK);  

繪製面與繪製線差不多,同樣先決定繪製時的順序

        short[] indices = { 0, 1,
                            2, 0,
                            2, 3 };

為了提高效能,通常將這些陣列存放到 java.io 中定義的 Buffer 類中:

        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        ShortBuffer indexBuffer = ibb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);

開始繪製

        //開啟點座標管道
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    //傳入點座標
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        //根據點與繪線順序繪面
        gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
                GL10.GL_UNSIGNED_SHORT, indexBuffer);
    //關閉點座標
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

其中GL10.GL_TRIANGLES:

  • GL_TRIANGLES
    每隔三個頂點構成一個三角形,為多個三角形組成。

  • GL_TRIANGLE_STRIP
    每相鄰三個頂點組成一個三角形,為一系列相接三角形構成。

  • GL_TRIANGLE_FAN
    以一個點為三角形公共頂點,組成一系列相鄰的三角形。