從0開始的OpenGL學習(二)-渲染三角形

本文主要解決一個問題:

如何渲染一個三角形?

本章中,會有大量的新名詞和解釋,大量的函數(shù)出現(xiàn),建議找個安靜的地方慢慢啃這塊骨頭。

首先,先從直覺上來想想要渲染一個三角形我們需要做些什么?大概需要這三個步驟:

  • 1、定義三個頂點。
  • 2、將三個頂點的邊兩兩相連。
  • 3、將內(nèi)部的區(qū)域涂成一種或幾種顏色。

我們就從這幾個方面來畫出我們的三角形。

一、頂點

在OpenGL中,所有的頂點都是三維空間內(nèi)的頂點,不過這不是問題,我們可以把深度定義為0來保證其在一個平面上。于是,我們定義三個點:(-0.5, 0.5, 0.0),(0.5, -0.5, 0.0),(0.0, 0.5, 0.0),由于在OpenGL中所有的頂點都會被規(guī)范化(將頂點的位置變換到-1到1之間),我們就直接定義規(guī)范化后的點,方便處理。我們的代碼就像這個樣子(編程是一種手寫編碼的過程,不是Ctrl+C、Ctrl+V的過程,手寫一遍代碼還是非常必要的):

頂點數(shù)組

我們有了頂點數(shù)組,如何讓OpenGL知道呢?這里有個新東西,叫頂點緩存對象(Vertex Buffer Object,簡稱VBO),表示存儲在GPU顯存中的大量頂點數(shù)據(jù)。我們可以通過這個對象,一次性向GPU發(fā)送大量的數(shù)據(jù),而不是一次次地從CPU中發(fā)送數(shù)據(jù)到GPU,這是個很慢的過程。

1、使用VBO

唯一ID:OpenGL中有太多的東西,我們需要一個唯一的ID,就像身份證一樣來標識出哪個是哪個。這個ID不能我們自己來定,只能告訴OpenGL說,我需要一個唯一ID,你給我一個吧。然后,OpenGL就會給你一個沒用過的唯一ID,這個過程是由glGenBuffers來實現(xiàn)的。


生成唯一ID

指明緩存對象類型:OpenGL中有很多緩存對象,雖然它給了我們一個ID,但不知道這個ID是用來表示什么緩存對象的。我們要明確告訴它,這是一個頂點緩存對象。綁定的作用,是將原來有的東西替換成我們新的東西,這樣,接下來對GL_ARRAY_BUFFER的操作都是對我們新東西的操作了。

指定為頂點緩存對象

將頂點數(shù)據(jù)傳到VBO:

頂點數(shù)據(jù)復制到VBO
  • 參數(shù)1:我們的頂點數(shù)據(jù)需要拷貝到的地方。(之前我們綁定的VBO)
  • 參數(shù)2:數(shù)組的大小
  • 參數(shù)3:數(shù)組的地址
  • 參數(shù)4:指定顯卡要采用什么方式來管理我們的數(shù)據(jù),GL_STATIC_DRAW表示這些數(shù)據(jù)不會經(jīng)常改變。

2、頂點著色器

從OpenGL 3.3開始,OpenGL的渲染方式就從固定功能管線轉(zhuǎn)向了可編程功能管線。而可編程的意思,就是可以通過許許多多的著色器來實現(xiàn)多種多樣的效果,這些效果要比固定的效果好的多。頂點著色器就是這些許許多多的著色器中的一種。
先放出一段代碼(GLSL語言編寫,語法與C極為類似):

頂點著色器代碼
  • 第一行:指明了使用OpenGL的版本以及運行模式(版本號3.3,核心模式)
  • 第二行:指明了需要從上一個步驟中獲取一個vec3類型的位置數(shù)據(jù),數(shù)據(jù)位置在輸入數(shù)據(jù)的0偏移位置(類似于輸入了一塊數(shù)據(jù),我們要的數(shù)據(jù)在頭部)
  • 第七行(main函數(shù)內(nèi)部):將頂點的位置直接賦值成輸入的位置,gl_Position是一個內(nèi)置的變量,用來表示頂點位置的。
2.1編譯著色器

代碼自然是要編譯鏈接之后才能執(zhí)行的,這里我們先說編譯,鏈接的部分等講完片元著色器再一起說,先不用糾結(jié)。
首先,創(chuàng)建一個著色器對象,返回值是這個對象的唯一ID

創(chuàng)建著色器對象

然后,我們將源碼附加到著色器對象上并且編譯這個著色器對象

附加源代碼并且編譯著色器對象

3、片元著色器

同樣,先放出代碼


片元著色器代碼

類似的,我們輸出一個顏色供片元使用,這個顏色是橙色。一個片元,包含了OpenGL用來渲染一個像素的所有信息。

3.1編譯著色器

我們同樣需要創(chuàng)建一個著色器對象,然后將源碼附加到著色器對象上,然后編譯。代碼如下:

片元著色器源碼

4、著色器程序?qū)ο?/h4>

