美高梅4688.com[翻译] 现代OpenGL教程 01 – 入门指南

modern-opengl

看手机游戏《烈火遮天》抄袭《热血传奇》,盛大公司为侵权及不正当竞争将奇天乐地公司、苹果公司、卓易讯畅公司和华为公司诉及法院,要求终止侵权及不正当竞争行为,赔礼道歉并赔偿经济损失1000万处女。日前,北京市海淀区人民法院受理了此案。

译序

早前学OpenGL的时段还是1.x版本,用底且是glVertexglNormal相当于固定管线API。后来做事要接触DirectX9,shader也只是是可选而已,跟固定管线同步混用着。现在干活内容是手机游戏,又改至OpenGL
ES,发现OpenGL的世界就全两样了,OpenGL ES
2.0本开始就不再支持固定管线,只支持可编程管线。

pipe2.0

国内不少素材教程参差不齐,旧式接口满天飞。在知乎张就无异文山会海教程,觉着非常好,就想在一面学顺便翻译下。毕竟手游市场的机会同竞争压力还当较涨,多矣解OpenGL
ES肯定没害处。浮躁功利的条件下重新用怀着同样颗宁静致远的方寸去增强自己基础,长路漫漫,与天王共勉。

接大家,这是现代OpenGL教程系列之首先篇。所有代码都是开源之,你可以GitHub上下载:https://github.com/tomdalling/opengl-series

经这篇教程,你以见面效仿到什么样以Windows下用Visual Studio
2013或者Mac下用Xcode搭建OpenGL 3.2工程。该使用包含一个极端着色器(vertex
shader),一个有的着色器(fragment
shader)和利用VAO和VBO来绘制的三角形。该工程应用GLEW来访问OpenGL
API,用GLFW来拍卖窗口创建及输入,还有使用GLM进行矩阵/矢量相关的数学运算。

顿时听上去有点粗俗,但搭建这样的工程的确怪辛苦的,尤其对于新家。只要解决得了就题目,我们就是可以起来玩些有趣之事物了。

[TOC]

严肃公司诉称,盛大公司是推中国互动游戏产业进步的领军企业,是中国网络游戏产业之领头羊,其商标“盛大”和“SHANDA”被认定为驰名商标。《热血传奇》,业内简称“传奇”,是一模一样缓缓由韩国公司Wemade
Entertainment制作、Actoz
soft负责海外发行的头等网络游戏,盛大公司得到该戏以中原陆上地域的独家代理权,并吃2001年9月始专业运作。作为同样缓慢国内运营时间最漫长之网游,《热血传奇》缔造了重重底家业神话,获得最佳科幻、最佳画面相当大多独奖项,并出了系列产品,是世界上用户规模极老、收益额位居前列的网络游戏。在不少口心目中,《热血传奇》不再单独是同缓打,而是一个陪同自己14年之知心朋友,一栽习惯成自然的存方式。《热血传奇》注册商标已经有所极其高的显著性、知名度及美誉度,其角色设置、场景画面、设计风格等情节曾为民众清楚和认同,具有最高的社会知名度。

收获代码

抱有例子代码的zip打包好自此处得到:https://github.com/tomdalling/opengl-series/archive/master.zip。

立刻等同多重文章被所用的代码都存放于:https://github.com/tomdalling/opengl-series。你得于页面中下载zip,加入你会git的口舌,也得复制该仓库。

正文代码你可以当<code>source/01_project_skeleton</code>目录里找到。使用OSX系统的,可以打开根目录里之opengl-series.xcodeproj,选择本文工程。使用Windows系统的,可以于Visual
Studio 2013里打开opengl-series.sln,选择相应工程。

工里就含有因,所以您莫待再次装或安排额外的事物。如果产生另编译或运行及之问题,请联系自己。

2014年9月,盛大公司察觉奇天乐地公司开了扳平放缓和《热血传奇》极其类似之手机游戏《烈火遮天》,经进一步取证、鉴定,发现《烈火遮天》完全抄了《热血传奇》,在作之角色形象名称、地图场景、技能、动画特效等多单方面跟《热血传奇》构成实质性相似,使得众多玩家针对《烈火遮天》与《热血传奇》及改编自《热血传奇》的泛滥成灾手机游戏发生混淆,更令人对娱乐之源于呢发生严重混淆。另外,奇天乐地公司于加大《烈火遮天》的经过被,假冒盛大公司之名商品、服务号,盗用盛大公司负有著作权的资深网络游戏形象图片,并将严肃公司备商标权的“热血传奇”、“沙城”、“传奇归来”等为拆、组合、突出等各种款式以于宣传受到,刻意为歧义性语言等引起人误会的计对《烈火遮天》进行宣传,使得许多网友对《烈火遮天》及其所在网站与《热血传奇》等多元游戏发生混淆。

