現(xiàn)代OpenGL教程 01——入門指南

轉(zhuǎn)自?http://www.cocoachina.com/game/20150811/12969.html

譯序

早前學(xué)OpenGL的時候還是1.x版本蔗衡,用的都是glVertex袍镀,glNormal等固定管線API廓奕。后來工作需要接觸DirectX9瞭亮,shader也只是可選項而已睛榄,跟固定管線一起混用著⌒偌現(xiàn)在工作內(nèi)容是手機(jī)游戲飘蚯,又轉(zhuǎn)到OpenGL ES熙参,發(fā)現(xiàn)OpenGL的世界已經(jīng)完全不同了艳吠,OpenGL ES 2.0版本開始就不再支持固定管線,只支持可編程管線孽椰。

國內(nèi)很多資料教程參差不齊昭娩,舊式接口滿天飛。在知乎看到這一系列教程弄屡,覺著挺好题禀,就想著一邊學(xué)順便翻譯下。畢竟手游市場的機(jī)遇和競爭壓力都在同比猛漲膀捷,多了解OpenGL ES肯定沒有壞處迈嘹。浮躁功利的環(huán)境下更需要懷著一顆寧靜致遠(yuǎn)的心去提高自身功底,長路漫漫全庸,與君共勉秀仲。

歡迎大家,這是現(xiàn)代OpenGL教程系列的第一篇壶笼。所有代碼都是開源的神僵,你可以在GitHub上下載:https://github.com/tomdalling/opengl-series

通過這篇教程,你將會學(xué)到如何在Windows下用Visual Studio 2013或Mac下用Xcode搭建OpenGL 3.2工程覆劈。該應(yīng)用包含一個頂點(diǎn)著色器(vertex shader)保礼,一個片段著色器(fragment shader)和使用VAO和VBO來繪制的三角形。該工程使用GLEW來訪問OpenGL API责语,用GLFW來處理窗口創(chuàng)建和輸入炮障,還有使用GLM進(jìn)行矩陣/矢量相關(guān)的數(shù)學(xué)運(yùn)算。

這聽上去有點(diǎn)無聊坤候,但搭建這樣的工程確實(shí)挺麻煩的胁赢,尤其對于初學(xué)者。只要解決完這問題白筹,我們就可以開始玩些有趣的東西了智末。

[TOC]

獲取代碼

所有例子代碼的zip打包可以從這里獲取:https://github.com/tomdalling/opengl-series/archive/master.zip徒河。

這一系列文章中所使用的代碼都存放在:https://github.com/tomdalling/opengl-series系馆。你可以在頁面中下載zip,加入你會git的話虚青,也可以復(fù)制該倉庫它呀。

本文代碼你可以在source/01_project_skeleton目錄里找到。使用OS X系統(tǒng)的棒厘,可以打開根目錄里的opengl-series.xcodeproj纵穿,選擇本文工程。使用Windows系統(tǒng)的奢人,可以在Visual Studio 2013里打開opengl-series.sln谓媒,選擇相應(yīng)工程。

工程里已包含所有依賴何乎,所以你不需要再安裝或者配置額外的東西句惯。如果有任何編譯或運(yùn)行上的問題,請聯(lián)系我支救。

關(guān)于兼容性的提醒

本文使用OpenGL 3.2抢野,但我會嘗試保持如下兼容:

向后兼容OpenGL 2.1

向前兼容OpenGL 3.X和4.X

兼容Android和iOS的OpenGL ES 2.0

因為OpenGL和GLSL存在許多不同版本,本文代碼不一定能做到100%上述兼容各墨。我希望能兼容99%指孤,并且不同版本之間只要輕微修改即可。

想要了解OpenGL和GLSL不同版本間的區(qū)別贬堵,這里很好得羅列了兼容列表恃轩。

Visual Studio下安裝

代碼在Windows 7 32位系統(tǒng),Visual Studio Express 2013(免費(fèi))下創(chuàng)建和測試黎做。你應(yīng)該可以打開解決方案并成功編譯所有工程叉跛。如果有問題請聯(lián)系我,或者將補(bǔ)丁發(fā)我蒸殿,我會更新工程筷厘。

