資料來源:java
OpenGL ES3.0編程指南android
在opengl es中,圖元能夠用glDrawArrays()
,glDrawElements()
,glDrawRangeElements()
等命令繪製幾何圖像。圖元有一組表示頂點位置的頂點描述。git
圖元總共三部分:github
支持的三角形圖元有GL_TRIANGLES
,GL_TRIANGLE_STRIP
,GL_TRIANGLE_FAN
三種。現根據opengl官方的wiki整理以下:編程
- GL_TRIANGLES: Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on.
- GL_TRIANGLE_STRIP: Every group of 3 adjacent vertices forms a triangle. The face direction of the strip is determined by the winding of the first triangle. Each successive triangle will have its effective face order reversed, so the system compensates for that by testing it in the opposite way. A vertex stream of n length will generate n-2 triangles.
- GL_TRIANGLE_FAN: The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
GL_TRIANGLES
而言,就是直接繪製一系列的單獨的三角形,以以下圖形舉例,頂點V0,V1,V2組成一個三角形,頂點V3,V4,V5組成一個三角形。經過頂點數組能夠組成三角形的數目爲數組長度/3api
在Anroid中代碼:數組
Demo地址https://github.com/JerryChan123/LearnOEL/tree/gl30 查看test for gl_triangle的提交學習
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.5f, 0f, 0.0f, -0.5f, 0f, 0.0f, 0.0f, -0.622008459f, 0.0f, }; float color[] = { 1.0f, 0.0f, 0.0f,1f, 1.0f, 0.0f, 0.0f,1f, 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f}; public void onDraw() { // Add program to OpenGL ES environment GLES30.glUseProgram(mProgram); // get handle to vertex shader's vPosition member mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition"); // createVertextBuffer(); //注意,這裏註釋掉了VBO,是由於打開後有Bug,具體是什麼問題有待發現 // Enable a handle to th、e triangle vertices GLES30.glEnableVertexAttribArray(mPositionHandle); // Prepare the triangle coordinate data GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, vertexBuffer); // get handle to fragment shader's vColor member mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor"); // Set color for drawing the triangle // GLES30.glVertexAttrib4fv(mColorHandle, color, 0); GLES30.glEnableVertexAttribArray(mColorHandle); GLES30.glVertexAttribPointer(mColorHandle, 4, GLES30.GL_FLOAT, false, 0, colorBuffer); // Draw the triangle GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
效果圖以下:翻譯
GL_TRIANGLE_STRIP
而言,英文翻譯過來就是每一個小組的三個臨近的頂點組成一個三角形,一以下圖形舉例:
看見英文一大堆就暈了,其實簡單的就是V0,V1,V2組成一個三角形,V1,V2,V3組成一個三角形,V2,V3,V4組成一個三角形,以此類推。經過頂點數組能夠組成三角形的數目爲數組長度-2
Android代碼使用以下:
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.0f, -0.622008459f, 0.0f, }; private final int mProgram; // Set color with red, green, blue and alpha (opacity) values float color[] = { 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 0f, 1.0f,1f, 0f, 0.0f, 0.0f,1f}; public void onDraw() { ... GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
與上面代碼的區別主要是在GL_TRIANGLE_STRIP參數的設置以及頂點數組數目的改變。實現效果以下所示:
GL_TRIANGLE_FAN
而言,表示一個扇形的三角形組成,看底下的圖就能明白:
頂點V0爲圓點,呈扇形畫出,即V0,V1,V2一個三角形,V0,V2,V3一個三角形,以此類推。 Android代碼示例:
static float triangleCoords[] = { // in counterclockwise order: -0.5f, 0f, 0.0f, // bottom left 0.0f, 0.622008459f, 0.0f, // top 0.5f, 0f, 0.0f, // bottom right 0.0f, -0.622008459f, 0.0f, }; private final int mProgram; // Set color with red, green, blue and alpha (opacity) values float color[] = { 1.0f, 0.0f, 0.0f,1f, 0f, 1.0f, 0.0f,1f, 0f, 0f, 1.0f,1f, 0f, 0.0f, 0.0f,1f}; public void onDraw() { .... GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); }
主要就是GL_TRIANGLE_FAN的設置以及數組位置的改變。實現效果與GL_TRIANGLE_STRIP相同。
opengl es中支持的直線有GL_LINES
,GL_LINE_STRIP
,GL_LINE_LOOP
三大類,三個變量的區別以下圖所示:
n指的是直線頂點數組的長度
比較簡單就不舉例子了。
點精靈是針對頂點進行繪製。點精靈一般將粒子效果做爲點而非正方形繪製,從而實現高效渲染。點精靈是指定位置和半徑的屏幕對齊的正方形,位置描述正方形的中心,半徑用於計算點精靈的四個角座標。
注意opengles窗口的座標範圍是:從左下角(原點)到右上角。
而點精靈的原點是在左上角 座標值 從0-1.
gl_PointSize()
是可用於在頂點着色器輸出點半徑的內建變量。與點圖元相關的頂點着色器輸出gl_PointSize很重要,不然,會被視爲未定義,極可能會形成繪圖錯誤。頂點着色器的輸出gl_PointSize收到opengl es 3.0實現所支持的非平滑點尺寸範圍的限制,能夠用以下命令查詢:
GLfloat pointSizeRange[2]; glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE,pointSizeRange); //android中的表示 GLES30.glGetFloatv();
gl_PointCoord
是隻能在渲染圖元爲點精靈的時候用於片斷着色器的內部建量。他用一個mediump精度限定符申明爲一個vec2變量。gl_PointCoord屬於區間[0,1],超出的則不顯示。
圖元總共有五個繪製方法:
在Android中只支持第一種跟第二種,Android native層有待考證支持的類型。
glDrawArrays用元素索引爲first到first+count-1的元素指定的頂點繪製mode指定的圖元。 查看上述使用GL_TRIANGLES
寫Demo的例子中的使用:
static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, 0f, 0.0f, // bottom left 0.5f, 0f, 0.0f, // bottom right 0.5f, 0f, 0.0f, -0.5f, 0f, 0.0f, 0.0f, -0.622008459f, 0.0f, }; GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);//vertexCount=6
first等於0,first+count-1=5,因此取(0,1,2)和(3,4,5)做爲兩個三角形的頂點進行繪製。支持的model就是咱們上面鎖講述的一系列幾何類型。
若是是一系列順序元素索引描述的圖元,且幾何圖形頂點不共享,那麼glDrawArrays
是能支持的也很好用,可是遊戲或者其餘3D的應用程序的典型對象由多個三角形網格組成,其中元素不必定按照順序,頂點一般在網格的三角形之間共享。使用glDrawElements能夠比調用glDrawArrays更簡單的將這些功能實現,並且內存消耗更小。
###圖元裝配
經過上述的glDraw*提供的頂點由頂點着色器執行,頂點着色器變換每一個頂點的頂點位置。圖元類型和頂點索引肯定將被渲染的單獨圖元。對於每一個單獨圖元與其對應的頂點,裝配過程如上圖所示。
下圖中展現了經過頂點着色器和圖元裝配後的座標系統:
頂點以物體或者本地座標空間輸入到opengl es中,在頂點着色器執行完後,頂點位置是被認爲執行在裁剪空間以內的。頂點位置從本地座標系統到裁剪座標的變換經過加載執行對應矩陣來完成。
關於opengl es中的座標系統須要單獨寫一篇文章。下面只是記錄書中的內容
####裁剪 裁剪座標的意義在於將判斷頂點是否落在裁剪座標空間內。裁剪座標是由(x,y,z,w)指定的同類座標,在裁剪空間(x,y,z,w)中定義的頂點座標根據視景體(又稱裁剪體)裁剪。 視景體由六個平面組成而成,這些平面被稱做遠,近,左,右,上,下裁剪平面,在裁剪座標中,裁剪體以下:
裁剪體以下所示:
####透視分割 透視分割取得裁剪座標(x,y,z,w)指定的點,並將其投影到屏幕或者視口上。這個操做經過將(x,y,z)除以w進行,執行(x/w),(y/w),(z/w)操做以後,獲得規範化的設備座標(q,w,e),他們落在[-1.0,1.0]中,這些座標會根據視口大小轉換成真正的屏幕座標。規範化的z座標可使用glDepthRangf()
指定的near和far深度值轉換成屏幕的z值,這些轉換在視口變換時候進行。
####視口變換 視口是一個二維矩形窗口區域,是全部opengl es渲染最終顯示的地方,可調用以下api進行設置:
void glViewport(GLint x,GLint y,GLsizei w,Glsizei h)
從規範化座標(x,w,z)到窗口座標(q,w,e)的轉換變化以下:
上述變化中Ox=x+w/2,Oy=y+h/2,n和f表明所須要的深度範圍,可以使用glDepthRangf()
設置。