转载些好的文章,原出处我忘记了,有人知道可以帮贴一下
3D图形的概念和渲染管线(Render Pipeline)
前面介绍了3D图形历史,接下来要解说的是3D图形的处理流程。
3D图形管线的流程图
图1是3D图形的流程模型。这个虽然是对应DirectX 10/SM4的GPU流程模型,不过部分流程会根据GPU的不同,有时会有更细致的处理,有时也会做一些简略,这点敬请谅解。
首先,介绍一下3D图形的处理为什么会变成这样的根本原因。会变成这个样子,是由于在漫长又短暂的实时3D图形历史中,这个部分需要进行最顺畅的处理,更重要的是因为这样设计GPU会更容易实现的原因。这个流程不管是在Direct3D还是在OpenGL里都没有太大的差异。

图1 GPU内部的渲染流程
CPU负责的3D图形处理部分 = 游戏引擎?
图1的[1]和[2]的部分,主要是在CPU里进行的处理。
配置3D物体或是移动后再设置,因为这两种很类似,所以把这些在系统中处理的部分全部称作[游戏引擎]。
在游戏引擎中,遵从键盘输入、鼠标输入、游戏控制输入让3D角色移动,或是进行开枪击中敌人的命中时的碰撞检测,根据碰撞的结果,虽然要进行把3D角色们击飞的物理模拟,但这些是游戏逻辑的部分,某种意味上,是和[1][2]相同的部分。
另外,在[2]中如果有对应DirectX 10/SM4.0的GPU,要是能利用Geometry Shader,那么也可以在GPU上进行了,例如关于particle或billboard这样的point sprite,把创建和销毁用Geometry Shader来处理,就可以实现让GPU介入的处理。虽然如此,一般的3D游戏处理中,这部分还是由CPU来处理的部分。
Vertex Pipeline和Vertex Shader的坐标系是什么?
图中红线的[3][4][5][6]的部分,是进行顶点相关处理的顶点管线。
通常从这里开始是在GPU内部进行处理的部分。但是,为了简化内部逻辑以降低成本,所以要让图形机能整合,就是所谓的[统一芯片组],把这个顶点管线转移到CPU的(仿真)系统也是存在的。
那么,直到稍早之前,很多时候把这个顶点管线称为[几何体处理]。所谓几何体(Geometry)就是是[几何学]。在高中,虽然就会在数学或是[代数?几何]的课程中,学到[向量(Vector)运算]和[线性映射(Linear Map)或线性变换(Linear Transformation)],不过这就是那个世界的事了。说句闲话,NVIDIA的GPU,GeForce系列的名字是由「Geometric Force(几何学的力量)」的缩写所造的名词,可以说有着[G-Force重力]的双关语。
把话题转回来,说回3D图形上的[3次元向量]的概念,简单而言想成是[三次元空间上的”方向”]就可以了。这些”方向”被x,y,z的3个轴的坐标值来表示,以这些”方向”为基准的被称之为[坐标系]。
「局部坐标系」,如果具体的描述就是对于某个3D角色来说,设置为基准的坐标系,3D角色的方向就是这个3D角色的基准坐标系,通过处理[朝向是哪里],控制的人会很轻松,所以利用了局部坐标系这个概念。
对了,一般的3D角色上虽然有很多是带有手臂和脚,考虑到那些手脚在关节处弯曲的情况,如果用关节为基准的局部坐标系进行控制会更容易理解,但是这样考虑的话,就要把局部坐标系做成多层的结构,最终的处理会变得不容易理解。
接下来,支配3D全局空间的整体坐标系就很有必要了,这就是[世界坐标系]。在处理3D图形的顶点管线中的顶点单位时,从局部坐标系向世界坐标系的变换会多次发生。
这样生成的顶点要根据shader程序进行坐标系的变换处理,就是[3][顶点着色语言][Vertex Shader]。通过着色器编程,就可以进行独特而特殊的坐标系变换。

图2 坐标系的概念图Vertex Shader的另一项工作:顶点空间的阴影处理。

