1. 程式人生 > >New程式媛OpenGL全解析之—基本圖元與繪製

New程式媛OpenGL全解析之—基本圖元與繪製

大家好!

本期丹丹將給大家解析OpenGL基本圖元以及繪製~~

本期視訊的連結地址是:

https://www.bilibili.com/video/av22494256/

大家也可以直接在bi站首頁搜尋:New程式媛 ,即可看到相應視訊

本期的資源和程式碼下載連結是:

連結:https://pan.baidu.com/s/1EMTZ6sgLmxq5qk1DWHKXdQ 密碼:hbjp

OpenGL中可以支援很多不同的圖元型別,但總結起來可以歸為點、線、三角形、四邊形、多邊形這幾種。

比如我們能遊戲中看到的模型它是這樣的:

但實際我們的美術設計人員製作模型的時候是先有了這樣的一個網格模型,然後再做的蒙皮處理的:

而我們的程式碼使用模型,實際就是讀取到了這些模型的頂點資訊,然後再逐步繪製出來的。

好啦~千里之行始於足下,我們先來看看OpenGL中的基本圖元型別:

OpenGL列舉量   圖元型別
GL_POINTS  點
GL_LINES
GL_POLYGON  多邊形
GL_TRAINGLES 獨立三角形
GL_QUADS 獨立四邊形
GL_LINE_STRIP 條帶線
GL_LINE_LOOP 迴圈線
GL_TRAINGLE_STRIP 線性連續填充三角形串
GL_TRAINGLE_FAN 扇形連續填充三角形串
GL_QUAD_STRIP 連續填充四邊形串

基本圖元都有了,我們就先來看看繪製效果,咱們今天程式碼繪製出的東東

嘿嘿嘿,是不是充(nan)滿(kan)創(wu)意(bi)?丹丹已經盡力啦~ 為了讓推文看起來美那麼一丟丟~

還有人會說,丹丹你在搞什麼? 這跟遊戲中我們看到的男神女神模型到底有什麼關係?丹丹要告訴你們,有關係的,以後我們會慢慢的把東西變得好看,因為模型製作的工作不是由程式完成,所以原諒一下丹丹的繪圖能力吧。時間緊張的情況下已經很盡力啦~

點and線:

void glPointSize(GLfloat size);

引數size設定點的寬度(以畫素為單位),必須大於0.0,預設時為1.0。

void glLineWidth(GLfloat width);

設定線寬(以畫素為單位)。引數width必須大於0.0,預設時為1.0。

線繪製時有三種方式:

GL_LINES:是指每兩個點構成一條獨立的線

GL_LINE_STRIP:每一個點都跟前一個頂點構成一條直線,是連續的線

GL_LINE_LOOP:跟GL_LINE_STRIP相同,並且線首尾相接,形成封閉連續線

三角形:

GL_TRIANGLES: 每三個點一組畫一個三角形,三角形之間是獨立的

GL_TRIANGLE_STRIP:從第三個點開始,每個點與前面的兩個頂點組合畫一個三角形,繪製的是線性連續的一組三角形

GL_TRIANGLE_FAN:第三個點開始,每個點與前一個點和第一個點組合畫一個三角形,即扇形連續三角形

四邊形原理與三角形類似,可以在之後的編碼階段大家進行實戰的測試,觀看結果。

有了基本圖元,我們就要進行相應的繪製工作了,先看看繪製前的一些設定工作相對應的函式:

void glPolygonMode(GLenum face ,GLenum mode);

函式控制多邊形的正面與背面繪製模式。

face:GL_ FRONT_ AND BACK

mode:可以是GL_ POINT、GL_LINE或者GL_FILL,它們分別是點、線和填充,預設是填充模式

void glFrontFace(GLenum mode)

設定多邊形正面的判斷方式。預設為GL_CCW即頂點按照逆時針排序的面作為正面。另一個模式是GL_CW即為順時針方向的面是物體的正面。

void glCullFace(GLenum mode):

背面一般是玩家看不到的面,所以我們可以通過該函式設定需要拋棄(裁減掉)哪一面的多邊形。

