OpenGL教程 002 设置OpenGL用C++创建一个窗口

Setting up OpenGL and Creating a Window in C++

上一次我们讲了关于opengl是什么,一点点关于opengl怎么工作的
还有就是这系列会包括什么
如果你们没有看过这个系列的视频,那么去看这个地方
今天我们开始进行这个系列并且写一些代码
我们会完成一些工作,会获得一个【opengl窗口】
展示并且会画一个【三角形】
这个系列里面,对比c++系列我想明确地做更多具体的方法
在我们开始写代码之前, 我会讲很多的解释和很多的理论
在这个系列里面我仍然想要这么做
因为我认为对于在事实上理解任何事物是怎么运作的是很重要的
但是
在这系列只是最初的地方,我只想用一些代码来讲解
我只想实际上写一些代码
然后让一些东西出现在屏幕上
所以希望你们有些进步的感觉
比以前要好一些,这就是我们实际上要收获的感觉
一周一次的继续下去
有一个理论视频只讲opengl是怎么实际工作的或者屏幕背后实际上发生了什么
现在我们今天的目标是创建一个窗口,我想要能够
用我的操作系统去给我创建一个窗口,这样我的应用就实际地在这个窗口里面了,然后
希望我们以后能够在这个窗口里面画出所有的图形,现在,这个系列明确地,我想
我想
拥有
多平台支持,我想人们能够在windows,mac和linux上面写这代码并且能够运行
它应该要能运行在这三个平台上
这也就意味着要这样做
我们需要一些方法去创建设置窗口
并且创建窗口是具体的明确平台
所以,换句话说,你在windows上创建一个窗口用问win32
通过win32 api,所以实际上你是用windows的api去做的
去说,嘿,我想要一个窗口,因为你创建一个窗口的这个方法是特定于这个操作系统的
因为这就像一件操作系统级别的事情,如果我我在写一个游戏引擎,这就是我可能会做的
我可能只是明确地设置这个窗口,去用明确的操作系统的api
对于每一个平台,我都想能够支持,这个系列不是
如何去写一个游戏引擎,那会是以后的另一个系列,这个系列只是明确地关于opengl和opengl如何工作和如何
去写opengl的代码,所以我们不会真的去关心怎样设置一个窗口这些
我们只是想去写一些opengl的代码,所以我会明确地用一个库,基本上用这个库去做
并且这库会给我提供合适的平台层,也就是说,这会
为我提供一个窗口创建的实施代码,并且在
windows,mac和linux上管理代码,所以每个人都能够使用,并且还有很多的库让我们做得到
【但其中一个我们要用的是GLFW(以后打小写了),我喜欢glfw的原因是】
因为它实际上是一个轻量级的库,对我们来说创建一个窗口,创建一个opengl
上下文(context),并且给我们权限去基础操作,比如说输入
这已经够了。它能做到的不像SDL那样,那是一个全类型的
它实际上就像一个渲染器,所以你可以在屏幕上画正方形、三角形或者是你想到的任何东西
那会是Directx或者是opengl的实现
我不想写我们自己的东西时用到一大堆的框架
我想要的是自动化,第一步就是我想要创建一个窗口,但我不想
为每个平台写不同的实现
我想要这代码能够跨平台,所以我用glfw这库,只是因为这适合我
再次重申,我可以写代码,但这意味着我要写3次(3平台各1次)
windows,mac还有linux,这很浪费时间,也不是这系列的真正目的
所以希望每个人理解我为什么这样做
好,让我们继续,下载glfw,你去这个简介下面这个url里面下载(glfw.org)
你会进到这个网页,这里我们关心的有两点
首先是只下载glfw3.2.1,这是我们实际想要的,另外,在
文档里,有一些关于如何创建窗口的样例代码,你能看到这些代码很整洁
基本上我们要做的
就是初始化glfw,然后我们就能创建窗口,这里有一个例子,如果你想创建opengl context
我们只需调用这个函数
然后就能开始一个推动事件的循环,去保证窗口在要关闭的时候才会关闭
你能看到我们是在这里写opengl的代码
这是非常重要的,这也是我们确切开始的地方
这里回到顶端,回退到glfw然后下载所有的glfw源码
这是另外一件我想要题一下的事,如果我在写,如果这是一个游戏引擎系列的一部分,我在
认证做一个应用,我会下载源码后build,再作为一个
独立项目加进vs再编译进静态库再连接到我的主应用里面
这样如果我需要调试的话,我这里有源码,这就没什么缺点了
我喜欢我的项目里面包含很多的源码
然而这次只是opengl,我们不用浪费时间在这些上面,我只需要为我的平台拿到
pre-build的二进制文件然后build
要这样做我们要去下载,你能看到这有windows
pre-compiled二进制文件,所以windows有prebuild二进制文件,mac和linux也有,也就是说你要下载然后编译源码
这里有一个导航,如果你是这两平台之一的你可以跟着这个做,我认为人们会运行出错,因为
这不是最琐碎的任务,而且像这样的系统到处都是,
所以你需要帮助去编译成linux的格式
加入我的discord,在这个网址 thecherno.com/discord/
里面有很多的人,他们会很乐意帮你解决这些问题
这里因为我们是windows系统,在这个系列开始前我已经下载好了对应的
二进制文件,另一个要说的是我们有32位和64位的二进制文件
我总是收到应该选哪个的问题,大部分人认为我用的是
windows64位,所以我应该选择windows64位的二进制文件
这是不对的,实际上你想要的
这是架构的问题,你要选择对应的架构的去build,如果我们设置vs项目是win32或者是
或者是x86,那就应该选32位的,如果是基于64位或x64的
那我们就选另外一个,所以这问题实际是基于你的平台架构是什么
所以你就如何编译你的应用
不是你在用什么操作系统
当然,64位应用不能在32位操作系统上运行,但如果
你是用64位操作系统,比如说windows
10 64位,你也可以运行32位应用或者是64位的,所以你下载的实际上取决于
你想要编译的应用是多少位,那这里只用一个32位的应用所以我们不需要64位的
在别的更正式的项目,我大概会用64位的,这里没有太多区别
这很容易去切换,不像是要一整个都要解决,不像我们要写不同的代码或者用
相当多的时间去做同样的东西,保持简单就好
这里我们用32位的,点击windows 32位的然后下载
ok,在这里面你下载了1个glfw文件夹和一大堆库,我们讲到的要设置它们
首先我们需要创建1个vs solution
这里我用的是vs 2017社区版(就是免费白嫖的那个版本),然后点击file->new->project
我要确保是在c++下面。然后选择empty project作为我的模板,我们在创建一个
新项目分支从路径这里面,然后更改路径,从document到
c:/dev/YouTube/opengl,你可以设置成别的,我喜欢这样,将所有的
教学类的东西放到c:/dev下面,不是在user(中文版是用户)文件夹下面
我没有将所有的都放进去,就只是c:/dev还有
opengl和别的放在YouTube文件夹里面的东西,因为这是youtube系列的
然后命名为opengl再点ok
好,我们得到了一个vs solution并且这个项目里面任何东西设置得看起来相当可以,如果你想要设置得更合适
或多或少的设置一个更好的路径,因为vs的默认
设置新project和solution的方式对于我个人喜好来说有点奇怪
看我之前的c++里面关于vs设置的视频,这里有一个链接
现在花时间做的这些并不是特别必要,但还请去看看视频
如果你想要了解如何设置得更合适的话,好,我们回到今天要做的
尽量快点设置完glfw,在source file,有一件事情我要做的是,点击project name
点击show all file然后创建一个新文件夹,命名为
src(也就是source),show all file实际上是模仿windows explorer的文件结构和目录结构,这些我也有在video里面讲到,链接放在这里,可以去看看
如果你不确定,我在这下面添加一个“Application.cpp”文件,这是我们的主文件,里面带着主函数
点击add,然后得到一个普通的c++文件,现在要做的就是
写上iostream,确保能够在主函数上运行起来,我写入了std::cout<
我们需要添加包括目录,还需要把lib文件加到linker里面,linker是链接所有文件并且能匹配所有的
让我们来看看怎么设置
右击opengl,点击属性,现在最重要的是事情是你是在全配置里面
并且是全平台,这是我们不喜欢的,但现在,确保是在全设置,然后不是release
如果你现在在修改release,然后你实际上是在debug模式下,这是不会有效果的
选择all configuration,能得到所有错误信息,所以都选这个,
在c/c++下,我们添加一个目录,就是我们刚刚做的那个
打开那个目录,复制路径然后放进去,现在我们不想这么做,因为其他用的不一定存在这个路径下面
我们通常创建一个和项目相关的,我喜欢创一个和solution目录相关的
vs有一个宏给我们,这是我们当前的solution目录,如果我们打开这里的这个tab,就会进入到宏里面,然后你可以输入solution目录,然后你能看到自动匹配上路径
这就是solution目录,我们用这里的,然后根据我们要包含的路径,现在打上去,这里有一个反斜杠,结尾也要跟上一个,然后其他的也这么整
ok,这就是我们要包含的目录了,如果你想要确认是否正确
你可以点edit然后看一下,将值复制出去
放进文件系统里面,回车,就会跳到对应的目录,现在你已经设置完了
通过这里的配置,文件里面的那句引用就能工作了,因为我们包含了这个glfw的目录,ok
然后我们接着可以在linker里面设置库的目录
我现在设置一个添加的库进去,这和之前的很类似,来到dependencies,实际上我是回退到文件夹里面然后复制路径
在glfw下面,我们有vc2015
整完后我们继续,表明哪个文件我们想要链接哪个不想要,我不知道
为什么它们在这里,但这是默认的,默认自带的库,我们可以删掉它们,这样变得干净许多,再打上我们想要链接的库glfw3.lib,带上这个文件
如果我这里进行得过快,我会有一个视频来讲一些细节,这里不想花上一整天时间,所以去看一下做好的视频吧,现在另一件事情是链接opengl
点ok,已经把需要的都设置上去了,你能看到我们的编译器
已经重置了,如果我们按ctrl+f7去编译,应用会编译成功,但现在还没有链接成功
因为你能看到我们在用一个opengl函数,但缺没有链接到opengl
但他们编译成功,我们关心的就是这里面种类是否齐全,右键build
这就会编译并且连接整个应用
让我们来看看,我们得到了一些信息,首先我们得到一个无法修复的额外符号
重申一下,我不是一个看error list的人,你应该要看的是output,因为这是一个列表,这种情况下里面总是些没用的信息,但output里面能给你更多的细节
ok, 这是一种默认lib冲突,不要慌,只是一个warning,明确说明只是一个烦人的warning,我们不需要去考虑修复,这根本不重要,但是,这里我们有gl clear的不可修复的exception
这里也有一大堆window stuff的不可修复的,因为我之前删了很多库,现在我们再次把它们加回来,但首先我们要修复的是
gl clear,我们可以通过连接opengl库去清掉这些错误,所以发生了什么就是我们得到了一个链接错误,如果你们
不知道c++linker是如何工作的,看回视频,因为我已经讲过了link是如何工作的,现在是找到gl clear函数的定义,这个定义在opengl库文件里面
所以我们要链接到那里,
在dependencies,我加了一个分号,再加opengl32.lib
如果我点ok,然后
我build,你能看到第一个错误已经重置了
事实上,第一次解决的符号问题只是一个设备的通知问题,这是基于windows类型的api
好,我们继续,现在添加进去,在这之前,实际上我想
展示给你们一种方法,这样你也能找到这些东西,我是故意删掉所有的文件的,因为
我想展示给你们看这些东西是如何运作的,并且是如何设置它们的
但如果你看到像这样子的错误,因为它们倾向于
相当普遍,有时如果你没有设置正确,你能看到函数名称被设备通知注册了
现在我们抓住这个点,然后复制到谷歌上看看,这是微软的文档
这实际上是一个函数,我们用来连接,我们不知道它在哪,如果我们往下翻
你能看到这个库,它在user32.lib
所以我们能做的就是复制,然后连接上去,这样子就可以继续
在这里我打上去后回车然后ok,再试着build一次,你能看到这个少了很多错误
这里一部分基本上是创建方法然后交换缓冲,并且所有的东西都是,我再做一次一样的
复制这个,然后到谷歌上面搜,翻到下面,你能看到这是在gdi32.lib,所以回到项目里再连接上去
然后ok后,再次编译代码,好,只剩一少部分了
再次复制上去,然后这个是shell32.lib,回到这里还是这样,再build,ok
已经没有错误了,如果我们按f5,或者本地调试去运行我们实际的应用,你能看到我们得到了一个黑色的屏幕
现在,所有手动的linking我已经做完了,你自己不需要去这样做,当你在vs新建一个空project的时候
事实上你能看到这一大堆的linking已经存在了,包括像kernel32.lib这样的,我只是想删掉它们给你们展示它们如何工作如何连接各种东西的
我希望你不需要做这个,这只是一个例子。
现在我们得到了一个黑色屏幕,让我们快速画一个三角形,实际上我画三角形用legacy opengl
因此在第一个视频里我们讲了关于什么是legacy opengl,还有为什么这里我们不用这东西
legacy opengl是最快的方式,现在我能用的,像是五行代码
就能在屏幕上画出一个三角形,现在我的目的是确保opengl能运行起来而不是写
再次说一下,现在我不是在写一个图形引擎,所以
同时你不应该用像是Seat Opengl这样的,专业的应用完美地适合调试人员,需要意识到即使有些事情是令人沮丧的,
如果你只是暂时写下来去测试,那完全没有问题
所以,记住这一点。这里我们要重做的是gl clear。因为事实上我打了gl begin
gl triangle,然后这是你们获得的一种经验和legacy opengl cars,在gl beginning和gl end之间,我们想要确定
三个顶点,我想要写在gl vertex2f里面去用来确定组件顶点的种类或者是2d
现在通过默认我们的项目矩阵在opengl里面
是在负向的一点和在每个轴的每个维度上都有一个,我们会讲更多的项目矩阵,并且所有的这些东西都在未来的视频里
再次,这里只是画一个三角形,我写上0.5f在负向,然后也给y的负向写上0.5f,然后,我想要让它在中间,所以
这里x上给0f,然后是一个正向y的0.5f,然后这里x给正向的0.5f,然后是负向的y0.5,我应该已经画出一个三角形了,事实上它是这个形状
让我们按下f5,然后你能看到我得到了一个三角形,在屏幕的中间,看起来不错,ok,现在我们可以总结了
opengl是能运行了,总结这个视频,我们事实上完成了每一件我们想要做的,我们获得了一个opengl窗口
每一件都在我们的应用文件里面
我们会将它移到一个类里面,或者是别的更加简单的,我们将会在下次实现
但总体再说一次,我们不打算花太多时间在创建一个api上面,因为我们是学习opengl的
我们已经得到了一些东西并且运行起来了,你们可以在你们的电脑里面重写这个代码,并且希望你们能能得到一些有益的东西
最后做一个有点好看小型的opengl应用,可以就只有一个三角形
如果继续下去的话,对于这个系列中的所有代码,现在该如何处理更多的东西
我实际上鼓励你们复制下来,因为当你们复制代码的时候,即使你只是从屏幕上复制代码,你实际上也会学到东西,因为是你自己敲进去了
就像当你遇到新面孔的人很多次,你遇到一个不介绍自己的人,然后说他们的名字,然后你会马上忘了他们的名字,但如果你实际上叫回他们的名字,就像hey,bob
然后你会马上记起他们的名字,这也是一样(好难翻译,硬翻,反正就是多写多练的意思),我喜欢人们复制代码这个主意,他们复制然后实际上他们自己手动敲进去,因为你一旦这么做了
就会形成肌肉记忆,实际上你就会学得更快,如果你想要源码
我把它提供给了你们,如果你上过这个网站patreon.com/TheCherno
但如果你你上patreon.com/TheCherno,你赞助并且支持这个系列,你能再github上获得代码的实际权限,那是独立于每一集,只是我做的其他的系列的,所以,如果你想要源码,你想要
帮助Spoil系列,或者你帮助支持这系列,能肯定你基本上能获得奖励,然后我可以做更多的视频,这也是在patreon上的一大堆奖励,当然,其他也是
所以我真的感谢我从那里获得的帮助和支持,那是让我坐下来做视频,非常感谢。下一次我们将把这抽象成一个类
并且讲一讲mordern opengl,因为我们现在做的是我们已经创建了一个opengl context,和一个opengl window,还有很多东西我们实际上被限制在opengl1.1
windows有它自己的渲染api,DirectX,Direct3d,所以实际上它们不向你提供函数,你需要mordern opengl
我在welcome to opengl视频里面提到过
那是通过我们的gpu驱动提供给我们,所以我们下次需要做的是如何获得这些函数
在新版的opengl app里,从Algae和我们的gpu驱动里,所以实际上我们能够
我们想要能够调用这些函数,我们需要做什么,这就是我们下次讲的
可能把这个移动到一个类里面,还有其他所有的东西,还有一些别的东西。