图1到3的Vertex Shader的工作不光是坐标变换,另一个重要的工作就是顶点空间的阴影处理和光照处理(lighting)。
「坐标变换」是「数学上的」的感觉,所谓“计算”的印象容易想象并理解。可是,在计算机中做光照,也就是说“光的照射”,这样的印象就很难想象是怎么回事。当然GPU因为不是照相机而是计算机,不可能直接拍出光照射后的效果照片,所以需要通过计算来获得。
光一旦照射到物体上,就会在那里反射/扩展和被吸收。如果这个物体有颜色或图案,那么也许就可以看到这个颜色,如果照射的光有颜色,那么就可以看到和物体颜色或图案合成后的颜色。寻求这样的计算处理,就是计算机图形的基本想法。
怎样才能把这个处理放入计算机所擅长的计算中呢?实际也是使用向量运算。
显示光的方向的[光源向量]和显示视线方向的[视线向量],还有显示构成光照射到的多边形的顶点方向的[法线向量],一共用到了这3个向量。再把这些向量对应到通过光和视线方向来表示反射的反射方程里来计算。
这个反射方程,可以表现出想要的各种类型的材质,这个反射方程在程序上的表现就是Vertex Shader程序。并且,实际执行这个顶点单位反射方程的程序,就是Vertex Shader.
在Vertex Shader中,不仅可以进行顶点空间的阴影处理,还可以进行多边形的纹理(Texture)坐标计算。纹理坐标的计算,就是计算出在怎样的多边形上,把怎样的材质纹理通过什么样的方式贴上去。还有,实际做纹理映射(Texture Mapping)是在[8][9]的Piexl Shader的时候,这里只是纹理映射的准备工作。


Vertex Shader工作的例子, 利用Vertex Shader来做折射表现。
Geometry Shader可以增减顶点的厉害东西
在DirectX 9/SM3.0之前,GPU并不包含Geometry Shader,3D模型的顶点信息是通过CPU这边预先准备好之后,再输入到GPU中,在GPU这里不能随意的进行增减。
为了打碎这个“原则性限制”,拥有可以自由增减顶点功能的着色器就是[Geometry Shader]。
通过Shader程序可以指定Geometry Shader对顶点信息进行增减。还有,因为实际增减的是复数的顶点,所以对各种的线段、多边形、粒子等图元也可以进行增减。
利用Geometry Shader的各种方法被创造出来,因为可以自由的生成多边形,那么就可以在地面上生长出草的多边形,或者让3D角色生长出毛发等是最基本的使用方法。在游戏中,还可以把不需要做逻辑交互处理的例如火花等特效的表现,使用Geometry Shader来生成。
【千里马肝注:Geometry Shader并不如想像中,或者说是宣传中那么好。可能是由于成本或是其他的什么原因,Geometry Shader通常是在display driver中实现的,也就是说其实是由CPU负责计算,当重新返回GPU的VS时,对流水线的影响很大,所以Geometry Shader的实际效能并不高,甚至是非常低。】
大致上就是可以做到这些吧。
用Geometry Shader生成的顶点,因为还可以再返回到Vertex Shader,所以可以对返回的顶点重新进行处理。例如普通方法不能实现的,把低多边形的3D模型,在Geometry Shader里通过插值生成更平滑的高多边形,理论上也是可行。

顶点管线处理的最后

[5][6]是顶点管线最后的处理部分,负责在描绘之前做最后的准备工作。
将世界坐标系中的坐标,进一步在[5]上进行变换到照相机视点坐标系的处理。这个相当于照相机在拍摄照片时构图和镜头的部分,这一连串的处理总的来说是[透视变换处理]。
因为3D图形只需要描画出视野内捕捉到的影像就可以了,一旦[5]的处理结束后,就转移到以视野空间为主体来考虑。
[6]是通过判断,将不需要描绘的多边形,在进入实际描绘处理的像素管线之前,进行剔除的处理(也称为Culling处理)。
[Clipping处理],是把完全在视野范围以外的3D模型的多边形进行剔除,如果3D模型的多边形只有一部分在视野内,那么会对视野范围内的多边形进行分割处理。
【千里马肝注:为了避免昂贵的View Frustum Clipping,一旦出现下图的这种情况,其代价为:
Extra vertices produced,costing more bandwidth
CPU cost for interpolation of x,y,z, u,v,color,specular,alpha and fog
Breaking up of strips and fans
Poor vertex locality of new vertices,which hurts CPU and vertex cache coherency
请参考:Guard Band。】

