Opengl ES----glDrawArray和glDrawElements

花了四天的時間, 把一款FPS遊戲引擎Fly3D 轉到OpenGL ES上, 衆所周知, ES是面向移動設備的, 所以,爲了效率,它對OpenGL進行了很多的篩減, 把一些沒有效率的函數如(glBegin)全部扔掉了, 一些繪製的類型如GL_POLYGON也拋掉了,

這裏跟大家分享一下, 使用glDrawArray繪製POLYGON的替代方法
以及glDrawElements繪製三角形網格時出現的問題.

glDrawArray(GL_POLYGON,index,nvert), 這是在OpenGL下繪製一個多邊形的方法, 第三個參數是點數目, 第二個是當前多邊形點的索引(標號), 該函數會從數組中找到第index個點, 向後找到nvert個, 用這些點來點點依次相連繪製成多邊形,

但在OpenGL ES下,對不起, 用不起來了, 只能繪製三角形, 所以, 要想繪製原來的多邊形, 你只能先對這個多邊形進行三角剖分(如Delaunay, 當然,如果這樣做,可能太傻了,  因爲在Fly3D中, 這些數據本來就是三角形存在的, 只是爲了方便, 我們把它導成了多邊形而已).

拿四邊形舉例, 數據在導出時,原來我們導出了四個點(v1,v2,v3,v4),
現在, 我們要把它拆分成兩個三角形, 導出時變成(v1,v2,v3),(v1,v3,v4),
繪製的時候,
glDrawArray(GL_TRIANGLES,index,6) ;//6個點,兩個三角形
這樣就行了.

glDrawElements:
這個函數要注意, 在OpenGL下,我們用的多的是:

glDrawElements(GL_TRIANGLES,ntrivert,GL_UNSIGNED_INT,trivert);
第一個參數是類型
第二個點數目
第三個指的是第四個參數的類型
第四個參數是三角形的索引數據,值爲頂點數組的索引,標誌了頂點數組中頂點繪製的順序

可以這麼理解, 拿四邊形來舉例,有點(v1,v2,v3,v4)保存在數組中, 第二個參數就是4,即有4個頂點數據,
這四個頂點數據如何組成兩個三角形呢? trivert事實上就是一個索引數組, 它的數目應該是6個,每個值記錄着對應四邊形數據中的某個點.如trivert[0]=0, trivert[1]=1,trivert[2]=3,即第一個三角形是使用(v1,v2,v4)來構成

說的都是廢話,大家應該知道,  我要說的是, 這裏要注意第三個參數,GL_UNSIGNED_INT在OpenGL ES下已經不支持了, 現在只支持: GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT這兩個參數, 我想不用說也知道,INT點4個字節, BYTE佔一個,SHORT佔兩個, 能省就省吧,

所以, 大家一定要注意trivert這個索引數組的類型, 必須爲GluByte或GluShort

 
#########################################################################
OpenGL API glDrawElements收藏
glDrawElements是一個OPENGL的圖元繪製函數,從數組中獲得數據渲染圖元。
函數原型爲:
void glDrawElements( GLenummode, GLsizei count,
                   GLenum type, const GLvoid *indices);

                 
其中:
mode指定繪製圖元的類型,它應該是下列值之一,GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,        GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP,GL_QUADS, and GL_POLYGON.
count爲繪製圖元的數量。
type爲索引值的類型,只能是下列值之一GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT。
indices:指向索引存貯位置的指針。