Xcode下安裝

Xcode工程實(shí)在OSX 10.10系統(tǒng),Xcode 6.1下創(chuàng)建并測試的宏所。打開Xcode工程應(yīng)該可以成功編譯所有目標(biāo)酥艳。加入你無法成功編譯請聯(lián)系我。

Linux下安裝

Linux是基于SpartanJ楣铁。我在Ubuntu 12.04下簡單測試通過玖雁。

安裝GLM,GLFW和GLEW: sudo aptitude install libglm-dev libglew-dev libglfw-dev

進(jìn)入工程目錄:cd platforms/linux/01_project_skeleto

運(yùn)行makefile:make

運(yùn)行可執(zhí)行文件:bin/01_project_skeleton-debug

GLEW, GLFW和GLM介紹

現(xiàn)在你有了工程盖腕,就讓我們開始介紹下工程所用到的開源庫和為啥需要這些赫冬。

The OpenGL Extension Wrangler (GLEW)是用來訪問OpenGL 3.2 API函數(shù)的。不幸的是你不能簡單的使用#include來訪問OpenGL接口溃列,除非你想用舊版本的OpenGL劲厌。在現(xiàn)代OpenGL中,API函數(shù)是在運(yùn)行時(run time)確定的听隐,而非編譯期(compile time)补鼻。GLEW可以在運(yùn)行時加載OpenGL API。

GLFW允許我們跨平臺創(chuàng)建窗口,接受鼠標(biāo)鍵盤消息风范。OpenGL不處理這些窗口創(chuàng)建和輸入咨跌,所以就需要我們自己動手。我選擇GLFW是因為它很小硼婿,并且容易理解锌半。

OpenGL Mathematics (GLM)是一個數(shù)學(xué)庫,用來處理矢量和矩陣等幾乎其它所有東西寇漫。舊版本OpenGL提供了類似glRotate, glTranslate和glScale等函數(shù)刊殉,在現(xiàn)代OpenGL中,這些函數(shù)已經(jīng)不存在了州胳,我們需要自己處理所有的數(shù)學(xué)運(yùn)算记焊。GLM能在后續(xù)教程里提供很多矢量和矩陣運(yùn)算上幫助。

在這系列的所有教程中栓撞,我們還編寫了一個小型庫tdogl用來重用C++代碼遍膜。這篇教程會包含tdogl::Shader和tdogl::Program用來加載,編譯和鏈接shaders腐缤。

什么是Shaders捌归?

Shaders在現(xiàn)代OpenGL中是個很重要的概念。應(yīng)用程序離不開它岭粤,除非你理解了惜索,否則這些代碼也沒有任何意義。

Shaders是一段GLSL小程序剃浇,運(yùn)行在GPU上而非CPU巾兆。它們使用OpenGL Shading Language (GLSL)語言編寫,看上去像C或C++虎囚,但卻是另外一種不同的語言角塑。使用shader就像你寫個普通程序一樣:寫代碼,編譯淘讥,最后鏈接在一起才生成最終的程序。

Shaders并不是個很好的名字蒲列,因為它不僅僅只做著色。只要記得它們是個用不同的語言寫的蝗岖,運(yùn)行在顯卡上的小程序就行。

在舊版本的OpenGL中抵赢,shaders是可選的唧取。在現(xiàn)代OpenGL中划提,為了能在屏幕上顯示出物體,shaders是必須的腔剂。

為可能近距離了解shaders和圖形渲染管線驼仪,我推薦Durian Software的相關(guān)文章The Graphics Pipeline chapter掸犬。

那shaders實(shí)際上干了啥?這取決于是哪種shader绪爸。

Vertex Shaders

Vertex shader主要用來將點(diǎn)(x湾碎,y,z坐標(biāo))變換成不同的點(diǎn)奠货。頂點(diǎn)只是幾何形狀中的一個點(diǎn)介褥,一個點(diǎn)叫vectex,多個點(diǎn)叫vertices(發(fā)音為ver-tuh-seez)递惋。在本教程中柔滔,我們的三角形需要三個頂點(diǎn)(vertices)組成铣口。

