OpenGL (二)OpenGL入門(mén)理論知識(shí)

@[TOC](OpenGL (二)OpenGL入門(mén)理論知識(shí))

OpenGL 學(xué)習(xí)網(wǎng)址

  1. http://www.opengl-tutorial.org/

感覺(jué)難度適中

  1. http://ogldev.atspace.co.uk/index.html

(有一些skybox,shadow volume 等實(shí)現(xiàn)技巧的教程)

  1. http://www.scratchapixel.com/

(看起來(lái)更傾向于計(jì)算機(jī)圖形學(xué),而不僅僅是一個(gè) OpenGL 的教程)

  1. https://learnopengl-cn.readthedocs.io/zh/latest/

(這個(gè)網(wǎng)站也很基礎(chǔ)坦报,內(nèi)容非常好端蛆,水平和第一個(gè)類似图云,并且還有中文泥技。至少看到紋理映射這篇的教程华坦,講得比第一個(gè)鏈接更翔實(shí)间驮〖菪祝可以和第一個(gè)互相參考尘奏,強(qiáng)推)

  1. http://nehe.gamedev.net/

這個(gè)是我覺(jué)得全世界最知名的OpenGL教程滩褥,而且有網(wǎng)友將其中48個(gè)教程翻譯成了中文http://www.owlei.com/DancingWind/Nehe 此教程最大的特點(diǎn)是提供了針對(duì)不同平臺(tái)、不同編譯器炫加、不同語(yǔ)言的各種版本瑰煎。你不用考慮自己用的是Linux/Windows铺然、VC/BC、C++/Java/C#/VB酒甸,甚至D語(yǔ)言魄健,你都能找到對(duì)應(yīng)的版本。除了這些教程插勤,在Nehe Productions你還能下載到各種很cool的Demo沽瘦,相當(dāng)多的一部分都提供源代碼。http://nehe.gamedev.net/data/downloads/download.asp?letter=0-9

  1. http://www.ultimategameprogramming.com/

有100個(gè)免費(fèi)的OpenGL教程农尖,內(nèi)容涉及很多八叉樹(shù)析恋、BSP、Cg盛卡、GLSL助隧、各種紋理映射技術(shù)等,還有OpenAL窟扑、Ray Tracing的教程喇颁。該網(wǎng)站還推出了一本教你制作游戲引擎的書(shū)《Ultimate Game Programming with DirectX》,暫時(shí)還沒(méi)有中文翻譯版嚎货。

  1. http://www.codesampler.com/

有關(guān)于OpenGL橘霎、DirectX的很多教程、而且還定時(shí)更新一些東西殖属,不過(guò)最近該鏈接我打開(kāi)不了姐叁,不知道暫時(shí)出了什么問(wèn)題。

  1. http://www.lighthouse3d.com/opengl/

有針對(duì)View Frustum洗显、GLSL外潜、Math、Billboarding挠唆、Picking处窥、Terrain、Display Lists玄组、GLUT各專題的教程滔驾。其中關(guān)于GLUT、Terrain部分講解都非常詳細(xì)俄讹。一般的教程網(wǎng)站都是通過(guò)一段代碼展示OpenGL的某種渲染效果哆致,如果沒(méi)有圖形學(xué)背景很難理解其原理,該網(wǎng)站對(duì)所列每項(xiàng)技術(shù)的來(lái)龍去脈患膛,相關(guān)算法都有比較詳細(xì)的說(shuō)明摊阀,會(huì)讓你理解更加深刻。

  1. http://www.gametutorials.com/

我接觸最早的一個(gè)OpenGL教程網(wǎng)站,有很多有特色的教程胞此,比如一個(gè)小的2D RPG教程臣咖,可惜現(xiàn)在大部分代碼都不能免費(fèi)下載了。

  1. http://www.ozone3d.net/tutorials/index.php

有關(guān)于OpenGL豌鹤、GLSL亡哄、Direct3D的教程,還有很多其它有用的資料布疙、工具下載蚊惯,個(gè)人覺(jué)得很棒的一個(gè)網(wǎng)站。

  1. http://www.swiftless.com/tutorials/opengl/opengltuts.html

OpenGL灵临、GLSL截型、DirectX、Physics儒溉、Math等相關(guān)教程宦焦,看著很不錯(cuò)。

  1. http://www.morrowland.com/apron/tut_gl.php