著色器程序?qū)ο笫亲罱K將所有著色器連接起來的對象。把所有的著色器對象和這個著色器程序?qū)ο筮B接起來之后,我們就能使用這個著色器程序?qū)ο罅恕?br> 將著色器都連接到程序?qū)ο笊蠒r,OpenGL會將上一個階段的輸出連接到下一個階段的輸入上。
我們需要三步來使用著色器程序?qū)ο?,現(xiàn)在已經(jīng)很熟悉了。創(chuàng)建、附加、鏈接。

鏈接著色器代碼

5、使用著色器程序?qū)ο?/h4>

代碼很簡單,只有一行

使用著色器對象

6、清理著色器

將已經(jīng)附加過的著色器都清除掉,我們現(xiàn)在不需要它們了(過河拆橋???)。

清理著色器

7、指明頂點屬性

頂點著色器給了我們極大的便利性,我們可以輸入想要輸入的任何屬性格式。因此,我們也就要告訴OpenGL我們頂點的格式是什么樣子的。我們定義的頂點格式如下:

頂點格式(圖片資源來源于learningopengl.com)

可以看到一些重要信息,我們的起始頂點的偏移為0,每個位置分量占用4字節(jié)的空間,一個頂點占用12字節(jié)空間。

于是,我們調(diào)用glVertexAttribPointer函數(shù)來指定頂點格式。

指明頂點格式代碼
  • 參數(shù)1:指明我們想要配置的頂點屬性。類似編號的東西,之前我們設(shè)置了location = 0,就是我們在這里用到的0.
  • 參數(shù)2:頂點屬性的大小。我們用到的頂點是一個vec3的結(jié)果,所以大小為3.
  • 參數(shù)3:數(shù)據(jù)的類型。我們使用的是float類型
  • 參數(shù)4:指明數(shù)據(jù)是否要被規(guī)范化。這里我們設(shè)置成FALSE,不用規(guī)范化,因為我們已經(jīng)規(guī)范化好了。
  • 參數(shù)5:表示屬性的跨度。正如之前我們分析的,我們的跨度是12,就是3倍的float類型。
  • 參數(shù)6:指明了數(shù)據(jù)的起始偏移量。這里轉(zhuǎn)成了一個void*指針類型比較奇怪,我們以后再聊。

我們獲取的頂點屬性是由VBO決定的,而glVertexAttribPointer操作的是當前綁定到GL_ARRAY_BUFFER上的VBO,所以,我們當前操作的就是我們之前生成并綁定的那個VBO。

glEnableVertexAttribArray(0)是用來讓頂點屬性生效的,參數(shù)0就是我們之前配置的那個頂點屬性的位置。

二、繪制三角形
OpenGL中并沒有將我們上面設(shè)想的兩步單獨弄出來,只需要指明要畫的是三角形,而且是實體三角形,這兩步就能自動完成了。
所以,當我們做完上面那么多步驟之后,我們只需要調(diào)用一行代碼就可以了。

繪制三角形

到這里,似乎我們要做的事情都已經(jīng)做完,只要編譯運行代碼就能看到我們想要的三角形了。然而,事實并不像我們想象的那樣。運行的代碼還是一片青灰色,根本看不到三角形的影子。加了一個VAO進去之后,就能顯示出三角形來了??纯唇坛蹋瓉磉@個VAO已經(jīng)是OpenGL渲染管線中不可缺少的一部分了。所以,我們要鄭重其事地來了解一下VAO。

三、VAO

全稱是頂點數(shù)組對象(Vertex Array Object),作用是來保存對頂點屬性的調(diào)用。這樣,當我們需要這些頂點屬性的時候,只需要簡單地綁定VAO,不需要再設(shè)置一遍頂點屬性就可以進行繪制了。(是不是覺得沒有必要調(diào)用,我不想保存,只想顯示。所以筆者才嘗試不用VAO看看能不能顯示出三角形,結(jié)果是,沒戲,只能乖乖的用它。)

VAO會保存兩種東西:

  • 其一、對glEnableVertexAttribArray或者是DisableVertexAttribArray的調(diào)用。
  • 其二、使用glVertexAttribPointer設(shè)置的頂點屬性以及與頂點屬性相關(guān)連的VBO。

生成VAO并綁定的代碼如下:

unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

將這段代碼添加到生成VBO的代碼之后就可以編譯運行了。
嗯,不出所料,我們的三角形顯示出來了。

顯示結(jié)果

最后,源碼可以參考這里,強烈建議自己手輸一遍代碼,不自己寫一遍還算是程序員么?

總結(jié)

圖片資源來源于(www.learningopengl.com)

這是一張頂點處理的流程圖,我們所做的工作就是處理其中的一些階段。今天我們處理的是頂點著色和片元著色,之后在學光照和紋理的時候我們依舊是處理這些著色,可見這兩個階段是多么重要。

下一篇
目錄
上一篇

參考資料:

www.learningopengl.com(推薦學習)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內(nèi)容