mode:可以是GL FRONT、 GL BACK或者 GL FRONT AND_BACK,分別表示正面、背面或者所有多邊形。

要使命令生效,我們還需要使用 glEnable()和 GL CULL FACE引數來開啟裁減;之後也可以使用 glDisable()和同樣的引數來關閉它。

接下來要做的就是繪製資料的準備啦~

a.建立和分配快取

OpenGL中的快取物件是使用 GLuint來進行命名的。而GLuint是使用 glGenBuffers()函式來建立。
void glGenBuffers(Glsizei n, Gluint* buffers)
返回n個當前未使用的快取物件名稱,並儲存到 buffers陣列中。
呼叫 glGenBuffers()完成之後,我們們將在 buffers中得到一個快取物件名稱的陣列,但是此時這些名稱只是徒有其表。並不是真正的快取物件。只有繫結到系統環境中的一個目標結點後,它所對應的快取物件才會真正創建出來。 

b.繫結目標

void glBindeBuffer(GLenum target,GLuint buffer);

OpenGL會採取一種最優記憶體管理策略,根據快取物件完成繫結的情況來分配它對應的記憶體。可用的快取目標結點我們稱作target,我們使用到了如下的型別:

GL ARRAY BUFFER:頂點陣列,儲存glVertexAttribPointer()設定的頂點資料

GL ELEMENT ARRAY BUFFER:頂點索引資料,以便用於glDrawElements()等索引形式的繪製命令

c.向快取輸入資料

void glBufferData(GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage );

target引數意義同b步驟中的,size引數表示需要分配的空間大小,以位元組為單位,data引數用於指定資料來源,如果data不為空將會拷貝其資料來初始化這個緩衝區,否則只是分配預定大小的空間。預分配空間後,後續可以通過glBufferSubData來更新緩衝區內容。 usage引數指定資料使用模式,OpenGL對於快取物件儲存資料中的最優分配方案的管理,並不僅僅依賴於初始化繫結時的 target引數。另一個重要的引數就是usage,它必須是內建標準識別符號中的一個,例如 GL STATIC DRAW或者 GL DYNAMIC COPY。注意這裡的識別符號名稱要分解為兩個部分去理解:第第一部分可以是 STATIC、 DYNAMIC或者 STREAM中的一個,而第二部分可以是DRAW、READ或者COPY中的一個。

STATIC:資料儲存內容只寫入一次,然後多次使用

DYNAMIC:資料儲存內容會被反覆寫入和反覆使用

STREAM:資料儲存內容只寫入一次,然後也不會被頻繁使用

DRAW:資料儲存內容由應用程式負責寫入,並且作為 OpenGL繪製和影象命令的資料來源

READ:資料儲存內容通過 OpenGL反饋的資料寫入,然後在應用程式進行查詢時返回這些資料

COPY:資料儲存內容通過 OpenGL反饋的資料寫入,並且作為 OpenGL繪製和影象命令的資料來源

最後一步驟,繪製!

大部分OpenGL繪製函式都是以Draw開始的。繪製可分為索引(GL ELEMENT ARRAY)和非索引兩種形式。

非索引繪製函式: 

void glDrawArrays(Glenum mode, Glint first, Glsizei count);

mode表示基本圖元型別,first是指資料陣列的起始位置,count表示數量,繪製的結束位置為first+count-1。

索引繪製函式: 

void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GL void* indices);

 接下來咱們就看看今天的程式碼,以下部分都是程式碼中有編輯和修改的部分:

shader中我們添加了控制顏色的uniform量,如下:

接著是我們繪製的幾個圖形的頂點:

這些頂點可以用紙筆直接繪製計算出相對的位置,也可以使用類似TileMap工具來生成,如果想知道工具,請大家看看視訊裡頭的說明哦

下圖是初始化頂點資料,因為我們這次的圖形都沒有說明索引規律可循,所以都是直接使用的頂點陣列繪製方式繪製出來的。

繪製程式碼如下圖:

好啦~ 到此為止咱們本期的基本圖元和繪製就介紹完畢了。

丹丹期待大家的意見和建議,歡迎小夥伴們積極留言