Vertex Shader的GLSL代碼如下:

#version?150

invec3?vert;

void?main()?{

????//?does?not?alter?the?vertices?at?all

????gl_Position?=?vec4(vert,?1);

}

第一行#version 150告訴OpenGL這個shader使用GLSL版本1.50虎敦。

第二行in vec3 vert;告訴shader需要那一個頂點(diǎn)作為輸入庆亡,放入變量vert绿贞。

第三行定義函數(shù)main痊末,這是shader運(yùn)行入口秦效。這看上去像C恬涧,但GLSL中main不需要帶任何參數(shù)穷绵,并且不用返回void邓馒。

第四行g(shù)l_Position = vec4(vert, 1);將輸入的頂點(diǎn)直接輸出嘶朱,變量gl_Position是OpenGL定義的全局變量,用來存儲vertex shader的輸出光酣。所有vertex shaders都需要對gl_Position進(jìn)行賦值疏遏。

gl_Position是4D坐標(biāo)(vec4),但vert是3D坐標(biāo)(vec3)救军,所以我們需要將vert轉(zhuǎn)換為4D坐標(biāo)vec4(vert, 1)财异。第二個的參數(shù)1是賦值給第四維坐標(biāo)。我們會在后續(xù)教程中學(xué)到更多關(guān)于4D坐標(biāo)的東西缤言。但現(xiàn)在宝当,我們只要知道第四維坐標(biāo)是1即可,i可以忽略它就把它當(dāng)做3D坐標(biāo)來對待胆萧。

Vertex Shader在本文中沒有做任何事庆揩,后續(xù)我們會修改它來處理動畫俐东,攝像機(jī)和其它東西虏辫。

Fragment Shaders

Fragment shader的主要功能是計算每個需要繪制的像素點(diǎn)的顏色砌庄。

一個"fragment"基本上就是一個像素娄昆,所以你可以認(rèn)為片段著色器(fragment shader)就是像素著色器(pixel shader)萌焰。在本文中每個片段都是一像素谷浅,但這并不總是這樣的一疯。你可以更改某個OpenGL設(shè)置墩邀,以便得到比像素更小的片段磕蒲,之后的文章我們會講到這個辣往。

本文所使用的fragment shader代碼如下:

#version?150

out?vec4?finalColor;

void?main()?{

????//set?every?drawn?pixel?to?white

????finalColor?=?vec4(1.0,?1.0,?1.0,?1.0);

}

再次站削,第一行#version 150告訴OpenGL這個shader使用的是GLSL 1.50许起。

第二行finalColor = vec4(1.0, 1.0, 1.0, 1.0);將輸出變量設(shè)為白色。vec4(1.0, 1.0, 1.0, 1.0)是創(chuàng)建一個RGBA顏色惦积,并且紅綠藍(lán)和alpha都設(shè)為最大值狮崩,即白色。

現(xiàn)在诽凌,就能用shader在OpenGL中繪制出了純白色侣诵。在之后的文章中狱窘,我們還會加入不同顏色和貼圖训柴。貼圖就是你3D模型上的圖像幻馁。

編譯和鏈接Shaders

在C++中仗嗦,你需要對你的.cpp文件進(jìn)行編譯稀拐,然后鏈接到一起組成最終的程序德撬。OpenGL的shaders也是這么回事躲胳。

在這篇文章中用到了兩個可復(fù)用的類坯苹,是用來處理shaders的編譯和鏈接:tdogl::Shader和tdogl::Program粹湃。這兩個類代碼不多为鳄,并且有詳細(xì)的注釋,我建議你閱讀源碼并且去鏈接OpenGL是如何工作的歧斟。

什么是VBO和VAO构捡?

當(dāng)shaders運(yùn)行在GPU,其它代碼運(yùn)行在CPU時滑凉,你需要有種方式將數(shù)據(jù)從CPU傳給GPU畅姊。在本文中若未,我們傳送了一個三角的三個頂點(diǎn)數(shù)據(jù)粗合,但在更大的工程中3D模型會有成千上萬個頂點(diǎn)隙疚,顏色供屉,貼圖坐標(biāo)和其它東西伶丐。

