原文連結:http://docs.eoeandroid.com/training/graphics/opengl/draw.html
用OpenGL定義好要繪製的形狀後,你就可能想把他們繪製在螢幕上。基於OpenGL ES 2.0繪製這些形狀,需要的代碼量比你想象中要多一點,這是因為2.0的API提供了大量對於映像渲染管道的控制。 這節課將會介紹如何使用OpenGL ES 2.0的API繪製你在前一節課定義好的形狀。
初始化形狀
在你製圖之前,你必須初始化和載入你計劃要繪製的形狀。你要在記憶體和處理速率的渲染器中的onSurfaceCreated()方法對形狀初始化,除非在程式執行的過程中,形狀的結構原始座標)發生了變化。
12345678 |
public void onSurfachttp://wiki.eoeandroid.com/Drawing_ShapeseCreated(GL10 unused, EGLConfig config) { ... // initialize a triangle mTriangle = new Triangle(); // initialize a square mSquare = new Square(); } |
繪製形狀
使用OpenGL ES 2.0繪製形狀需要大量的代碼,因為你需要提供大量的映像渲染器管道的細節。具體地,你需要定義: * 頂點著色器Vertex Shader) - OpenGL ES映像中渲染形狀頂點的代碼 * 片斷著色器Fragment Shader) - OpenGL ES渲染形狀表面顏色與紋理的代碼 * 程式Program) - 包含了你想要用來繪製形狀的著色器的OpenGL ES對象 你需要至少一個頂點著色器來繪製映像,一個片斷著色器去給映像著色。這些著色器必須被定義和添加到一個OpenGL ES程式中,它將會在繪製形狀時被用到。下面是一個基本的定義著色器的例子:
1 2 3 4 5 6 7 8 9101112 |
private final String vertexShaderCode = "attribute vec4 vPosition;" + "void main() {" + " gl_Position = vPosition;" + "}"; private final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}"; |
包含了OpenGL著色語言GLSL)的著色器在被OpenGL ES環境使用之前,必須先被定義。你可以在渲染類中建立一個實用的方法來定義這些著色器:
1 2 3 4 5 6 7 8 9101112 |
public static int loadShader(int type, String shaderCode){ // create a vertex shader type (GLES20.GL_VERTEX_SHADER) // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // add the source code to the shader and compile it GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } |
為了繪製形狀,你必須編寫著色器的代碼,並把它們添加到OpenGL ES程式對象中,與程式串連起來。你可以在繪製對象的構造器做這些事情,這樣它就會只運行一次。
備忘:定義OpenGL ES著色器並於程式串連,需要消耗大量的CPU周期和處理時間,所以你要避免重複做這個動作。如果你想要擷取執行期間著色器的內容,你可以在建立代碼使它們只建立一次,並儲存起來在後面用。
1 2 3 4 5 6 7 8 91011 |
public Triangle() { ... int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables } |
事情進展到此,你可以在實際中調用繪製圖形方法了。使用OpenGL ES製圖時,需要你指定幾個參數,來告訴渲染器管道要畫什麼和怎樣畫。既然形狀會影響到繪製的情況,所以最好的辦法就是給形狀類添加它們各自的邏輯。 可以建立draw()的方法來繪製形狀。下面的例子就設定了形狀的頂點著色器的位置和片段著色器的顏色值,然後就執行繪製的函數方法。
1 2 3 4 5 6 7 8 9101112131415161718192021222324252627 |
public void draw() { // Add program to OpenGL ES environment GLES20.glUseProgram(mProgram); // get handle to vertex shader's vPosition member mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); // Enable a handle to the triangle vertices GLES20.glEnableVertexAttribArray(mPositionHandle); // Prepare the triangle coordinate data GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); // get handle to fragment shader's vColor member mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); // Set color for drawing the triangle GLES20.glUniform4fv(mColorHandle, 1, color, 0); // Draw the triangle GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // Disable vertex array GLES20.glDisableVertexAttribArray(mPositionHandle); } |
只要你代碼齊全,你只需要調用渲染器 onDrawFrame()方法中的draw()方法來繪製映像。當應用程式運行起來時,應該會得到以下這樣的結果:
圖1.沒有使用到投影和攝影視圖的三角形繪製
以上代碼中還是存在一些問題。第一,它不會帶給你朋友很深的影響;第二,當你改變手機裝置的螢幕方向時,這三角形會被壓扁,改變形狀,這是因為所繪製對象的定點座標沒有根據GLSurfaceView螢幕顯示的比例設定好,下節課的使用投影和攝影視圖可以解決這個問題;最後,這三角形是不動的,讓人覺得沒勁,在Adding_Motion這節課,你可以讓形狀旋轉,將會接觸到OpenGL ES映像管道的更多有趣的用法。