教程的內(nèi)容包含OpenGL基本變換顿涣、紋理映射等波闹,也有一些有趣的Demo,可惜沒(méi)有提供源碼下載涛碑。

  1. http://www.coolgroups.com/

挺有特色的一個(gè)網(wǎng)站精堕。

  1. http://www.videotutorialsrock.com/

我知道的第一個(gè)OpenGL視頻教程,可惜是全英文的蒲障,看視頻教程還有一個(gè)好處就是不經(jīng)意間能學(xué)到作者編程時(shí)的一些細(xì)小技巧歹篓。

  1. https://github.com/tomdalling/opengl-series

我學(xué)習(xí)opengl得到的啟示最多的一篇文章,我強(qiáng)烈地建議大家去讀一下這位大神的相關(guān)系列的文章.這里面的代碼包含全面揉阎,真正想學(xué)習(xí)opengl的可以去看看

OpenGL 簡(jiǎn)介

  • 什么是OpenGL

1庄撮、OpenGL是一種應(yīng)用程序編程接口,它是一種可以對(duì)圖形硬件設(shè)備特性進(jìn)行訪問(wèn)的軟件庫(kù)毙籽。
2洞斯、OpenGL被設(shè)計(jì)為一個(gè)現(xiàn)代化的、硬件無(wú)關(guān)的接口坑赡,因此我們可以在不考慮計(jì)算機(jī)操作系統(tǒng)或窗口系統(tǒng)的前提下巡扇,在多種不同的圖形硬件系統(tǒng)上,或者完全通過(guò)軟件的方式實(shí)現(xiàn)OpenGL接口垮衷。
3、OpenGL自身并不包含任何執(zhí)行窗口任務(wù)乖坠,或者處理用戶輸入的函數(shù)搀突。
4、OpenGL也沒(méi)有提供任何用于表達(dá)三維物體模型熊泵,或者讀取圖像文件的操作仰迁。我們需要通過(guò)一系列的幾何圖元(點(diǎn)甸昏,線段,三角形徐许,以及patch)來(lái)創(chuàng)建三維空間物體施蜜!
5、OpenGL API是過(guò)程性的雌隅,不是描述性的翻默,即OpenGL不是面向?qū)ο蟮模設(shè)penGL無(wú)法利用面向?qū)ο蟮奶匦郧∑稹J褂玫臅r(shí)候只需要:程序與OpenGL的實(shí)現(xiàn)鏈接就可以了修械!
6、OpenGL的實(shí)現(xiàn)可以是軟件實(shí)現(xiàn)检盼,也可以是硬件實(shí)現(xiàn)肯污。
軟件實(shí)現(xiàn):是對(duì)OpengGL函數(shù)調(diào)用時(shí)作出的響應(yīng)并創(chuàng)建二維或三維圖像的函數(shù)庫(kù)。
硬件實(shí)現(xiàn):則是通過(guò)設(shè)置能夠繪制圖形或圖像的圖形卡驅(qū)動(dòng)程序
硬件實(shí)現(xiàn)要比軟件實(shí)現(xiàn)快得多6滞鳌蹦渣!

在這里插入圖片描述
  • OpenGL可以用來(lái)干什么?

1貌亭、OpenGL已經(jīng)誕生很長(zhǎng)時(shí)間了柬唯,1992年7月,SGI公司發(fā)布了OpenGL的1.0版本属提。
2权逗、應(yīng)用領(lǐng)域:視頻、圖形冤议、圖片處理斟薇,2D/3D游戲引擎開(kāi)發(fā),科學(xué)可視化恕酸,醫(yī)學(xué)軟件的開(kāi)發(fā) 堪滨,CAD(計(jì)算機(jī)輔助技術(shù)),虛擬實(shí)境(AR VR)蕊温,AI人工智能

  • OpenGL ES和OpenGL有什么關(guān)系?