這就是我們?yōu)槭裁葱枰猇ertex Buffer Objects (VBOs)和Vertex Array Objects (VAOs)哗魂。VBO和VAO用來將C++程序的數(shù)據(jù)傳給shaders來渲染辙芍。

在舊版本的OpenGL中,是通過glVertex庶灿,glTexCoord和glNormal函數(shù)把每幀數(shù)據(jù)發(fā)送給GPU的往踢。在現(xiàn)代OpenGL中峻呕,所有數(shù)據(jù)必須通過VBO在渲染之前發(fā)送給顯卡瘦癌。當(dāng)你需要渲染某些數(shù)據(jù)時,通過設(shè)置VAO來描述該獲取哪些VBO數(shù)據(jù)推送給shader變量热押。

Vertex Buffer Objects (VBOs)

第一步我們需要從內(nèi)存里上傳三角形的三個頂點(diǎn)到顯存中。這就是VBO該干的事娘锁。VBO其實(shí)就是顯存的“緩沖區(qū)(buffers)” - 一串包含各種二進(jìn)制數(shù)據(jù)的字節(jié)區(qū)域莫秆。你能上傳3D坐標(biāo)雷蹂,顏色杯道,甚至是你喜歡的音樂和詩歌党巾。VBO不關(guān)心這些數(shù)據(jù)是啥,因為它只是對內(nèi)存進(jìn)行復(fù)制署海。

Vertex Array Objects (VAOs)

第二步我們要用VBO的數(shù)據(jù)在shaders中渲染三角形医男。請記住VBO只是一塊數(shù)據(jù)镀梭,它不清楚這些數(shù)據(jù)的類型研底。而告訴OpenGL這緩沖區(qū)里是啥類型數(shù)據(jù),這事就歸VAO管榜晦。

VAO對VBO和shader變量進(jìn)行了連接抖剿。它描述了VBO所包含的數(shù)據(jù)類型牙躺,還有該傳遞數(shù)據(jù)給哪個shader變量。在OpenGL所有不準(zhǔn)確的技術(shù)名詞中脓恕,“Vertex Array Object”是最爛的一個炼幔,因為它根本沒有解釋VAO該干的事。

你回頭看下本文的vertex shader(在文章的前面)跺讯,你就能發(fā)現(xiàn)我們只有一個輸入變量vert刀脏。在本文中愈污,我們用VAO來說明“hi,OpenGL金麸,這里的VBO有3D頂點(diǎn)揍魂,我想要你在vertex shader時喜最,發(fā)三個頂點(diǎn)數(shù)據(jù)給vert變量瞬内〕娴”

在后續(xù)的文章中能真,我們會用VAO來說“hi,OpenGL卤档,這里的VBO有3D頂點(diǎn)蝙泼,顏色,貼圖坐標(biāo)劝枣,我想要你在shader時汤踏,發(fā)頂點(diǎn)數(shù)據(jù)給vert變量,發(fā)顏色數(shù)據(jù)給vertColor變量舔腾,發(fā)貼圖坐標(biāo)給vertTexCoord變量茎活。”

給使用上個OpenGL版本的用戶的提醒:

假如你在舊版本的OpenGL中使用了VBO但沒有用到VAO琢唾,你可能會不認(rèn)同VAO的描述。你會爭論說“頂點(diǎn)屬性”可以用glVertexAttribPointer將VBO和shaders連接起來盾饮,而不是用VAO采桃。這取決于你是否認(rèn)為頂點(diǎn)屬性應(yīng)該是VAO“內(nèi)置(inside)”的(我是這么認(rèn)為的)普办,或者說它們是否是VAO外置的一個全局狀態(tài)。3.2內(nèi)核和我用的AIT驅(qū)動中,VAO不是可選項 - 沒有VAO的封裝glEnableVertexAttribArray, glVertexAttribPointer和glDrawArrays都會導(dǎo)致GL_INVALID_OPERATION錯誤。這就是為啥我認(rèn)為頂點(diǎn)屬性應(yīng)該內(nèi)置于VAO,而非全局狀態(tài)的原因。3.2內(nèi)核手冊也說VAO是必須的,但我只聽說ATI驅(qū)動會拋錯誤。下面描述引用自OpenGL 3.2內(nèi)核手冊