「背面剔除」,即没有朝向视点方向的顶点,理论上从视点应该把看不到的多边型进行剔除。但如果涉及到透明物体的情况,进行这样的处理有时会出现不协调的问题。
【千里马肝:即Independent Transparency,从视点观察时模型时,可能出现由于顶点传入顺序的原因,背面的顶点在前面的顶点之前就绘制的问题,于是Alpha Blend就不正确了。】
负责分解和发送像素单位工作的光栅器(rasterrizer)
当变换到视野空间,无用多边形都剔除后,在[7]上进行的是,把到没有实际形态的多边形,绘制为对应在画面上的像素的处理。另外,在最新的3D图形上,并不只是绘制显示帧,也有把场景渲染到纹理的情况,这个时候[7]会进行多边形和纹理像素的处理。
在[7]上的处理,实质上是将从顶点管线上把成为顶点单位(多边形单位)输出的计算结果,作为像素单位进行分解,持续的向像素管线发送任务,可以说是起到中介的作用。
这个[7]的处理被称作[triangle setup],或者是[rasterise处理],因为是个规范化的处理,所以从1990年代初期的GPU里就作为固定功能实现在GPU里,到现在也没有太大的进化。
通常,一个多边形因为要用多个像素来绘制,所以多边形通过光栅化被分解成大量的Pixel Task。在GPU上Pixel Shader处理单元的数量如此之多,是由于需要处理的像素是如此繁多的原故。

图5:Rasterise也可以说成是生成piexl shader的任务书,还有,一个多边型会生成多个pixel task.
3D图形的概念和渲染管线(Render Pipeline)
前面介绍了3D图形历史,接下来要解说的是3D图形的处理流程。
3D图形管线的流程图
图1是3D图形的流程模型。这个虽然是对应DirectX 10/SM4的GPU流程模型,不过部分流程会根据GPU的不同,有时会有更细致的处理,有时也会做一些简略,这点敬请谅解。
首先,介绍一下3D图形的处理为什么会变成这样的根本原因。会变成这个样子,是由于在漫长又短暂的实时3D图形历史中,这个部分需要进行最顺畅的处理,更重要的是因为这样设计GPU会更容易实现的原因。这个流程不管是在Direct3D还是在OpenGL里都没有太大的差异。