关于兼容性的唤起

正文使用OpenGL 3.2,但我会尝试保持如下兼容:

  • 朝后兼容OpenGL 2.1
  • 上前兼容OpenGL 3.X以及4.X
  • 兼容Android和iOS的OpenGL ES 2.0

因OpenGL和GLSL存在重重异版本,本文代码不必然能够不辱使命100%上述兼容。我盼望会配合99%,并且不同版本中要轻微修改即可。

想念只要打听OpenGL和GLSL不同版本里的别,这里十分好得罗列了匹配列表。

苹果店是网络苹果用商店(App
Store)的纳税人、管理者、所有者和Ipad等苹果设备产品之生产者、销售者,其通过网苹果下企业对第三在上传的应用程序加以筛选,并透过提供下载服务赢得可观的分为经济便宜。近来,盛大公司察觉网苹果采用企业也社会公众提供《烈火遮天》的下载服务,公众可以直接通过Iphone、Ipad、Itouch等出品上网络苹果用商店,将《烈火遮天》下充斥至苹果设备中运作并取经济利益。卓易讯畅公司和华为公司通通以该网站上向群众提供《烈火遮天》的下载服务,侵害了严肃公司之著作权。

Visual Studio下安装

代码在Windows 7 32位系统,Visual Studio Express
2013(免费)下开创与测试。你应该好打开解决方案并打响编译所有工程。如果出题目要联系我,或者以补丁发我,我会更新工程。

盛大公司看,各被告因《热血传奇》的知名度,擅自侵犯自己之著作权并进行不正当竞争,已经对社会公众产生严重误导,严重分流了庄严公司之用户,抢占了尊严公司的市场份额并赚取了许许多多非法利润,给盛大公司造成了巨大损失。

Xcode下安装

Xcode工程实在OSX 10.10体系,Xcode
6.1产开创并测试的。打开Xcode工程应可以成功编译所有目标。加入你无法成功编译请联系我。

目前,此案正以越来越审理中。

Linux下安装

Linux是基于SpartanJ。我以Ubuntu
12.04下简单测试通过。

  • 安装GLM,GLFW和GLEW:
    sudo aptitude install libglm-dev libglew-dev libglfw-dev
  • 跻身工程目录:cd platforms/linux/01_project_skeleto
  • 运行makefile:make
  • 运作可执行文件:bin/01_project_skeleton-debug

来自:中国法院网

GLEW, GLFW和GLM介绍

今而发矣工,就被咱开介绍下工程所用到的开源库和为啥用这些。

The OpenGL Extension Wrangler
(GLEW)大凡为此来走访OpenGL
3.2
API函数的。不幸的是您无能够简单的下#include <GL/gl.h>来访问OpenGL接口,除非您想用旧本子的OpenGL。在现世OpenGL中,API函数是在运转时(run
time)确定的,而不编译期(compile time)。GLEW可以以运转时加载OpenGL
API。

GLFW许我们过平台创建窗口,接受鼠标键盘消息。OpenGL不处理这些窗口创建与输入,所以即使待我们好下手。我选择GLFW是因她杀有些,并且爱懂。

OpenGL Mathematics
(GLM)大凡一个数学库,用来拍卖矢量和矩阵等几任何具有东西。旧版本OpenGL提供了近乎glRotate,
glTranslateglScale相当函数,在当代OpenGL中,这些函数已经不有了,我们要好处理所有的数学运算。GLM能以继承教程里提供许多矢量和矩阵运算上帮。

每当马上一连串的持有课程被,我们还编制了一个小型库tdogl故而来用C++代码。这篇教程会含有tdogl::Shadertdogl::Program用来加载,编译和链接shaders。

什么是Shaders?

Shaders在现代OpenGL中凡是个老要紧之定义。应用程序离不开它,除非您懂得了,否则这些代码也不曾任何意义。

