您的位置:首页 > 编程语言

【图形学与游戏编程】开发笔记-入门篇3:d3d,opengl以及GPU

2016-07-20 09:35 344 查看
(本系列文章由pancy12138编写,转载请注明出处:http://blog.csdn.net/pancy12138)

在上一篇文章中,我们讲了一些需要的基础知识,例如c/c++,线代,windows程序架构这些。这些知识属于很多程序开发和设计所通用的基础。那么这一节我们来讲一些图形学所专属的基础部分。

首先,提及游戏开发,不得不提的一个东西就是显卡。不要说游戏开发人员,就算是经常玩游戏的人也很清楚显卡在游戏程序中起着极其重要,甚至可以说是最为重要的作用。但是,大部分从未接触开发层的人可能并不清楚显卡究竟是个什么玩意。下面我们来为大家讲解关于显卡的一部分知识(当然啦,这里讲解的都是工作层面的知识,不会给大家宣传神马四路泰坦,1080ti这些的,卡巴基佬可以先别急着激动

)。首先第一个给大家扫盲的就是,显卡并不是和显示器类似的“感光装置”,而是和cpu类似的一种“运算装置”。也就是说虽然这货的名字叫显卡,但是实际上是一个运算器。那么接下来大家肯定有一些疑问了,比如:

1,游戏程序和普通的程序区别很大吗,为什么需要一个专门的运算装置来做运算?直接用CPU难道会出神马问题吗?

2,既然CPU已经可以作为运算器了,那么要显卡做运算有什么意义?它算的比CPU快吗,如果不比CPU快的话那么要它有神马用,如果比CPU快的话那么要CPU有神马用?

3,显卡既然有运算能力那么能不能在不玩游戏的时候也不浪费它的能力,比如让我的机子反应快一点啥的?

下面我们就来解释这些问题。

首先是游戏程序为什么需要单独的运算器。大家如果学过算法的话,应该都听闻过时间复杂度这个东西,也就是O(n),O(n^2) 这些,那么接下来我们大致的估算一下一个游戏每秒需要运算的n的次数。首先我们将游戏的算法分为三种,其一是几何体级别的算法,n的次数与之前我们说的几何体的顶点以及索引数量有关系,其二是光栅化级别的算法,这一部分的n的次数是所有几何体的三角面的所包住像素点数量之和,一般会比几何体的矢量点数量多个好几倍。其三是屏幕空间的算法,复杂度就是屏幕像素点的个数。随着游戏质量的逐步提升,第一种算法,也就是几何体级别的算法的n会越来越大,现在的一个大型游戏描述一个场景的顶点就已经可以达到几百万甚至几千万的数量级了。然后是光栅化部分,这里光栅化之后的点一般来说是高于几何体的点数量的,目前一个场景估计最终光栅化的点也会有个几百上千万。最后是屏幕空间的算法,这个最好估计,对于一个高清屏幕来说n的数量就是1920*1080个点。也就是大概来说是200万左右,可以看出比前面的都少。因此现在很多算法的优化
都企图将光栅化的部分转移成屏幕空间的部分,像ssao,deferred lighting这些。那么现在我们说的是运算出一个图片所需要的n的次数,对于一个游戏来说,一秒钟要想流畅运行的话至少得有个30帧才算是靠谱的吧,那么n的数量还得乘以30。那么现在的n的数量大家可以想象大概是多少了,大概已经过亿了。好,那么现在我们回头来看算法复杂度,当n过亿的时候,神马算法才能保证他流畅运行呢?很明显,以当代的运算来说,只能是O(n)的算法。但是事实上,因为这个当量过大,我们不得不考虑算法的常数系数的大小,假设我们所有的渲染算法的常数项加起来有几十左右(其实一次抗锯齿估计就得个几十次,再加上ssao,shadowmap的柔化估计上百次都有可能

),那么最终的每秒运算次数估计几十亿都是很容易的,注意这里的一次运算还是指的我们的循环次数,具体里面一条指令运算多少次还没有再继续乘。这个时候我们回头来看看CPU的运算速度,很明显差的十万八千里,大家做过ACM竞赛的估计体会更深,别说几十亿的级别,就算是一秒几亿的级别也很容易就在赛场上TLE了。那么现在我们就明白为什么需要专用的运算器了吧,游戏程序可是非常需要运算速度的一项产品。

接下来我们谈到GPU与CPU作对比,首先从上面的介绍里大家可以看出,很显然GPU的运算速度是比CPU快的,不然我们不会用它来弥补CPU的不足,那么他到底是如何变快的以及他为什么不能代替CPU呢,下面我们来从他的架构讲起。

首先我们先看CPU的运算瓶颈,如果大家学过计算机组成原理的话,都会知道,CPU虽然是运算装置,但是它里面并不是全都是用于做逻辑运算的运算器,除了运算器以外,它里面还有一大堆的寄存器,微控制器等一系列的装置以保证一些基础的汇编指令能够准确的被执行。目前来说提升单个CPU的运算速度一般就是提升主频这种办法,那么还有一种减轻其负荷的办法就是多核,现在的CPU一般都有很多个运算核,这种方法也可以加大其运算速度,但是这种方法有个问题,首先是以CPU繁杂的架构来说,添加运算核心的代价非常的大,所以大家电脑上的CPU虽然都是多核的,但是大都属于4-8核的这种。还有就是提升核心只能是对于一些并行程序提升速度,对于不能并行的程序,例如最简单的冒泡排序,他就没有办法。那么什么是可并行的程序的,比如一道题目要求给两组数据进行排序,并把第一组和第二组的排序结果拼成一个数组,那么两组排序可以分给两个核心去运算,然后算完就可以拼到一起了。这就是可以并行的程序。如果现在变一下要求,我们要先把两组数据合成一个数组,再把这一个数组排序,这一个数组的排序我们就不能拆开给两个运算核心去解决,因为这些数据之间是有关联的,拆开了就没办法执行算法了。

接下来我们来分析游戏程序,首先游戏程序是否是一种并行的程序呢,很明显,他不仅仅是可并行,他是高度可并行的程序,因为无论是几何体,还是光栅化的顶点,还是屏幕像素,处理这些点的时候我们不需要使用到别的点的数据,只要这一个点的数据就足够我们执行算法了。那么我们就清楚了一个问题,就是游戏程序虽然运算量很大,但是我们是可以借助多核架构来加速游戏算法的优化的。那么接下来就水到渠成了,既然CPU由于架构的原因不能够添加大量的运算核心,我们干脆就重改一种架构,把CPU里面与图形运算无关的东西全都扔掉,只保留一些最基本的寄存器和微控制器这些,然后大量的添加运算核心,这样就可以在不提升主频的情况下,大大的提升硬件的运算速度以保证游戏程序的流畅运行。这就是GPU最初的由来,当然目前GPU提升游戏算法的速度已经不仅仅是靠多核运算了,他还把一些必要的步骤(例如光栅化,纹理采样等)进行了硬件级别的封装来进一步提升对游戏的支持,但是超多的运算核心仍然是它运算速度远超CPU的一个最重要的途径。像最新的GTX1080已经有两千多个运算核心了,这种等级的并行运算速度是CPU所远远不能比的。当然了,由于这种大量核心添加是建立在图形专用卡这种轻型架构之上的,因此很多通用程序设计常用的技巧在这里都几乎无法实现,所以大部分程序包括操作系统都是很难用这种方法加速的,所以无论他的运算核心有多么庞大,他依然是代替不了CPU来作为PC机的主要运算器的。

最后我们来说一下关于显卡的运算能力的利用方面,事实上,对于大多数人来说,显卡的运算能力只有在运行游戏的时候才会用到,当然看超高清视频也有可能会用到。不过对于专业人员来说,GPU的运算能力可以在他们熟悉GPU程序设计的情况下来为他的程序的某些部分提供加速,这些应用我们称之为通用计算(GPGPU),之后我们在讲图形API的时候会提到,directx与openGL都有类似的功能,我们称之为compute
shader,当然除此之外还有专门的通用计算语言,例如CUDA和openCL这些。这部分知识会在之后的教程中再详细讲解。总之,这里大家只要了解显卡这一重要硬件的功能就足够了。

显卡部分的知识讲完了,接下来我们就要普及一下关于directx和openGL这两个图形API了,这俩api可以说是从上个世纪争斗到这个世纪的图形学界两个最终要的标准了。当然他俩孰好孰坏以我们当前的眼界来看是很难比较的,但是可以说这两个API都是非常优秀的图形接口,对应的两个GPU语言HLSL,GLSL也算是都很亲民,而且两个API的思想也基本上是一毛一样的,只不过在使用的过程中,看个人的喜好来决定到底用什么吧

。下面我来讲一下每个API的优缺点,大家可以作为学习的根据扬长避短。

首先是DirectX:

主要缺点:

1,windows独占,也就是说这项API只能用于windows平台的游戏开发。

2,非常严谨且复杂的命名规则和设计架构,对于新手非常不友好。

3,不会向下支持,也就是说dx11开发的游戏不能用dx10或者是dx9来运行。

主要优点:

1,基本上是windows平台上的必选图形API,由于windows平台的游戏开发者众多,所以因此参考资料和相关知识更新的很快。而且也更容易在windows平台下进行开发。

2,强大的硬件兼容性,虽然只能用于windows平台,但是在这个前提下几乎不会出现A卡上能跑而N卡上不能跑的情况。

3,面向对象的架构,这一点很重要,这样我们可以更好的在其之上架构引擎,而不必重新为其API进行再封装。

4,抱上了微软的大腿,所以有强大且方便的IDE(VS),有强大的GPU语言调试工具(VS的图形调试)



接下来是openGL:

主要缺点:

1,硬件兼容很差,因为openGL的实现依靠的是各个硬件厂家在显卡驱动里面提供的opengl32.dll,换句话说各家写各家的,所以有时候会出现A卡上跑的好好的程序到了N卡就炸了这种情况,虽然说大部分时候都是程序员写错逻辑的锅,但是这毕竟不利于产品开发。

2,万恶的状态机,openGl的程序设计给我们最大的印象就是glgenXXX(),glbindXXX(),glXXXdata()这些调整状态的语句,因此我们为了大型程序的开发方便不得不去一遍遍的对他进行重新封装,这对于现代的程序架构而言是很不友好的。

3,调试困难,因为没有大腿抱,所以没有专用的IDE和GPU调试器,一旦shader有了bug,基本找bug全靠猜的,再加上要是开发了一两个月之后发现A卡切N卡的时候发现有bug,那找bug之难绝对能令你吐血

,这是非常浪费时间的。

主要优点:

1,跨平台,这是openGL最大的优点,也就是因此他才能作为安卓的主要图形api来工作。当然像嵌入式啊这些新兴的机器也

可以依靠openGL在linux下实现一些复杂的图形操作。

2,设计极其简练,openGL不像directx一样有一大堆的类和架构来封装渲染需要的交互函数,基本上每种资源都是用一个int来

存储编号就够了。所有的东西都存储在它的状态机里面。这种设计对于新手来说是比较友好的。

3,向下兼容,高版本openGL设计的程序一般如果没有用到新特性的话,很容易的改改就能在低版本的机子上运行了,而

diectx的话就不是随便改改能解决问题的了,除非把API换回低版本的。

上述就是两个API的对比了,我个人是比较喜欢用drectx的,因为毕竟对开发者非常友好,大家可以根据需求不同来选择,虽然

其实会发现学完了到最后两个API都是一样的deth

....
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息