第二課 你的第一個多邊形:
在第一個教程的基礎上,我們添加了一個三角形和一個四邊形。也許你認為這很簡單,但你已經邁出了一大步,要知道任何在OpenGL中繪制的模型都會被分解為這兩種簡單的圖形。
讀完了這一課,你會學到如何在空間放置模型,並且會知道深度緩存的概念。
其他類不變,只更改OpenGLRenderer類。
首先,我們畫一個三角形,主要是在OnDrawFrame里面畫,使用的函數是
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
或者
gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_FLOAT, mIndexBuffer);
我們先使用drawArray,drawElement里面要多用一個indexBuffer。
第一步,定義個array
private float[] mTriangleArray = { 0f, 1f, 0f, // 是上頂點 -1f, -1f, 0f, // 左下頂點 1f, -1f, 0f // 右下頂點 };
這里實際上是定義了三角形的三個頂點,三個數分別是x,y,z的坐標,和數學里直角坐標系相同
0f, 1f, 0f 是上頂點
-1f, -1f, 0f 是左下頂點
1f, -1f, 0f 是右下頂點
定義個FloatBuffer,這是android畫三角形必須的結構
private FloatBuffer mTriangleBuffer;
來一個函數轉換array到Buffer
我們直接上一個工具類
BufferUtil類:
import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; public class BufferUtil { public static FloatBuffer mBuffer; public static FloatBuffer floatToBuffer(float[] a) { // 先初始化buffer,數組的長度*4,因為一個float占4個字節 ByteBuffer mbb = ByteBuffer.allocateDirect(a.length * 4); // 數組排序用nativeOrder mbb.order(ByteOrder.nativeOrder()); mBuffer = mbb.asFloatBuffer(); mBuffer.put(a); mBuffer.position(0); return mBuffer; } }
注意:這里有個排序的問題,是使用大端(BIG_ENDIAN)還是用小端(LITTLE_ENDIAN),在android里面,opengl畫圖must use native order direct buffer,否則報錯為ERROR/AndroidRuntime(6897): java.lang.IllegalArgumentException: Must use a native order direct Buffer這個錯誤在android1.6以上會出現,在1.5上不會出現。
這里我們直接使用allocateDirect和nativeOrder,就能滿足android的要求
第二步:
在SurfaceCreate里面構建這個Buffer
mTriangleBuffer = BufferUtil.floatToBuffer(mTriangleArray);
第三步:
在OndrawFrame里面畫三角形
// 利用數組模型來畫模型,要加此句(原文中沒有) gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 三角形的顏色為紅色,透明度為不透明 gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 設置頂點,第一個參數是坐標的維數,這里是3維,第二個參數,表示buffer里面放的是float,第三個參數是0, // 是因為我們的坐標在數組中是緊湊的排列的,沒有使用offset,最后的參數放的是存放頂點坐標的buffer gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mTriangleBuffer); // 畫數組,第一個參數表示畫三角形,第二個參數是first,第三個參數是count,表示在buffer里面的坐標的開始和個數 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
運行,會看到一個大三角形
下面,我們來變換坐標軸,畫個小三角形,原理就是把坐標軸向遠拉,意思就是讓鏡頭向后拉,這樣三角形就小了。
第一步:
在onSurfaceChanged(原文是OnSurfaceCreate,有錯誤)里面加入下面幾行代碼
float ratio = (float) width / height; gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
這幾行為透視圖設置屏幕。意味着越遠的東西看起來越小。這么做創建了一個現實外觀的場景。此處透視按照基於窗口寬度和高度的45度視角來計算。0.1f,100.0f是我們在場景中所能繪制深度的起點和終點。
gl.glMatrixMode(GL10.GL_PROJECTION);指明接下來的兩行代碼將影響projection matrix(投影矩陣)。投影矩陣負責為我們的場景增加透視。
glLoadIdentity()近似於重置。它將所選的矩陣狀態恢復成其原始狀態。調用 glLoadIdentity()之后我們為場景設置透視圖。
glMatrixMode(GL_MODELVIEW)指明任何新的變換將會影響 modelview matrix(模型觀察矩陣)。模型觀察矩陣中存放了我們的物體訊息。最后我們重置模型觀察矩陣。如果您還不能理解這些術語的含義,請別着急。在以后的教程里,我會向大家解釋。只要知道如果您想獲得一個精彩的透視場景的話,必須這么做。
第二步:
在OndrawFrame里面增加代碼如下:
gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置當前的模型觀察矩陣。 gl.glLoadIdentity(); // 沿着X軸左移1.5個單位,Y軸不動(0.0f),最后移入屏幕6.0f個單位 gl.glTranslatef(-1.5f, 0.0f, -6.0f);
當您調用glLoadIdentity()之后,您實際上將當前點移到了屏幕中心,X坐標軸從左至右,Y坐標軸從下至上,Z坐標軸從里至外。OpenGL屏幕中心的坐標值是X和Y軸上的0.0f點。中心左面的坐標值是負值,右面是正值。移向屏幕頂端是正值,移向屏幕底端是負值。移入屏幕深處是負值,移出屏幕則是正值。
glTranslatef(x, y, z)沿着 X, Y 和 Z 軸移動。根據前面的次序,下面的代碼沿着X軸左移1.5個單位,Y軸不動(0.0f),最后移入屏幕6.0f個單位。注意在glTranslatef(x, y, z)中當您移動的時候,您並不是相對屏幕中心移動,而是相對與當前所在的屏幕位置。
這時候就能畫出個小三角形了。
下面,我們來畫一個四邊形
四邊形的頂點數組為:
// 四邊形的頂點數組 private float[] mQuadsArray = { 1f, 1f, 0f, // 右上 -1f, 1f, 0f, // 左上 -1f, -1f, 0f, // 左下 1f, -1f, 0f // 右下 }; // 從這里可以看出,我們按照逆時針的方向畫圖 private FloatBuffer mQuadsBuffer;
在OnDrawFrame里面添加代碼
gl.glLoadIdentity(); // 坐標向右移1.5個單位 gl.glTranslatef(1.5f, 0.0f, -6.0f); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mQuadsBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4); // 畫四邊形
在onSurfaceCreated里面添加代碼
mQuadsBuffer = BufferUtil.floatToBuffer(mQuadsArray);
第一個參數是繪圖模式,而且你現在看到兩種可能的OpenGL繪圖方式。 我想花時間來討論現在不同的繪圖模式。
它們是:
GL_POINTS
GL_LINES
GL_LINE_LOOP
GL_LINE_STRIP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
我們還沒有討論點或線,所以我只介紹最后的三個 。在我開始之前,我要提醒你,頂點數組可能包含不止一個三角形,以便當您只看到一個物體頂點數組,你要知道,不僅限於這一點。
GL_TRIANGLES - 這個參數意味着OpenGL使用三個頂點來組成圖形。所以,在開始的三個頂點,將用頂點1,頂點2,頂點3來組成一個三角形。完成后,在用下一組的三個頂點來組成三角形,直到數組結束。
GL_TRIANGLE_STRIP - OpenGL的使用將最開始的兩個頂點出發,然后遍歷每個頂點,這些頂點將使用前2個頂點一起組成一個三角形。所以第三個點與第一個,第二個生成一個三角形。第四個點將於第二個,第三個生成三角形。
也就是說,0,1,2這三個點組成一個三角形,1,2,3這三個點也組成一個三角形。
GL_TRIANGLE_FAN - 在跳過開始的2個頂點,然后遍歷每個頂點,讓OpenGL將這些頂點於它們前一個,以及數組的第一個頂點一起組成一個三角形。 第3個點將與 第二個點(前一個)和第一個點(第一個).生成一個三角形。
也就是說,同樣是0,1,2,3這4個頂點。
在STRIP狀態下是,0,1,2;1,2,3這2個三角形。
在FAN狀態下是,0,1,2;0,2,3這2個三角形。
這次我們將使用 GL_TRIANGLE_FAN ,我們將在顯示區域獲得一個矩形。
(注:本教程轉自其他網頁,並加以修改,查看原網頁請點擊這里)