Shaders是一段GLSL小程序,运行在GPU上而非CPU。它们运OpenGL Shading
Language
(GLSL)言语编写,看上去像C或C++,但也是另外一种植不同的语言。使用shader就如而写单平常程序一样:写代码,编译,最后链接以一道才转最终之次第。

Shaders并无是个要命好之名,因为它不光只是做着色。只要记得她是独用不同之言语描绘的,运行在显卡上之多少序即使尽。

在初本子的OpenGL中,shaders是可选的。在现世OpenGL中,为了能以屏幕及出示有物体,shaders是必须的。

啊可能将近距离了解shaders和图渲染管线,我推荐Durian
Software的连带文章The Graphics Pipeline
chapter。

主程序 Shader程序
语言 C++ GLSL
主函数 int main(int, char**); void main();
运行于 CPU GPU
需要编译?
需要链接?

那shaders实际上干了什么?这取决是啊种shader。

Vertex Shaders

Vertex
shader主要用以以沾(x,y,z坐标)变换成不同的接触。
极端只是几哪样子中的一个碰,一个沾吃vectex,多独点于vertices(发音为ver-tuh-seez)。在本教程中,我们的三角需要三独极端(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这个shader使用GLSL版本1.50.

第二行in vec3 vert;晓shader需要那么一个极限作为输入,放入变量vert

其三推行定义函数main,这是shader运行入口。这看起来像C,但GLSL中main勿需要带其他参数,并且永不回到void。

第四行gl_Position = vec4(vert, 1);拿输入的巅峰直接出口,变量gl_Position是OpenGL定义的全局变量,用来存储vertex
shader的输出。所有vertex shaders都亟需对gl_Position进展赋值。

gl_Position是4D坐标(vec4),但vert是3D坐标(vec3),所以我们要用vert转换为4D坐标vec4(vert, 1)。第二独底参数1是赋值给第四维坐标。我们会于此起彼伏教程被拟到重多关于4D坐标的东西。但现,我们设知道第四维坐标是1即可,i可以忽略它就是将她看作3D坐标来比。

Vertex
Shader在本文中从不举行另外事,后续我们见面修改它来处理动画,摄像机和外东西。

Fragment Shaders

Fragment shader的第一成效是计算每个需要绘制的比如说素点的颜料。

一个”fragment”基本上就是是一个像素,所以若可当部分着色器(fragment
shader)就是比如说从方色器(pixel
shader)。在本文中每个片都是一像素,但就并无连续如此的。你可更改某个OpenGL设置,以便获得比像素更粗的有些,之后的稿子我们会讲到之。

正文所动的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);用出口变量设为白色。vec4(1.0, 1.0, 1.0, 1.0)凡是创立一个RGBA颜色,并且红绿蓝和alpha都要为极端酷价值,即白。

今昔,就会为此shader在OpenGL中绘制出了纯粹白色。在此后的章中,我们还会见在不同颜色及贴图。贴图就是你3D模型上之图像。

编译和链接Shaders

于C++中,你用针对你的.cpp文件进行编译,然后链接到一起构成最终之次。OpenGL的shaders也是这么回事。

在即时篇稿子中之所以到了零星个可复用的类,是故来处理shaders的编译和链接:tdogl::Shadertdogl::Program。这点儿只类似代码不多,并且产生详实的笺注,我建议你看源码并且失去链接OpenGL是怎么做事的。

什么是VBO和VAO?

当shaders运行于GPU,其它代码运行在CPU时,你待发种植方法将数据从CPU传为GPU。在本文中,我们传递了一个三角的老三单顶峰数据,但在重充分的工程被3D模型会来为数不少个极,颜色,贴图坐标和其它东西。

即就是是咱为何用Vertex Buffer Objects (VBOs)和Vertex Array Objects
(VAOs)。VBO和VAO用来拿C++程序的数码传被shaders来渲染。

当原来本子的OpenGL中,是透过glVertexglTexCoordglNormal函数把每帧数据发送给GPU的。在当代OpenGL中,所有数据必须通过VBO在渲染之前发送给显卡。当你用渲染某些数据经常,通过安装VAO来描述该得到哪些VBO数据推送给shader变量。

Vertex Buffer Objects (VBOs)

先是步我们需要打外存里上传三角形的老三独顶峰到显存中。这就是是VBO该干的行。**VBO其实就是显存的“缓冲区(buffers)”

相同弄错包含各种二进制数据的字节区域。**你能够上传3D坐标,颜色,甚至是若喜欢的乐以及诗词。VBO不体贴这些数量是甚,因为其只是针对内存进行复制。

