久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

現(xiàn)代OpenGL教程 01

 學(xué)海無涯GL 2017-08-11



譯序

早前學(xué)OpenGL的時(shí)候還是1.x版本,,用的都是glVertexglNormal等固定管線API,。后來工作需要接觸DirectX9,,shader也只是可選項(xiàng)而已,跟固定管線一起混用著?,F(xiàn)在工作內(nèi)容是手機(jī)游戲,,又轉(zhuǎn)到OpenGL ES,發(fā)現(xiàn)OpenGL的世界已經(jīng)完全不同了,,OpenGL ES 2.0版本開始就不再支持固定管線,,只支持可編程管線,。



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

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

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

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

[TOC]

獲取代碼

所有例子代碼的zip打包可以從這里獲?。?a target="_blank" rel="external">https://github.com/tomdalling/opengl-series/archive/master.zip。

這一系列文章中所使用的代碼都存放在:https://github.com/tomdalling/opengl-series,。你可以在頁面中下載zip,,加入你會(huì)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)行上的問題,請(qǐng)聯(lián)系我,。

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

本文使用OpenGL 3.2,,但我會(huì)嘗試保持如下兼容:

  • 向后兼容OpenGL 2.1
  • 向前兼容OpenGL 3.X和4.X
  • 兼容Android和iOS的OpenGL ES 2.0

因?yàn)镺penGL和GLSL存在許多不同版本,本文代碼不一定能做到100%上述兼容,。我希望能兼容99%,,并且不同版本之間只要輕微修改即可。

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

Visual Studio下安裝

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

Xcode下安裝

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

Linux下安裝

Linux是基于SpartanJ,。我在Ubuntu 12.04下簡(jiǎn)單測(cè)試通過,。

  • 安裝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ù)的。不幸的是你不能簡(jiǎn)單的使用#include <GL/gl.h>來訪問OpenGL接口,,除非你想用舊版本的OpenGL,。在現(xiàn)代OpenGL中,API函數(shù)是在運(yùn)行時(shí)(run time)確定的,,而非編譯期(compile time),。GLEW可以在運(yùn)行時(shí)加載OpenGL API。

GLFW允許我們跨平臺(tái)創(chuàng)建窗口,,接受鼠標(biāo)鍵盤消息,。OpenGL不處理這些窗口創(chuàng)建和輸入,所以就需要我們自己動(dòng)手,。我選擇GLFW是因?yàn)樗苄?,并且容易理解?/p>

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

在這系列的所有教程中,我們還編寫了一個(gè)小型庫tdogl用來重用C++代碼,。這篇教程會(huì)包含tdogl::Shadertdogl::Program用來加載,,編譯和鏈接shaders。

什么是Shaders?

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

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

Shaders并不是個(gè)很好的名字,,因?yàn)樗粌H僅只做著色,。只要記得它們是個(gè)用不同的語言寫的,運(yùn)行在顯卡上的小程序就行,。

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

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

主程序 Shader程序
語言 C++ GLSL
主函數(shù) int main(int, char**); void main();
運(yùn)行于 CPU GPU
需要編譯?
需要鏈接,?

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

Vertex Shaders

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

Vertex Shader的GLSL代碼如下:

1
2
3
4
5
6
7
8
#version 150

in vec3 vert;

void main() {
// does not alter the vertices at all
gl_Position = vec4(vert, 1);
}

第一行#version 150告訴OpenGL這個(gè)shader使用GLSL版本1.50.

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

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

第四行gl_Position = vec4(vert, 1);將輸入的頂點(diǎn)直接輸出,變量gl_Position是OpenGL定義的全局變量,,用來存儲(chǔ)vertex shader的輸出,。所有vertex shaders都需要對(duì)gl_Position進(jìn)行賦值。

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

Vertex Shader在本文中沒有做任何事,后續(xù)我們會(huì)修改它來處理動(dòng)畫,,攝像機(jī)和其它東西,。

Fragment Shaders

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

一個(gè)”fragment”基本上就是一個(gè)像素,,所以你可以認(rèn)為片段著色器(fragment shader)就是像素著色器(pixel shader),。在本文中每個(gè)片段都是一像素,但這并不總是這樣的,。你可以更改某個(gè)OpenGL設(shè)置,,以便得到比像素更小的片段,之后的文章我們會(huì)講到這個(gè),。

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

1
2
3
4
5
6
7
8
#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這個(gè)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)建一個(gè)RGBA顏色,,并且紅綠藍(lán)和alpha都設(shè)為最大值,,即白色。