1袱箱、OpenGL ES是OpenGL的子集,針對(duì)手機(jī)义矛、PDA和游戲主機(jī)嵌入式設(shè)備而設(shè)計(jì)
2发笔、OpenGL ES 是從 OpenGL 裁剪定制而來(lái)的,去除了 glBegin/glEnd凉翻,四邊形(GL_QUADS)了讨、多邊形(GL_POLYGONS)等復(fù)雜圖元等許多非絕對(duì)必要的特性,剩下最核心有用的部分。
可以理解成:OpenGL ES是一個(gè)在移動(dòng)平臺(tái)上能夠支持 OpenGL 最基本功能的精簡(jiǎn)規(guī)范前计。

  • OpenGL程序需要執(zhí)行的主要操作步驟

1胞谭、從OpenGL的幾何圖元中設(shè)置數(shù)據(jù),用于構(gòu)建形狀
2男杈、使用不同的著色器對(duì)輸入的圖元數(shù)據(jù)執(zhí)行計(jì)算操作丈屹,判斷位置,顏色以及其他渲染屬性伶棒。
3旺垒、將輸入圖元的數(shù)學(xué)描述 轉(zhuǎn)換為與屏幕位置對(duì)應(yīng)的像素片元,也稱(光柵化)苞冯。
4袖牙、針對(duì)光柵化過(guò)程產(chǎn)生的每個(gè)片元,執(zhí)行 片元著色器舅锄,從而決定這個(gè)片元的最終顏色和位置
5鞭达、如果有必要 可以對(duì)片元執(zhí)行一些額外操作。
例如:判斷片元對(duì)應(yīng)的對(duì)象是否可見(jiàn)皇忿,或者將片元的顏色與當(dāng)前屏幕位置的顏色進(jìn)行融合畴蹭。

  • 開(kāi)發(fā)語(yǔ)言與編程約定

我們以后會(huì)見(jiàn)到OpenGL的函數(shù)多是以gl開(kāi)頭,因?yàn)镺penGL的函數(shù)遵循一定的命名約定鳍烁,它可以告訴我們這個(gè)函數(shù)來(lái)自哪個(gè)函數(shù)庫(kù)叨襟,并且還可以告訴我們這個(gè)函數(shù)的參數(shù)個(gè)數(shù)和類型。
OpenGL的函數(shù)是采用以下的書(shū)寫(xiě)格式:
<函數(shù)庫(kù)前綴> <根命令> <可選的參數(shù)數(shù)量> <可選的參數(shù)類型>

在這里插入圖片描述
  • OpenGL版本比較

早前學(xué)OpenGL的時(shí)候還是1.x版本幔荒,用的都是glVertex糊闽,glNormal等固定管線API。后來(lái)工作需要接觸DirectX9爹梁,shader也只是可選項(xiàng)而已右犹,跟固定管線一起混用著。OpenGL ES 2.0版本開(kāi)始就不再支持固定管線姚垃,只支持可編程管線念链。

OpenGL 基礎(chǔ)理論知識(shí)

1. 坐標(biāo)系與變換

1、在開(kāi)發(fā)OpenGL程序時(shí)积糯,需要用到兩個(gè)坐標(biāo)系掂墓。
一個(gè)稱為對(duì)象坐標(biāo)系 :(物體坐標(biāo)系)第一個(gè)坐標(biāo)系是我們?cè)陂_(kāi)發(fā)中使用的坐標(biāo)系。
另一個(gè)稱為世界坐標(biāo)系:(世界坐標(biāo)系)第二個(gè)坐標(biāo)系又稱為窗口坐標(biāo)系或屏幕坐標(biāo)系看成,在這個(gè)坐標(biāo)系中的單位是像素君编。
2、 在繪制的過(guò)程中川慌,OpenGL會(huì)自動(dòng)實(shí)現(xiàn)從對(duì)象到窗口坐標(biāo)系的轉(zhuǎn)換啦粹,所需要的信息是屏幕中顯示窗口的尺寸和用戶希望顯示對(duì)象空間的大小偿荷。
3、OpenGL中所需要的坐標(biāo)系變換由兩個(gè)矩陣決定唠椭,
即:模型視圖矩陣和投影矩陣,這些矩陣是OpenGL的狀態(tài)的一部分忍饰。
設(shè)置這兩種矩陣的典型步驟包括以下三個(gè)步驟:
(1) 指定我們希望修改的矩陣贪嫂。
(2) 將矩陣設(shè)為單位矩陣。
(3) 修改當(dāng)前矩陣為用戶期望的矩陣艾蓝。