Vertex Array Objects (VAOs)

仲步我们设就此VBO的数额在shaders中渲染三角形。请牢记VBO只是平等片数据,它不晓得这些数据的类。而告知OpenGL这缓冲区里是啥类型数据,这行就归VAO管。

VAO对VBO和shader变量进行了连。它描述了VBO所包含的数据类型,还有该传递数据给哪个shader变量。于OpenGL所有不准确的技巧名词中,“Vertex
Array Object”是太腐败的一个,因为它们从无讲VAO该干的从事。

公回头看下本文的vertex
shader(在篇章的前方),你就会觉察我们只有出一个输入变量vert。在本文中,我们因此VAO来说明“hi,OpenGL,这里的VBO有3D顶点,我眷恋使你当vertex
shader时,发三单极数据被vert变量。”

在继承的文章被,我们会用VAO来说“hi,OpenGL,这里的VBO有3D顶点,颜色,贴图坐标,我怀念如果而于shader时,发顶点数据为vert变量,发颜色数据给vertColor变量,发贴图坐标给vertTexCoord变量。”

深受采用及只OpenGL版本的用户的唤起

要你于原有本子的OpenGL中使用了VBO但没有就此到VAO,你或会见不承认VAO的叙说。你晤面争论说“顶点属性”可以就此glVertexAttribPointer拿VBO和shaders连接起来,而休是为此VAO。这取决你是否认为极属性应该是VAO“内置(inside)”的(我是这样认为的),或者说她是否是VAO外置的一个大局状态。3.2根本和我用的AIT驱动中,VAO不是可挑选

  • 没有VAO的封装glEnableVertexAttribArray,
    glVertexAttribPointerglDrawArrays犹见面招致GL_INVALID_OPERATION错误。这即是为底我认为极属性应该放权于VAO,而不全局状态的故。3.2外核手册为说VAO是必的,但我单独听说ATI驱动会抛错误。下面描述引用自OpenGL
    3.2内核手册

怀有和终端处理有关的多少定义都当封装在VAO里。
相似VAO边界包含有改变vertex
array状态的指令,比如VertexAttribPointer和EnableVertexAttribArray;所有应用vertex
array进行绘图的命,比如DrawArrays和DrawElements;所有对vertex
array状态进行询问的一声令下(见第6章)。

无论如何,我吧掌握为甚会有人当极属性应该在VAO外部。glVertexAttribPointer起早于VAO,在当下段时间里及点属性一直让认为是大局状态。你该能够看得出VAO是同等种植改变全局状态的行措施。我更倾向于认为是这样:假如你没有创造VAO,那OpenGL通过了一个默认的大局VAO。所以当你下glVertexAttribPointer时,你依旧是以VAO内修改及点属性,只不过现在起默认的VAO变成你协调创办的VAO。

此出再次多的议论:http://www.opengl.org/discussion\_boards/showthread.php/174577-Questions-on-VAOs

代码解释

好不容易!理论都说了了,我们初步编码。OpenGL对于新家而言不是特地融洽,但如你知道了事先所介绍的定义(shaders,VBO,VAO)那若便从来不啥问题。

打开main.cpp,我们从main()函数开始。

率先,我们初始化GLFW:

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

glfwSetErrorCallback(OnError)这一行告诉GLFW当错误有时调用OnError函数。OnError函数会抛一个含错误信息的死去活来,我们能从中发现哪里错了。

下一场我们因而GLFW创建一个窗口。

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?");

拖欠窗口包含一个迈入兼容的OpenGL
3.2外核上下文。假如glfwCreateWindow挫折了,你应当下降OpenGL版本。

创立窗口最后一步,我们理应安装一个“当前”OpenGL上下文给正创立的窗口:

glfwMakeContextCurrent(gWindow);

甭管我们调用谁OpenGL函数,都见面潜移默化至“当前齐下文”。我们才会就此到一个上下文,所以设置完毕晚,就别管它了。理论及吧,我们得发差不多单窗口,且每个窗口都得生出投机的上下文。

今天咱们窗口起了OpenGL上下文变量,我们要初始化GLEW以便访问OpenGL接口。

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

此间的GLEW与OpenGL内核有点小题目,设置glewExperimental哪怕好修复,但想更未来永久不要产生。

咱吧得据此GLEW再次确认3.2本是否是:

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