所有與頂點(diǎn)處理有關(guān)的數(shù)據(jù)定義都應(yīng)該封裝在VAO里。 一般VAO邊界包含所有更改vertex array狀態(tài)的命令监署,比如VertexAttribPointer和EnableVertexAttribArray;所有使用vertex array進(jìn)行繪制的命令俏拱,比如DrawArrays和DrawElements;所有對vertex array狀態(tài)進(jìn)行查詢的命令(見第6章)么鹤。

不管怎樣,我也知道為啥會有人認(rèn)為頂點(diǎn)屬性應(yīng)該放在VAO外部。glVertexAttribPointer出現(xiàn)早于VAO,在這段時間里頂點(diǎn)屬性一直被認(rèn)為是全局狀態(tài)。你應(yīng)該能看得出VAO是一種改變?nèi)譅顟B(tài)的有效方法。我更傾向于認(rèn)為是這樣:假如你沒有創(chuàng)建VAO,那OpenGL通過了一個默認(rèn)的全局VAO挺份。所以當(dāng)你使用glVertexAttribPointer時探赫,你仍然是在VAO內(nèi)修改頂點(diǎn)屬性搁嗓,只不過現(xiàn)在從默認(rèn)的VAO變成你自己創(chuàng)建的VAO。

這里有更多的討論:http://www.opengl.org/discussion_boards/showthread.php/174577-Questions-on-VAOs

代碼解釋

終于!理論已經(jīng)說完了潘拨,我們開始編碼。OpenGL對于初學(xué)者而言不是特別友好濒生,但如果你理解了之前所介紹的概念(shaders,VBO,VAO)那你就沒啥問題。

打開main.cpp不脯,我們從main()函數(shù)開始。

首先肖揣,我們初始化GLFW:

glfwSetErrorCallback(OnError);

if(!glfwInit())

????throwstd::runtime_error("glfwInit?failed");

glfwSetErrorCallback(OnError)這一行告訴GLFW當(dāng)錯誤發(fā)生時調(diào)用OnError函數(shù)。OnError函數(shù)會拋一個包含錯誤信息的異常,我們能從中發(fā)現(xiàn)哪里出錯了蔚出。

然后我們用GLFW創(chuàng)建一個窗口衅胀。

glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,?GL_TRUE);

glfwWindowHint(GLFW_OPENGL_PROFILE,?GLFW_OPENGL_CORE_PROFILE);

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,?3);

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,?2);

glfwWindowHint(GLFW_RESIZABLE,?GL_FALSE);

gWindow?=?glfwCreateWindow((int)SCREEN_SIZE.x,?(int)SCREEN_SIZE.y,?"OpenGL?Tutorial",?NULL,?NULL);

if(!gWindow)

????throwstd::runtime_error("glfwCreateWindow?failed.?Can?your?hardware?handle?OpenGL?3.2?");

該窗口包含一個向前兼容的OpenGL 3.2內(nèi)核上下文。假如glfwCreateWindow失敗了宙帝,你應(yīng)該降低OpenGL版本仍侥。

創(chuàng)建窗口最后一步,我們應(yīng)該設(shè)置一個“當(dāng)前”O(jiān)penGL上下文給剛創(chuàng)建的窗口:

1glfwMakeContextCurrent(gWindow);

無論我們調(diào)用哪個OpenGL函數(shù)否淤,都會影響到“當(dāng)前上下文”鞍帝。我們只會用到一個上下文,所以設(shè)置完后煞茫,就別管它了帕涌。理論上來說,我們可以有多個窗口续徽,且每個窗口都可以有自己的上下文蚓曼。

現(xiàn)在我們窗口有了OpenGL上下文變量,我們需要初始化GLEW以便訪問OpenGL接口钦扭。

glewExperimental?=?GL_TRUE;?//stops?glew?crashing?on?OSX?:-/