2. OpenGL 顯示圖形流程

在這里插入圖片描述

OpenGL是使用客戶端——服務(wù)端的形式實(shí)現(xiàn)的力崇。
(客戶端):我們編寫(xiě)的程序。
(服務(wù)端):計(jì)算機(jī)圖形硬件廠商所提供的OpenGL實(shí)現(xiàn)赢织。
在沒(méi)有OpenGL的時(shí)候亮靴,CPU與GPU之間傳遞數(shù)據(jù)是通過(guò)控制器內(nèi)存之間傳遞,傳遞速度非常的慢于置,內(nèi)存在復(fù)制數(shù)據(jù)時(shí)茧吊,CPU和GPU都不能操作這個(gè)數(shù)據(jù)。OpenGL很好的解決這個(gè)問(wèn)題八毯,OpenGL創(chuàng)建了緩存區(qū)域搓侄,能夠連續(xù)的管理RAM,保證數(shù)據(jù)傳輸不影響GPU處理數(shù)據(jù)效率话速。

在這里插入圖片描述

3. OpenGL 基本概念

  1. GLEW, GLFW和GLM介紹

The OpenGL Extension Wrangler (GLEW)是用來(lái)訪問(wèn)OpenGL 3.2 API函數(shù)的讶踪。不幸的是你不能簡(jiǎn)單的使用#include <GL/gl.h>來(lái)訪問(wèn)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)鍵盤(pán)消息白指。OpenGL不處理這些窗口創(chuàng)建和輸入留晚,所以就需要我們自己動(dòng)手。我選擇GLFW是因?yàn)樗苄「娉埃⑶胰菀桌斫狻?/p>

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

  1. Shaders

Shaders在現(xiàn)代OpenGL中是個(gè)很重要的概念犬庇。應(yīng)用程序離不開(kāi)它,除非你理解了侨嘀,否則這些代碼也沒(méi)有任何意義臭挽。
Shaders是一段GLSL小程序,運(yùn)行在GPU上而非CPU咬腕。它們使用OpenGL Shading Language (GLSL)語(yǔ)言編寫(xiě)欢峰,看上去像C或C++,但卻是另外一種不同的語(yǔ)言涨共。使用shader就像你寫(xiě)個(gè)普通程序一樣:寫(xiě)代碼纽帖,編譯,最后鏈接在一起才生成最終的程序举反。
Shaders并不是個(gè)很好的名字懊直,因?yàn)樗粌H僅只做著色。只要記得它們是個(gè)用不同的語(yǔ)言寫(xiě)的火鼻,運(yùn)行在顯卡上的小程序就行室囊。
在舊版本的OpenGL中,shaders是可選的凝危。在現(xiàn)代OpenGL中波俄,為了能在屏幕上顯示出物體,shaders是必須的蛾默。
為可能近距離了解shaders和圖形渲染管線懦铺,我推薦Durian Software的相關(guān)文章The Graphics Pipeline chapter

  1. Vertex Shaders