图1 GPU内部的渲染流程
CPU负责的3D图形处理部分 = 游戏引擎?
图1的[1]和[2]的部分,主要是在CPU里进行的处理。
配置3D物体或是移动后再设置,因为这两种很类似,所以把这些在系统中处理的部分全部称作[游戏引擎]。
在游戏引擎中,遵从键盘输入、鼠标输入、游戏控制输入让3D角色移动,或是进行开枪击中敌人的命中时的碰撞检测,根据碰撞的结果,虽然要进行把3D角色们击飞的物理模拟,但这些是游戏逻辑的部分,某种意味上,是和[1][2]相同的部分。
另外,在[2]中如果有对应DirectX 10/SM4.0的GPU,要是能利用Geometry Shader,那么也可以在GPU上进行了,例如关于particle或billboard这样的point sprite,把创建和销毁用Geometry Shader来处理,就可以实现让GPU介入的处理。虽然如此,一般的3D游戏处理中,这部分还是由CPU来处理的部分。
Vertex Pipeline和Vertex Shader的坐标系是什么?
图中红线的[3][4][5][6]的部分,是进行顶点相关处理的顶点管线。
通常从这里开始是在GPU内部进行处理的部分。但是,为了简化内部逻辑以降低成本,所以要让图形机能整合,就是所谓的[统一芯片组],把这个顶点管线转移到CPU的(仿真)系统也是存在的。
那么,直到稍早之前,很多时候把这个顶点管线称为[几何体处理]。所谓几何体(Geometry)就是是[几何学]。在高中,虽然就会在数学或是[代数?几何]的课程中,学到[向量(Vector)运算]和[线性映射(Linear Map)或线性变换(Linear Transformation)],不过这就是那个世界的事了。说句闲话,NVIDIA的GPU,GeForce系列的名字是由「Geometric Force(几何学的力量)」的缩写所造的名词,可以说有着[G-Force重力]的双关语。
把话题转回来,说回3D图形上的[3次元向量]的概念,简单而言想成是[三次元空间上的”方向”]就可以了。这些”方向”被x,y,z的3个轴的坐标值来表示,以这些”方向”为基准的被称之为[坐标系]。
「局部坐标系」,如果具体的描述就是对于某个3D角色来说,设置为基准的坐标系,3D角色的方向就是这个3D角色的基准坐标系,通过处理[朝向是哪里],控制的人会很轻松,所以利用了局部坐标系这个概念。
对了,一般的3D角色上虽然有很多是带有手臂和脚,考虑到那些手脚在关节处弯曲的情况,如果用关节为基准的局部坐标系进行控制会更容易理解,但是这样考虑的话,就要把局部坐标系做成多层的结构,最终的处理会变得不容易理解。
接下来,支配3D全局空间的整体坐标系就很有必要了,这就是[世界坐标系]。在处理3D图形的顶点管线中的顶点单位时,从局部坐标系向世界坐标系的变换会多次发生。
这样生成的顶点要根据shader程序进行坐标系的变换处理,就是[3][顶点着色语言][Vertex Shader]。通过着色器编程,就可以进行独特而特殊的坐标系变换。

图2 坐标系的概念图Vertex Shader的另一项工作:顶点空间的阴影处理。

图1到3的Vertex Shader的工作不光是坐标变换,另一个重要的工作就是顶点空间的阴影处理和光照处理(lighting)。
「坐标变换」是「数学上的」的感觉,所谓“计算”的印象容易想象并理解。可是,在计算机中做光照,也就是说“光的照射”,这样的印象就很难想象是怎么回事。当然GPU因为不是照相机而是计算机,不可能直接拍出光照射后的效果照片,所以需要通过计算来获得。
光一旦照射到物体上,就会在那里反射/扩展和被吸收。如果这个物体有颜色或图案,那么也许就可以看到这个颜色,如果照射的光有颜色,那么就可以看到和物体颜色或图案合成后的颜色。寻求这样的计算处理,就是计算机图形的基本想法。
怎样才能把这个处理放入计算机所擅长的计算中呢?实际也是使用向量运算。
显示光的方向的[光源向量]和显示视线方向的[视线向量],还有显示构成光照射到的多边形的顶点方向的[法线向量],一共用到了这3个向量。再把这些向量对应到通过光和视线方向来表示反射的反射方程里来计算。
这个反射方程,可以表现出想要的各种类型的材质,这个反射方程在程序上的表现就是Vertex Shader程序。并且,实际执行这个顶点单位反射方程的程序,就是Vertex Shader.
在Vertex Shader中,不仅可以进行顶点空间的阴影处理,还可以进行多边形的纹理(Texture)坐标计算。纹理坐标的计算,就是计算出在怎样的多边形上,把怎样的材质纹理通过什么样的方式贴上去。还有,实际做纹理映射(Texture Mapping)是在[8][9]的Piexl Shader的时候,这里只是纹理映射的准备工作。