if(glewInit()?!=?GLEW_OK)

????throwstd::runtime_error("glewInit?failed");

這里的GLEW與OpenGL內(nèi)核有點(diǎn)小問題纫版,設(shè)置glewExperimental就可以修復(fù),但希望再未來永遠(yuǎn)不要發(fā)生客情。

我們也可以用GLEW再次確認(rèn)3.2版本是否存在:

if(!GLEW_VERSION_3_2)

????throwstd::runtime_error("OpenGL?3.2?API?is?not?available.");

在LoadShaders函數(shù)中其弊,我們使用本教程提供的tdogl::Shader和tdogl::Program兩個類編譯和鏈接了vertex shader和fragment shader。

std::vector?shaders;

shaders.push_back(tdogl::Shader::shaderFromFile(ResourcePath("vertex-shader.txt"),?GL_VERTEX_SHADER));

shaders.push_back(tdogl::Shader::shaderFromFile(ResourcePath("fragment-shader.txt"),?GL_FRAGMENT_SHADER));

gProgram?=?newtdogl::Program(shaders);

在LoadTriangle函數(shù)中裹匙,我們創(chuàng)建了一個VAO和VBO瑞凑。這是第一步,創(chuàng)建和綁定新的VAO:

glGenVertexArrays(1,?&gVAO);

glBindVertexArray(gVAO);

然后我們創(chuàng)建和綁定新的VBO:

glGenBuffers(1,?&gVBO);

glBindBuffer(GL_ARRAY_BUFFER,?gVBO);

接著概页,我們上傳一些數(shù)據(jù)到VBO中籽御。這些數(shù)據(jù)就是三個頂點(diǎn),每個頂點(diǎn)包含三個GLfloat惰匙。

GLfloat?vertexData[]?=?{

????//??X?????Y?????Z

?????0.0f,?0.8f,?0.0f,

????-0.8f,-0.8f,?0.0f,

?????0.8f,-0.8f,?0.0f,

};

glBufferData(GL_ARRAY_BUFFER,?sizeof(vertexData),?vertexData,?GL_STATIC_DRAW);

現(xiàn)在緩沖區(qū)包含了三角形的三個頂點(diǎn)技掏,是時候開始設(shè)置VAO了。首先项鬼,我們應(yīng)該啟用shader程序中的vert變量哑梳。這些變量能被開啟或關(guān)閉,默認(rèn)情況下是關(guān)閉的绘盟,所以我們需要開啟它鸠真。vert變量是一個“屬性變量(attribute variable)”,這也是為何OpenGL函數(shù)名稱中有帶“Attrib”龄毡。我們可以在后續(xù)的文章中看到更多類型吠卷。

1glEnableVertexAttribArray(gProgram->attrib("vert"));

VAO設(shè)置最復(fù)雜的部分就是下個函數(shù):glVertexAttribPointer。讓我們先調(diào)用該函數(shù)沦零,等會解釋祭隔。

1glVertexAttribPointer(gProgram->attrib("vert"),?3,?GL_FLOAT,?GL_FALSE,?0,?NULL);

第一個參數(shù),gProgram->attrib("vert")路操,這就是那個需要上傳數(shù)據(jù)的shder變量疾渴。在這個例子中千贯,我們需要發(fā)數(shù)據(jù)給vertshader變量。

第二個參數(shù)搞坝,3表明每個頂點(diǎn)需要三個數(shù)字搔谴。

第三個參數(shù),GL_FLOAT說明三個數(shù)字是GLfloat類型桩撮。這非常重要己沛,因為GLdouble類型的數(shù)據(jù)大小跟它是不同的。

第四個參數(shù)距境,GL_FALSE說明我們不需要對浮點(diǎn)數(shù)進(jìn)行“歸一化”,假如我們使用了歸一化垮卓,那這個值會被限定為最小0垫桂,最大1。我們不需要對我們的頂點(diǎn)進(jìn)行限制粟按,所以這個參數(shù)為false诬滩。

第五個參數(shù),0灭将,該參數(shù)可以在頂點(diǎn)之間有間隔時使用疼鸟,設(shè)置參數(shù)為0,表示數(shù)據(jù)之間沒有間隔庙曙。