LoadShaders函数中,我们采用仍课程提供的tdogl::Shadertdogl::Program些微独八九不离十编译和链接了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函数中,我们创建了一个VAO和VBO。这是第一步,创建和绑定新的VAO:

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

接下来我们创建及绑定新的VBO:

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

随后,我们上传一些多少到VBO中。这些数量就是三单极,每个终端包含三只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);

如今缓冲区包含了三角形的老三单极端,是时起设置VAO了。首先,我们应有启用shader程序中之vert变量。这些变量能为拉开或关闭,默认情况下是倒闭的,所以我们要敞开它。vert变量是一个“属性变量(attribute
variable)”,这吗是为何OpenGL函数名称被发出带“Attrib”。我们可以在后续之章中视重复多路。

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

VAO设置极端复杂的一些即使是产个函数:glVertexAttribPointer。让咱先调用该函数,等会见解释。

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

率先只参数,gProgram->attrib("vert"),这虽是深需要达到传数据的shder变量。在斯例子中,我们用发多少给vertshader变量。

亚单参数,3表明每个终端需要三独数字。

其三个参数,GL_FLOAT证明三单数字是GLfloat列。这十分重大,因为GLdouble型的数额大小和它是不同之。

季独参数,GL_FALSE征我们无需针对浮点数进行“归一化”,假如我们下了归一化,那是值会被限为极端小0,最深1。我们不待对咱们的顶进行限制,所以这参数为false。

第五独参数,0,该参数可以于终端之间时有发生距离时采取,设置参数为0,表示数据里面从来不距离。

第六只参数,NULL,假如我们的数额不是自从缓冲区头部起以来,可以装这个参数来指定。设置该参数为NULL,表示我们的数由VBO的首先独字节开始。

今日VBO和VAO都安装完成,我们要针对其进行解绑定,防止同一请勿小心给哪给改了。

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

至此,shader,VBO和VAO都备好了。我们可初步在Render函数里绘制了。

先是,我们先行清空下屏幕,让它成为纯黑色:

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

接下来告诉OpenGL我们只要起来应用VAO和shader了:

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

最终,我们绘制出三角形:

glDrawArrays(GL_TRIANGLES, 0, 3);

调用glDrawArrays函数说明我们需要绘制三角形,从第0只终端开始,有3独顶峰被发送至shader。OpenGL会在目前VAO范围外确定拖欠打哪得到极限。

顶点将见面从VBO中取出并发送到vertex
shader。然后三角形内的每个像素会发送给fragment shader。接着fragment
shader将每个像素变成白色。欢呼!

兹绘制了了,为了安全起见,我们要用shader和VAO进行解绑定:

glBindVertexArray(0);
glUseProgram(0);

最后一项事,在我们看出三角形之前要切换帧缓冲:

glfwSwapBuffers(gWindow);

以帧缓冲为换成前,我们见面绘制到一个不可见的离屏(off-screen)帧缓冲区。当我们调用glfwSwapBuffers每每,离屏缓冲会化屏幕缓冲,所以我们便会当窗口及见内容了。

更加看

在此起彼伏文章中,我们会对三角形进行贴图。之后,你会效仿到一点矩阵变换知识,就可以用vertex
shader来实现3D立方体旋转。

当当时下,我们开创办3D场景并交由多单物体。

又多现代OpenGL资料

噩运之是,我只得跳了许多情,防止以课程的字数过长。后面还有多好之现世OpenGL资料能满足你的求知欲:

  • An intro to modern
    OpenGL
    by Joe Groff of Durian Software
  • Learning Modern 3D Graphics
    Programming
    by Jason L. McKesson
  • A collection of simple single file OpenGL
    examples
    by Jakob Progsch
  • OpenGL Step by
    Step by
    Etay Meiri
  • All about OpenGL ES
    2.x
    by Diney Bomfim
  • The OpenGL Progamming book on
    Wikibooks
  • Tutorials on the OpenGL
    wiki
  • OpenGL 4
    tutorials
    by Donald Urquhart (Swiftless)
  • open.gl by Alexander
    Overvoorde
  • OpenGLBook.com
    by Eddy Luten
  • The official OpenGL SDK
    documentation
  • Compatibility tables for OpenGL, OpenGL ES, GLSL, and GLSL
    ES
    by Sugih Jamin

翻译更多内容请走huangwei.pro

发表评论

电子邮件地址不会被公开。 必填项已用*标注