glDrawElements函數能夠通過較少的函數調用繪製多個幾何圖元,而不是通過OPENGL函數調用來傳遞每一個頂點,法線,顏色信息。你可以事先準備一系列分離的頂點、法線、顏色數組,並且調用一次glDrawElements把這些數組定義成一個圖元序列。當調用glDrawElements函數的時候,它將通過索引使用count個成序列的元素來創建一系列的幾何圖元。mode指定待創建的圖元類型和數組元素如何如來創建這些圖元。但是如果GL_VERTEX_ARRAY沒有被激活的話,不能生成任何圖元。被glDrawElements修改的頂點屬性在glDrawElements調用返回後的值具有不確定性,例如,GL_COLOR_ARRAY被激活後,當glDrawElements執行完成時,當前的顏色值是沒有指定的。沒有被修改的屬性值保持不變。
可以在顯示列表中包含glDrawElements,當glDrawElements被包含進顯示列表時,相應的頂點、法線、顏色數組數據也得進入顯示列表的,因爲那些數組指針是ClientSideState的變量,在顯示列表創建的時候而不是在顯示列表執行的時候,這些數組指針的值影響顯示列表。glDrawElements只能用在OPENGL1.1或者更高的版本。

OpenGL快速渲染函數glDrawElements使用說明

OpenGL基本的繪圖函數例如glVertex、glNormal等在調試模式下運行時,如果模型的頂點數或者三角面數過大(比如超過一萬時),則程序運行速度會非常慢,根本就無法進行正常的調試。爲此查閱了相關資料,找到glArrayElement、glDrawElements這兩個個函數。這兩個函數都能通過少數幾條語句的調用實現大量數據的繪製,從而節省了函數調用的資源佔用。
 
glArrayElement函數用法簡單直接,只要把所有的頂點、法向量等數據,按照三角形的順序準備好,就可以直接渲染,但缺點是不支持頂點索引,所以內存佔用比較大。舉例來說,如果一個網格有100個頂點,一般大約會有200個三角面,如果使用glArrayElement就需要存儲200×3=600個頂點的數據,相比原有的數據多了5倍。如果是已經條帶化的數據,這種冗餘數據多的可能就不只5倍了。權衡之下還是決定使用glDrawElements函數。
 
glDrawElements函數支持頂點數據列表,更爲方便的是它還支持頂點索引,所以就成爲了快速渲染的首選。可是我在具體使用過程中,卻總是沒有任何頂點數據被繪製出來,查了相關資料,既不是數據錯誤,也不是硬件不支持,只好暫時擱置一邊了。一個偶然的機會,我看到某段示例代碼,發現glDrawElements中索引數據類型的參數是GL_UNSIGNED_INT,而我之前用的參數都是GL_INT(因爲算法的需要,有時需要存儲負數索引,以表示正反方向的不同)。抱着試試看的想法,我把參數改成了GL_UNSIGNED_INT,結果竟然繪製出圖像來了。趕緊查閱了MSDN,對glDrawElements的說明如下:
void glDrawElements(
  GLenum
mode,
  GLsizei
count,
  GLenum
type,
  const GLvoid
*indices
);

Parameters

mode
The kind of primitivesto render. It can assume one of the following symbolic values:GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, and GL_POLYGON.
count
The number of elements to be rendered.
type
The type of the values in indices. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
indices
A pointer to the location where the indices are stored.
注意其中對type參數的說明,索引數據的類型必須是GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT之一。這一來就解釋了爲什麼glDrawElements沒有繪製出任何元素的問題所在了。可氣的是OpenGL竟然沒有對這個問題給出任何的提示,不知到是不是微軟有意如此淡化OpenGL的作用,如果改天有機會可以用linux系統下的編譯器作作測試。
 
最後,附上我在渲染時調用的部分代碼。
 
//頂點
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, (float*)m_vDataCoord[0]);
 
// 法向量
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, (float*)m_vDataNormal[0]);
 
//頂點顏色
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, (float*)m_vDataColor[0]);
 
//紋理座標
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, (float*)m_vDataUv[0]);
glDrawElements(GL_TRIANGLES, (GLsizei)m_vIndexCoord.size()*3, GL_UNSIGNED_INT, (GLvoid*)m_vIndexCoord[0]);

 

 原文地址http://blog.csdn.net/zhucde/archive/2008/12/18/3547442.aspx


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章