Vertex shader主要用來(lái)將點(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代碼如下:

#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。
第四行g(shù)l_Position = vec4(vert, 1);將輸入的頂點(diǎn)直接輸出陆赋,變量gl_Position是OpenGL定義的全局變量沐祷,用來(lái)存儲(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)來(lái)對(duì)待。
Vertex Shader在本文中沒(méi)有做任何事领突,后續(xù)我們會(huì)修改它來(lái)處理動(dòng)畫(huà)暖璧,攝像機(jī)和其它東西

  1. 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代碼如下:

#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模型上的圖像。

  1. 編譯和鏈接Shaders

在C++中枫攀,你需要對(duì)你的.cpp文件進(jìn)行編譯括饶,然后鏈接到一起組成最終的程序。OpenGL的shaders也是這么回事脓豪。
在這篇文章中用到了兩個(gè)可復(fù)用的類巷帝,是用來(lái)處理shaders的編譯和鏈接:tdogl::Shader和tdogl::Program。這兩個(gè)類代碼不多扫夜,并且有詳細(xì)的注釋楞泼,我建議你閱讀源碼并且去鏈接OpenGL是如何工作的驰徊。

  1. 什么是VBO和VAO?

當(dāng)shaders運(yùn)行在GPU堕阔,其它代碼運(yùn)行在CPU時(shí)棍厂,你需要有種方式將數(shù)據(jù)從CPU傳給GPU。在本文中超陆,我們傳送了一個(gè)三角的三個(gè)頂點(diǎn)數(shù)據(jù)牺弹,但在更大的工程中3D模型會(huì)有成千上萬(wàn)個(gè)頂點(diǎn),顏色时呀,貼圖坐標(biāo)和其它東西张漂。
這就是我們?yōu)槭裁葱枰猇ertex Buffer Objects (VBOs)和Vertex Array Objects (VAOs)。VBO和VAO用來(lái)將C++程序的數(shù)據(jù)傳給shaders來(lái)渲染谨娜。
在舊版本的OpenGL中航攒,是通過(guò)glVertex,glTexCoord和glNormal函數(shù)把每幀數(shù)據(jù)發(fā)送給GPU的趴梢。在現(xiàn)代OpenGL中漠畜,所有數(shù)據(jù)必須通過(guò)VBO在渲染之前發(fā)送給顯卡。當(dāng)你需要渲染某些數(shù)據(jù)時(shí)坞靶,通過(guò)設(shè)置VAO來(lái)描述該獲取哪些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),顏色硝枉,甚至是你喜歡的音樂(lè)和詩(shī)歌廉丽。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)樗緵](méi)有解釋VAO該干的事。
你回頭看下本文的vertex shader(在文章的前面)仇让,你就能發(fā)現(xiàn)我們只有一個(gè)輸入變量vert典奉。在本文中躺翻,我們用VAO來(lái)說(shuō)明“hi,OpenGL卫玖,這里的VBO有3D頂點(diǎn)公你,我想要你在vertex shader時(shí),發(fā)三個(gè)頂點(diǎn)數(shù)據(jù)給vert變量假瞬∩驴浚”
在后續(xù)的文章中,我們會(huì)用VAO來(lái)說(shuō)“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但沒(méi)有用到VAO,你可能會(huì)不認(rèn)同VAO的描述唱蒸。你會(huì)爭(zhēng)論說(shuō)“頂點(diǎn)屬性”可以用glVertexAttribPointer將VBO和shaders連接起來(lái)邦鲫,而不是用VAO。這取決于你是否認(rèn)為頂點(diǎn)屬性應(yīng)該是VAO“內(nèi)置(inside)”的(我是這么認(rèn)為的)神汹,或者說(shuō)它們是否是VAO外置的一個(gè)全局狀態(tài)庆捺。3.2內(nèi)核和我用的AIT驅(qū)動(dòng)中,VAO不是可選項(xiàng) - 沒(méi)有VAO的封裝glEnableVertexAttribArray, glVertexAttribPointer和glDrawArrays都會(huì)導(dǎo)致GL_INVALID_OPERATION錯(cuò)誤屁魏。這就是為啥我認(rèn)為頂點(diǎn)屬性應(yīng)該內(nèi)置于VAO滔以,而非全局狀態(tài)的原因。
3.2內(nèi)核手冊(cè)也說(shuō)VAO是必須的氓拼,但我只聽(tīng)說(shuō)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)行查詢的命令(見(jià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)為是這樣:假如你沒(méi)有創(chuàng)建VAO蕊苗,那OpenGL通過(guò)了一個(gè)默認(rèn)的全局VAO沿后。所以當(dāng)你使用glVertexAttribPointer時(shí),你仍然是在VAO內(nèi)修改頂點(diǎn)屬性朽砰,只不過(guò)現(xiàn)在從默認(rèn)的VAO變成你自己創(chuàng)建的VAO尖滚。
這里有更多的討論:http://www.opengl.org/discussion_boards/showthread.php/174577-Questions-on-VAOs

OpenGL 入門(mén)實(shí)踐

  1. 先來(lái)介紹一個(gè)大神的開(kāi)源opengl項(xiàng)目代碼:

這是現(xiàn)代OpenGL教程系列的第一篇。所有代碼都是開(kāi)源的瞧柔。通過(guò)這篇教程漆弄,你將會(huì)學(xué)到如何在Windows下用Visual Studio 2013或Mac下用Xcode搭建OpenGL 3.2工程。該應(yīng)用包含一個(gè)頂點(diǎn)著色器(vertex shader)造锅,一個(gè)片段著色器(fragment shader)和使用VAO和VBO來(lái)繪制的三角形撼唾。該工程使用GLEW來(lái)訪問(wèn)OpenGL API,用GLFW來(lái)處理窗口創(chuàng)建和輸入哥蔚,還有使用GLM進(jìn)行矩陣/矢量相關(guān)的數(shù)學(xué)運(yùn)算倒谷。所有例子代碼的zip打包可以從這里獲取:https://github.com/tomdalling/opengl-series/archive/master.zip糙箍。
這一系列文章中所使用的代碼都存放在:https://github.com/tomdalling/opengl-series渤愁。
你可以在頁(yè)面中下載zip,加入你會(huì)git的話深夯,也可以復(fù)制該倉(cāng)庫(kù)抖格。

  1. 關(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ū)別 滓玖,可以參考這個(gè)網(wǎng)站:OpenGL, OpenGL ES, WebGL, GLSL, GLSL ES APIs Table

  1. 環(huán)境安裝配置
  • Visual Studio下安裝

代碼在Windows 7 32位系統(tǒng),Visual Studio Express 2013(免費(fèi))下創(chuàng)建和測(cè)試质蕉。你應(yīng)該可以打開(kāi)解決方案并成功編譯所有工程呢撞。

  • Xcode下安裝

Xcode工程實(shí)在OSX 10.10系統(tǒng),Xcode 6.1下創(chuàng)建并測(cè)試的饰剥。打開(kāi)Xcode工程應(yīng)該可以成功編譯所有目標(biāo)殊霞。

  • Linux下安裝

Linux是基于SpartanJ。我在Ubuntu 12.04下簡(jiǎn)單測(cè)試通過(guò)汰蓉。
安裝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

  1. 開(kāi)始編碼
    打開(kāi)main.cpp,我們從main()函數(shù)開(kāi)始。
    首先祝钢,我們初始化GLFW:
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è)窗口蜒什。

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)建的窗口:

glfwMakeContextCurrent(gWindow);

無(wú)論我們調(diào)用哪個(gè)OpenGL函數(shù)铃拇,都會(huì)影響到“當(dāng)前上下文”钞瀑。我們只會(huì)用到一個(gè)上下文,所以設(shè)置完后慷荔,就別管它了雕什。理論上來(lái)說(shuō),我們可以有多個(gè)窗口显晶,且每個(gè)窗口都可以有自己的上下文贷岸。
現(xiàn)在我們窗口有了OpenGL上下文變量,我們需要初始化GLEW以便訪問(wèn)OpenGL接口磷雇。

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

這里的GLEW與OpenGL內(nèi)核有點(diǎn)小問(wèn)題凰盔,設(shè)置glewExperimental就可以修復(fù),但希望再未來(lái)永遠(yuǎn)不要發(fā)生倦春。
我們也可以用GLEW再次確認(rèn)3.2版本是否存在:

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

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

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:

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

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

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

接著呢堰,我們上傳一些數(shù)據(jù)到VBO中。這些數(shù)據(jù)就是三個(gè)頂點(diǎn)凡泣,每個(gè)頂點(diǎn)包含三個(gè)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ū)包含了三角形的三個(gè)頂點(diǎn),是時(shí)候開(kāi)始設(shè)置VAO了鞋拟。首先骂维,我們應(yīng)該啟用shader程序中的vert變量。這些變量能被開(kāi)啟或關(guān)閉贺纲,默認(rèn)情況下是關(guān)閉的航闺,所以我們需要開(kāi)啟它。vert變量是一個(gè)“屬性變量(attribute variable)”,這也是為何OpenGL函數(shù)名稱中有帶“Attrib”潦刃。我們可以在后續(xù)的文章中看到更多類型侮措。

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

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

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說(shuō)明三個(gè)數(shù)字是GLfloat類型巴粪。這非常重要,因?yàn)镚Ldouble類型的數(shù)據(jù)大小跟它是不同的粥谬。
第四個(gè)參數(shù)肛根,GL_FALSE說(shuō)明我們不需要對(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ù)之間沒(méi)有間隔即硼。
第六個(gè)參數(shù)逃片,NULL,假如我們的數(shù)據(jù)不是從緩沖區(qū)頭部開(kāi)始的話只酥,可以設(shè)置這個(gè)參數(shù)來(lái)指定褥实。設(shè)置該參數(shù)為NULL,表示我們的數(shù)據(jù)從VBO的第一個(gè)字節(jié)開(kāi)始裂允。
現(xiàn)在VBO和VAO都設(shè)置完成损离,我們需要對(duì)它們進(jìn)行解綁定,防止一不小心被哪里給更改了绝编。

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

