1> 人们将在平面画幅上根据一定原理,用线条来显示物体的空间位置、轮廓和投影的科学称为透视学。这种方式,也就成了今天图形渲染工业中Rasterization的基础。
2> 线透法: 在多种透视方法中,最常用到的是线透法。线透法的基本原理,在于将物体的每一个点全部以连线的方式与观察视野,也就是我们的眼睛相连,然后再将一块平面置于这些线上,由线穿透平面所构成的投影来确定物体在画面中的形态
3> CPU生成的顶点数量在很多时候都是不够的,过少的顶点不仅会大幅降低模型精度,影响香草的面容,更会因为调节点过少而影响表情表达的精度,让那些本该传神的表情显得僵硬。于是,我们有了增加顶点的需求。
4> 尽管像素和像素着色器更加吸引人们的目光,但几何体才是一切的根源所在。没有了几何体,我们将发现光照、阴影和反射毫无意义。因为提高底层几何体的复杂度,将同时提高像素的质量
5> 区别于以往的传统的处理方式,新的Geometry Shader+Tesselation允许GPU自己生成新的顶点并完成设置工作。现在CPU还是干以前一样的工作,基本模型的顶点还是由他来生成,而且数量也没有变化,只不过当顶点再次流入到GPU之后情况会发生些许变化。现在的几何单元会先查看程序中是否包含一种叫做镶嵌系数的新东西,如果没有,则几何单元重复上面的香草解救大作战;如果有,则几何单元将会进入一个全新的状态。
6> 顶点引证(Vertex Instancing)和DrawInstanced函数,copy和修改的过程,加速大场面的渲染
7> 图形处理过程:
第一:CPU它会根据程序的需要生成构成模型的所有顶点,然后将这些顶点的坐标发给GPU
第二:常规的几何处理过程(setup单元):描点(顶点输出过程),连接,顶点的操作(根据方程生成不同的表情),蒙皮和打光(Vertex Texture和Vertex Lighting,如同生成石膏雕刻)
第三:首先,CPU生成的模型依旧不变,几何单元在阅读了同顶点模型信息一起传过来的镶嵌系数及方程之后,会先让Geometry Shader中的Hull Shader对曲面要求进行解析,按照要求寻找其中的控制点,然后让Tesselator单元根据系数的要求生成全新的点。新生成的点全部在旧有顶点范围之内,当这些新生成的点被Tesselator单元送出之后,Hull Shader会根据程序的镶嵌说明把它们送到新的位置上并完成必要的调整,最后再由Domain Shader把Hull shader调整好的镶嵌点变成新的顶点输送给setup。
1> Rasterizer过程是直接将现有的几何模型中的点全部变换成二维形式
2> Transform词如其意,就是指对立体物体的变形。三维空间中的物体会自然地呈现三维坐标系的特征,其上的每一个点均会带有完整的三维坐标向量。想要将这些点固定在二维世界中同时还要符合透视关系,这就是Transform的工作。经过计算,所有三维空间的点都可以在保证与观察者也就是摄像机位置存在正确关系的前提下,变成一个没有真实Z轴的二维点。
3> 由于这是整个光栅化过程的核心,因此,光栅化也经常被称作坐标变换。
4> 除了满足二维平面输出对坐标变换的要求之外,Rasterizer(光栅化)最大的意义,便在于减轻流水线后续的无效渲染的压力。
5> 光栅化操作,是发生在模型完全建立,并且完成基本光照及对应纹理操作之后的操作环节。
6> Z轴闭塞检查(Z-culling),Deferred Shading:它将光照操作的步骤直接转移到整个流水线后端的MRT(多目标渲染)里。Vertex Shader和Pixel Shader结合成了Unified Shader
1> 时候对特效的处理只能通过固定的单元来直接实现,每一代API下所能够实现的特定的特效,都需要通过预先将其固化成固定指令的形式出现在硬件中,而对于像素的处理,也仅能局限于固化指令所能够允许的范围内,一旦像素进入管线,程序员就失去了对他的控制。因此,可编程shader尤其是Pixel Shader的出现,在当时是一件轰动的大事,Pixel Shader的出现,标志着程序员在像素级层面上第一次具备了可以精确而且随心所欲的控制自己想要实现特效的能力。
2> 可编程shader program,尤其是Pixel Shader的出现,标志着人类正式进入了游戏应用向电影特效进军的时代。
3> Pixel Shader1.0(Directx 8)精度问题,只能控制整型,第一代shader所采用的combine仅能处理整型数据,对于浮点数据则无能为力,这极大地限制了数据处理的精度,进而影响到了数据背后的像素颜色的表现。数据的精度决定颜色的精度,当特效对像素的要求达到一定高度之后,对颜色的正确性也会变得更加敏感,整型数据的运算精度显然不能满足最终效果的要求,连数字都没算对,程序员当然看不到自己想象中的结果了。
4> 在Pixel Shader2.0中微软第一次引入了FP24/32浮点数据作为颜色处理的基本精度,而执行这些数据的硬件也从combine转变成了功能更加强大的mini ALU。更加精确的浮点型数据让RGBA数值具备了充足的准确性,3D图形终于完成了从“美妙”到“栩栩如生”的转变。
5> 3D图形不同于静态画面,连续动态画面的流畅度和画面的准确表现是同等重要的,如果硬件仅仅能输出准确的效果,却无法在输出速度上予以保证,用户获得的最终体现效果一样会大打折扣。随着Pixel Shader的逐步发展,其最大指令长度慢慢的从出现之初的16条发展到了2.0b的512条,这使得指令的执行效率成了摆在人们面前的现实问题。非常遗憾的是,Pixel Shader发展到2.0b为止都没有引入真正有效的提升指令执行效率的手段,跳转、分支、流控制等今天看来很平常的东西在当时全都是不存在或仅仅存在于“支持”这种程度的,这让PixelShader的执行效率出现了极大的问题。
6> 在DirectX 9.0C中,MS显然想将之前版本的DirectX中所遗留的问题一次性彻底搞定,Shader Modle3.0的最大指令数提升至65535,增加了寄存器数量,引入了动态程序流控制,将分支和跳转能力彻底开放给了程序员,同时通过多目标渲染(MRT)和延迟渲染(Deferred Shading)等创造性的技术保证了光栅化过程中整个流水线的整体效率,可以说DirectX 9.0C几乎解决了ALU利用率和效率之外的一切问题,它成了历史上第一个真正能够“实现一切特效”的图形API。
7> 因此传统硬件只有使用专门的比例一定的VertexShader和Pixel Shader单元,将它们分开进行处理。这种举措本身从最开始就注定了很多不可调和的矛盾——固定单元比例的硬件凭什么就能达到程序员对Vertex Shader和Pixel Shader数量及分布的要求?Shader Modle3.0号称是破除一切限制的史上最自由的Shader Modle,结果到头来还是要程序员严格按照硬件构架的大致比例和节奏来分配自己的Vertex Shader programs和Pixel Shader programs,只要稍有出格,硬件马上会以直线下降的执行效率来回报你。
8> DirectX 10以及其所带来的Shader Modle4.0可以说为图形界翻开了全新的篇章,它创造性的引入了Unified Shader的概念,将传统的Vertex Shader和Pixel Shader从软件和硬件层面上予以统一,shader programs内部不再需要严格按照格式来区分Vertex/Geometry/Pixel。软件变了,硬件也要跟着改,所以对于支持ShaderModle4.0的硬件来说,其执行shader programs的单元也从过去的分立式固定功能变成了更加强大完整且完全统一的通用ALU。因为ALU可以对全部shader进行无差别吞吐,整个硬件的执行效率第一次在理论上达到了100%。
9> Shader Modle4.0对像素来说有着极其重要的意义,它不仅通过统一ALU吞吐提升了硬件的执行效率,更让程序员们可以更加随心所欲的使用效率更高的指令。传统的DirectX 9硬件中的shader格式是非常固定的,Vertex Shader指令天生就是4D(X,Y,Z,A),而Pixel Shader指令因为硬件单元设计通常都是对应RGBA的3D+1D 结构的缘故,一般情况下也会写成4D。这导致了DirectX 9环境下的PixelShader指令无论属于何种应用,哪怕仅包含一条Z-buffer或者一条texture load,也要在指令结构上找齐成4D格式。这种格式的刻板要求极大的限制了程序员对shader尤其是Pixel Shader的发挥。在Shader Modle4.0环境下,统一且无限制的指令格式要求以及直接面向底层ALU的特点让程序员可以大胆的直接使用更加灵活的1D、2D指令以及各种算数函数,而不用担心任何来自硬件方面的限制,这让Shader Modle4.0的效率和灵活度提升到了一个新的高度。
10> Shader Modle4.0的问题:这次暴露给他们的东西包括了并行度和几何关联性问题。
11> DirectX 11以及Shader Modle5.0。在Shader Modle5.0中,微软引入了两个重要的概念:并行kernel及Compute Shader,前者通过引入kernel并行执行的形式来解决ALU利用率的问题,而后者则通过打破几何关联性的方式将ALU的运算能力真正释放了出来。
12> 传统分立单元的效率很难得到保障
13> 如果我想将材质中某个原本黄色的像素点揉到光线效果中并令其因此改变颜色,需要将像素原本颜色的数值以及它与光线和其他通过数学的手段处理成一个或一组方程。这就是像素向效果迈进的第一步,从像素变成方程。不同的像素改变对应了不同的方程或者方程组,要处理这些方程/方程组,就必须将它们转化成ALU能够接受的形式,因此方程/方程组就变成了指令。
14> 幕内会出现大量需要更改的像素,这些像素更改所对应的全部过程就是一个kernel,这个kernel,就是由所有Grid组合成的集合。
15> 因为我们要理解的是像素到画面之间的递进关系,所以我们只看像素即可。要实现特效,所要改变的最基本单位首先是像素,一个改变的最终结果对应一个像素任务(Thread);出于提高GPU的像素吞吐效率的考量,若干个像素会被组合成一个整体集团被ALU团簇执行(CTA);既然方便了硬件,程序员也要得到便利,所以我们又设定了一个程序员方便管理的最小单元,里面包含了若干被组合在一起的像素集团(Block);一个ALU团簇一次能够面对若干个这样的像素集团,他们也可以被称作一个更高级的集合体(Grid);最后,当屏幕内所有的这种最高级待改变像素集合体被执行完毕之后(kernel),特效就呈现在我们眼前了。
16> 处理完的结果将被传送至ROP单元,它会将处理好的像素与已经存在的基本材质进行混合,然后就可以输出我们能够看到的最终效果了。
17> 因为现在的ALU根本没有那个本事面对直接生成像素所带来的运算量。
18> 像素的处理过程从本质上来说并不复杂,其巨大的执行难度并不来自步骤的繁琐,而是来源于对大量像素进行数学关系运算所导致的运算量
1> Texture Array是一个较新出现的词汇,它的目的在于应付材质单元从传统的单一贴图操作转向更加全面应用的需要。在更早的时候,纹理单元其实一直都被称为Texture Mapping Unit,也就是我们熟悉的TMU。
2> TMU的作用,归根到底就是对材质的贴图和过滤操作。根据程序的需要,在完成几何处理和光栅化之后,TMU单元会从材质库中找出合适的纹理贴在对应的位置上以实现模型的外形完整化
3> 多重纹理贴图与以往最大的不同,在于它能够让TMU以一个周期为单位实现二重至四重,甚至是更多次的材质贴图操作。复合贴图的好处是显而易见的,他可以让多边形表面拥有更好的图案和色彩表现,从而提升物体细节的真实度,同时又不会牺牲太多的操作周期从而降低帧数表现
4> 在可编程shader出现之后,TMU的工作就从原来的实现全部特效很自然的过渡到了为各种特效提供基础上。了直接操作像素的手段,程序员们不必再为材质的不准确而垂头丧气,他们可以自行调节像素以弥补材质本身的不足。
5> TMU与可编程shader单元的这种“基础—修饰”的配合很快就成为了程序员们实现特效,或者说近乎完美的欺骗我们眼睛的常规手段
6> DirectX 9.0C是一个足以名流计算机图形学发展史册的API版本,虽然它仅仅是DirectX 9.0的一次升级,但这次升级却带来了诸多令人印象极其深刻且意义深远的改进,比如长度达65536、已经近乎于无限长度的指令,分支、跳转以及流控制等指令形式的引入,MRT的首次出现等等。在这一系列重大的改进中,有两样是关于TMU单元的,一个是Shader Modle3.0引入的VTF(Vertex Texture Fetch),另一个则是TA/TF单元的分离。
7> VTF允许Vertex Shader单元直接访问材质库,并从中读取含有基本光照信息的材质然后贴在完成处理的几何模型表面。由于Vertex Shader包含全部操作之后的顶点信息,其中的重要的信息之一就是顶点相对于网格平面的高度值,因此VTF最大的意义,便在于可以让TMU以比过去方便快捷许多的方式来实现对高度及视差极其敏感的环境凹凸贴图特效。
8> Texture Address(纹理定址)以及Texture Filtering(纹理拾取)(TA,TF)。因此从DirectX 9.0C开始,TMU单元正式分割成了TA和TF两个部分,TA单元专门负责材质的定址操作,在完成定址之后,TF单元根据定址结果对材质进行拾取并完成贴图作业。
9> 技术的发展在不断的督促着GPU内部各个单元的快速进步,纹理单元也不例外。尽管它已经改名叫TextureArray,而且拥有了TA和TF这两个完全不同的组成部分,但人们还是喜欢叫它最开始的名字——TMU。在DirectX 10/10.1的带动下,TMU单元继续维持着自己的发展,又具备了两个非常好用的改进——纹理阵列以及Gather指令。
10> 从本质上讲,TMU单元所做的事情,就是在需要时扫描预先准备好的材质库,从中寻找出合适当前多边形需要的材质,然后把它从库中拷出来,加以适当的缩放调整及其他动作之后再贴到多边形表面上去。而对纹理单元的常规改进,也就是增加纹理操作单元的数量,使用更加先进的压缩算法来缩小纹理在操作期间的体积,加入适当的纹理过滤机制以保证其清晰度,以及为纹理单元配置更好的缓冲机制比如Tex Cache之类的琐事了。
11> 对于纹理的定址和拾取,本质上是对一定像素区域内颜色信息的处理过程,从材质库中拾取的纹理,其实就是一大堆像素数据的集合,所以这个处理过程本身其实也就是对数字的比对和改变。