現(xiàn)在,,就能用shader在OpenGL中繪制出了純白色,。在之后的文章中,我們還會(huì)加入不同顏色和貼圖,。貼圖就是你3D模型上的圖像,。

編譯和鏈接Shaders

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

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

什么是VBO和VAO,?

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

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

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

Vertex Buffer Objects (VBOs)

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

Vertex Array Objects (VAOs)

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

VAO對(duì)VBO和shader變量進(jìn)行了連接,。它描述了VBO所包含的數(shù)據(jù)類型,還有該傳遞數(shù)據(jù)給哪個(gè)shader變量,。在OpenGL所有不準(zhǔn)確的技術(shù)名詞中,,“Vertex Array Object”是最爛的一個(gè),因?yàn)樗緵]有解釋VAO該干的事,。

你回頭看下本文的vertex shader(在文章的前面),,你就能發(fā)現(xiàn)我們只有一個(gè)輸入變量vert。在本文中,,我們用VAO來說明“hi,,OpenGL,這里的VBO有3D頂點(diǎn),,我想要你在vertex shader時(shí),,發(fā)三個(gè)頂點(diǎn)數(shù)據(jù)給vert變量?!?/p>

在后續(xù)的文章中,,我們會(huì)用VAO來說“hi,OpenGL,,這里的VBO有3D頂點(diǎn),,顏色,貼圖坐標(biāo),,我想要你在shader時(shí),,發(fā)頂點(diǎn)數(shù)據(jù)給vert變量,發(fā)顏色數(shù)據(jù)給vertColor變量,,發(fā)貼圖坐標(biāo)給vertTexCoord變量,。”

給使用上個(gè)OpenGL版本的用戶的提醒

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

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

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

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

代碼解釋

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

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

首先,,我們初始化GLFW:

1
2
3
glfwSetErrorCallback(OnError);
if(!glfwInit())
throw std::runtime_error("glfwInit failed");

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

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

1
2
3
4
5
6
7
8
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)
throw std::runtime_error("glfwCreateWindow failed. Can your hardware handle OpenGL 3.2?");

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

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

1
glfwMakeContextCurrent(gWindow);

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

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

1
2
3
glewExperimental = GL_TRUE; //stops glew crashing on OSX :-/
if(glewInit() != GLEW_OK)
throw std::runtime_error("glewInit failed");

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

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

1
2
if(!GLEW_VERSION_3_2)
throw std::runtime_error("OpenGL 3.2 API is not available.");

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

1
2
3
4
std::vector<tdogl::Shader> 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 = new tdogl::Program(shaders);

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

1
2
glGenVertexArrays(1, &gVAO);
glBindVertexArray(gVAO);

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

1
2
glGenBuffers(1, &gVBO);
glBindBuffer(GL_ARRAY_BUFFER, gVBO);

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

1
2
3
4
5
6
7
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ū)包含了三角形的三個(gè)頂點(diǎn),,是時(shí)候開始設(shè)置VAO了。首先,,我們應(yīng)該啟用shader程序中的vert變量,。這些變量能被開啟或關(guān)閉,默認(rèn)情況下是關(guān)閉的,,所以我們需要開啟它,。vert變量是一個(gè)“屬性變量(attribute variable)”,這也是為何OpenGL函數(shù)名稱中有帶“Attrib”,。我們可以在后續(xù)的文章中看到更多類型,。

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

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

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

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

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

第三個(gè)參數(shù),GL_FLOAT說明三個(gè)數(shù)字是GLfloat類型,。這非常重要,,因?yàn)?code>GLdouble類型的數(shù)據(jù)大小跟它是不同的。

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

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

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

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

1
2
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

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

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

1
2
glClearColor(0, 0, 0, 1); // black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

1
2
glUseProgram(gProgram->object());
glBindVertexArray(gVAO);

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

1
glDrawArrays(GL_TRIANGLES, 0, 3);

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

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

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

1
2
glBindVertexArray(0);
glUseProgram(0);

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

1
glfwSwapBuffers(gWindow);

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

進(jìn)一步閱讀

在后續(xù)文章中,,我們會(huì)對(duì)三角形進(jìn)行貼圖,。之后,你會(huì)學(xué)到一點(diǎn)矩陣變換知識(shí),,就可以使用vertex shader來實(shí)現(xiàn)3D立方體旋轉(zhuǎn),。

在這之后,我們開始創(chuàng)建3D場(chǎng)景并提交多個(gè)物體,。

更多現(xiàn)代OpenGL資料

不幸的是,,我不得不跳過很多內(nèi)容,防止本教程的篇幅過長(zhǎng),。后面還有很多好的現(xiàn)代OpenGL資料能滿足你的求知欲:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多