然后告訴OpenGL我們要開(kāi)始使用VAO和shader了:

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

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

glDrawArrays(GL_TRIANGLES, 0, 3);

調(diào)用glDrawArrays函數(shù)說(shuō)明我們需要繪制三角形,從第0個(gè)頂點(diǎn)開(kāi)始,有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é)束了谬运,為了安全起見(jiàn)隙赁,我們需要將shader和VAO進(jìn)行解綁定:

glBindVertexArray(0);
glUseProgram(0);

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

glfwSwapBuffers(gWindow);

參考教程:https://www.e-learn.cn/content/qita/641129
http://huangwei.pro/2015-05/modern-opengl1/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梆暖,一起剝皮案震驚了整個(gè)濱河市伞访,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轰驳,老刑警劉巖厚掷,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異级解,居然都是意外死亡冒黑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)勤哗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抡爹,“玉大人,你說(shuō)我怎么就攤上這事芒划《梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵民逼,是天一觀的道長(zhǎng)泵殴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)缴挖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任焚辅,我火速辦了婚禮映屋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘同蜻。我一直安慰自己棚点,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布湾蔓。 她就那樣靜靜地躺著瘫析,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贬循,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天咸包,我揣著相機(jī)與錄音,去河邊找鬼杖虾。 笑死烂瘫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奇适。 我是一名探鬼主播坟比,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嚷往!你這毒婦竟也來(lái)了葛账?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤皮仁,失蹤者是張志新(化名)和其女友劉穎籍琳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體魂贬,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巩割,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了付燥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宣谈。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖键科,靈堂內(nèi)的尸體忽然破棺而出闻丑,到底是詐尸還是另有隱情,我是刑警寧澤勋颖,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布嗦嗡,位于F島的核電站,受9級(jí)特大地震影響饭玲,放射性物質(zhì)發(fā)生泄漏侥祭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一茄厘、第九天 我趴在偏房一處隱蔽的房頂上張望矮冬。 院中可真熱鬧,春花似錦次哈、人聲如沸胎署。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琼牧。三九已至恢筝,卻和暖如春惊来,著一層夾襖步出監(jiān)牢的瞬間冗疮,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工恤煞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抱究,地道東北人恢氯。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鼓寺,于是被迫代替她去往敵國(guó)和親勋拟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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

  • 譯序 早前學(xué)OpenGL的時(shí)候還是1.x版本妈候,用的都是glVertex敢靡,glNormal等固定管線API。后來(lái)工作...
    威士忌閱讀 6,634評(píng)論 4 51
  • 你好苦银,三角形 圖形渲染管線(Pipeline) 3D坐標(biāo)轉(zhuǎn)為2D坐標(biāo)的處理過(guò)程是由OpenGL的圖形渲染管線(Pi...
    IceMJ閱讀 7,452評(píng)論 2 13
  • 晚清 藏傳紫檀嵌銀絲綠度母造像啸胧,取王木之王小葉紫檀,工藝高超幔虏,局部嵌銀絲工藝纺念,度母頭帶佛冠,慈祥悲憫想括,身上瓔珞清晰...
    書(shū)畫(huà)作品交流閱讀 442評(píng)論 0 1
  • 一切都是那么蹊蹺陷谱,即使一切的一切只是一種邂逅,我想我邂逅過(guò)瑟蜈,但不是跟你烟逊,是跟很多你并不認(rèn)識(shí)的人 ,我想這不一定就是...
    稀罕你的喵閱讀 210評(píng)論 0 0
  • 成長(zhǎng)日志 付愛(ài)寶特種兵第三天 每天早上的八點(diǎn)五十簽到 僅僅三天的時(shí)間讓我已經(jīng)成為習(xí)慣 三天的課程學(xué)到用到很多 課程...
    寶女王閱讀 130評(píng)論 0 0