第六個參數(shù)空镜,NULL,假如我們的數(shù)據(jù)不是從緩沖區(qū)頭部開始的話捌朴,可以設(shè)置這個參數(shù)來指定吴攒。設(shè)置該參數(shù)為NULL,表示我們的數(shù)據(jù)從VBO的第一個字節(jié)開始砂蔽。

現(xiàn)在VBO和VAO都設(shè)置完成洼怔,我們需要對它們進(jìn)行解綁定,防止一不小心被哪里給更改了左驾。

glBindBuffer(GL_ARRAY_BUFFER,?0);

glBindVertexArray(0);

到此镣隶,shader,VBO和VAO都準(zhǔn)備好了诡右。我們可以開始在Render函數(shù)里繪制了安岂。

首先,我們先清空下屏幕稻爬,讓它變成純黑色:

glClearColor(0,?0,?0,?1);?//?black

glClear(GL_COLOR_BUFFER_BIT?|?GL_DEPTH_BUFFER_BIT);

然后告訴OpenGL我們要開始使用VAO和shader了:

glUseProgram(gProgram->object());

glBindVertexArray(gVAO);

最后嗜闻,我們繪制出三角形:

1glDrawArrays(GL_TRIANGLES,?0,?3);

調(diào)用glDrawArrays函數(shù)說明我們需要繪制三角形,從第0個頂點(diǎn)開始桅锄,有3個頂點(diǎn)被發(fā)送到shader琉雳。OpenGL會在當(dāng)前VAO范圍內(nèi)確定該從哪里獲取頂點(diǎn)样眠。

頂點(diǎn)將會從VBO中取出并發(fā)送到vertex shader。然后三角形內(nèi)的每個像素會發(fā)送給fragment shader翠肘。接著fragment shader將每個像素變成白色檐束。歡呼!

現(xiàn)在繪制結(jié)束了束倍,為了安全起見被丧,我們需要將shader和VAO進(jìn)行解綁定:

glBindVertexArray(0);

glUseProgram(0);

最后一件事,在我們看到三角形之前需要切換幀緩沖:

1glfwSwapBuffers(gWindow);

在幀緩沖被交換前绪妹,我們會繪制到一個不可見的離屏(off-screen)幀緩沖區(qū)甥桂。當(dāng)我們調(diào)用glfwSwapBuffers時,離屏緩沖會變成屏幕緩沖邮旷,所以我們就能在窗口上看見內(nèi)容了黄选。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市婶肩,隨后出現(xiàn)的幾起案子办陷,更是在濱河造成了極大的恐慌,老刑警劉巖律歼,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件民镜,死亡現(xiàn)場離奇詭異,居然都是意外死亡险毁,警方通過查閱死者的電腦和手機(jī)制圈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辱揭,“玉大人离唐,你說我怎么就攤上這事∥是裕” “怎么了亥鬓?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長域庇。 經(jīng)常有香客問我嵌戈,道長,這世上最難降的妖魔是什么听皿? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任熟呛,我火速辦了婚禮,結(jié)果婚禮上尉姨,老公的妹妹穿的比我還像新娘庵朝。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布九府。 她就那樣靜靜地躺著椎瘟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侄旬。 梳的紋絲不亂的頭發(fā)上肺蔚,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音儡羔,去河邊找鬼宣羊。 笑死,一個胖子當(dāng)著我的面吹牛汰蜘,可吹牛的內(nèi)容都是我干的仇冯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼族操,長吁一口氣:“原來是場噩夢啊……” “哼赞枕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坪创,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姐赡,沒想到半個月后莱预,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡项滑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年依沮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枪狂。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡危喉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出州疾,到底是詐尸還是另有隱情辜限,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布严蓖,位于F島的核電站薄嫡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颗胡。R本人自食惡果不足惜毫深,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毒姨。 院中可真熱鬧哑蔫,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稿黍,卻和暖如春疹瘦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巡球。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工言沐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酣栈。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓险胰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矿筝。 傳聞我的和親對象是個殘疾皇子起便,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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