Vertex Shader工作的例子, 利用Vertex Shader来做折射表现。
Geometry Shader可以增减顶点的厉害东西
在DirectX 9/SM3.0之前,GPU并不包含Geometry Shader,3D模型的顶点信息是通过CPU这边预先准备好之后,再输入到GPU中,在GPU这里不能随意的进行增减。
为了打碎这个“原则性限制”,拥有可以自由增减顶点功能的着色器就是[Geometry Shader]。
通过Shader程序可以指定Geometry Shader对顶点信息进行增减。还有,因为实际增减的是复数的顶点,所以对各种的线段、多边形、粒子等图元也可以进行增减。
利用Geometry Shader的各种方法被创造出来,因为可以自由的生成多边形,那么就可以在地面上生长出草的多边形,或者让3D角色生长出毛发等是最基本的使用方法。在游戏中,还可以把不需要做逻辑交互处理的例如火花等特效的表现,使用Geometry Shader来生成。
【千里马肝注:Geometry Shader并不如想像中,或者说是宣传中那么好。可能是由于成本或是其他的什么原因,Geometry Shader通常是在display driver中实现的,也就是说其实是由CPU负责计算,当重新返回GPU的VS时,对流水线的影响很大,所以Geometry Shader的实际效能并不高,甚至是非常低。】
大致上就是可以做到这些吧。
用Geometry Shader生成的顶点,因为还可以再返回到Vertex Shader,所以可以对返回的顶点重新进行处理。例如普通方法不能实现的,把低多边形的3D模型,在Geometry Shader里通过插值生成更平滑的高多边形,理论上也是可行。



[5][6]是顶点管线最后的处理部分,负责在描绘之前做最后的准备工作。
将世界坐标系中的坐标,进一步在[5]上进行变换到照相机视点坐标系的处理。这个相当于照相机在拍摄照片时构图和镜头的部分,这一连串的处理总的来说是[透视变换处理]。
因为3D图形只需要描画出视野内捕捉到的影像就可以了,一旦[5]的处理结束后,就转移到以视野空间为主体来考虑。
[6]是通过判断,将不需要描绘的多边形,在进入实际描绘处理的像素管线之前,进行剔除的处理(也称为Culling处理)。
[Clipping处理],是把完全在视野范围以外的3D模型的多边形进行剔除,如果3D模型的多边形只有一部分在视野内,那么会对视野范围内的多边形进行分割处理。
【千里马肝注:为了避免昂贵的View Frustum Clipping,一旦出现下图的这种情况,其代价为:
Extra vertices produced,costing more bandwidth
CPU cost for interpolation of x,y,z, u,v,color,specular,alpha and fog
Breaking up of strips and fans
Poor vertex locality of new vertices,which hurts CPU and vertex cache coherency
请参考:Guard Band。】

「背面剔除」,即没有朝向视点方向的顶点,理论上从视点应该把看不到的多边型进行剔除。但如果涉及到透明物体的情况,进行这样的处理有时会出现不协调的问题。
【千里马肝:即Independent Transparency,从视点观察时模型时,可能出现由于顶点传入顺序的原因,背面的顶点在前面的顶点之前就绘制的问题,于是Alpha Blend就不正确了。】
负责分解和发送像素单位工作的光栅器(rasterrizer)
当变换到视野空间,无用多边形都剔除后,在[7]上进行的是,把到没有实际形态的多边形,绘制为对应在画面上的像素的处理。另外,在最新的3D图形上,并不只是绘制显示帧,也有把场景渲染到纹理的情况,这个时候[7]会进行多边形和纹理像素的处理。
在[7]上的处理,实质上是将从顶点管线上把成为顶点单位(多边形单位)输出的计算结果,作为像素单位进行分解,持续的向像素管线发送任务,可以说是起到中介的作用。
这个[7]的处理被称作[triangle setup],或者是[rasterise处理],因为是个规范化的处理,所以从1990年代初期的GPU里就作为固定功能实现在GPU里,到现在也没有太大的进化。
通常,一个多边形因为要用多个像素来绘制,所以多边形通过光栅化被分解成大量的Pixel Task。在GPU上Pixel Shader处理单元的数量如此之多,是由于需要处理的像素是如此繁多的原故。

图5:Rasterise也可以说成是生成piexl shader的任务书,还有,一个多边型会生成多个pixel task.
