您的位置:首页 > 其它

3D绘图程序设计之shader学习总结(一)

2014-06-18 23:17 288 查看
引言

最近在看《3D绘图程序设计》这本书,这本书对3D渲染方面的知识以及shader部分讲得都比较详细,目前也正在学习shader部分的内容,想到能使用shader做出许多图像处理方面的效果,还有像RimLight(边缘光)、Silhouette遮挡剪影(当角色被场景中的物体遮挡住后显示其轮廓的效果)、水波等高级特效,还是有些激动呢!在学习的过程中,我也想分享一下,也能督促自己学习,做一些总结,一举两得嘛。我也只是个初学者,有什么理解不对的地方还请各位大牛们批评指正。好了,开始进入正题。

正文

Shader,翻译过来就是着色器的意思,简单来说就是向显示屏幕上的各个像素填充颜色。实际上,shader所能进行的操作有很多,是一段被GPU(Graphics Processing Unit,绘图处理器,也就是显卡)执行的程序。在学习shader之前,我了解了一些计算机图形学方面的知识,并且参考了其他人的一些关于3D渲染方面的文章,了解shader能具体做些什么。下面就具体说一下3D渲染管线(rendering pipline)。

3D渲染就是将3D场景中的物体模型转换到2D屏幕中成为一张2D的图像。就好比是使用摄像机进行拍摄,将拍摄的画面显示在二维的相片上。渲染管线,也称为渲染流水线,就相当于3D场景向2D图像转换的过程,也就是将一些数据输入到GPU中,经过处理后转为画面显示的二维数据,这些输入数据包括顶点的坐标、法线(Normal)、颜色、纹理/贴图(Texture)、光照数据等。下面是描述该流程的图解:



这里主要说一下应用程序中通过使用DirectX或OpenGL图形库,设置好3D场景中模型的顶点坐标等数据之后,接下来的渲染管线流程。该流程可分为两个阶段:图形管线阶段、光栅化阶段。

1.图形管线阶段

1.1顶点变换

顶点变换的阶段也就是将3D中的物体模型转换到2D屏幕坐标中,通过各个转换矩阵相乘来实现变换。

1.1.1 Model Space到World Space

Model Space模型空间,也就是以模型自身的坐标系为原点,模型上各个顶点的坐标,比如一个立方体,可选取立方体中心的位置为坐标原点,立方体上的8个顶点的坐标也就相对于该坐标系。World Space,世界空间,就是规定的一个标准坐标空间,可以看做是屏幕或者窗口中间的位置为坐标原点,DirectX使用的坐标系为左手坐标系,OpenGL使用的是右手坐标系,不过这两个坐标系是可以互相转换的。该坐标空间的转换就称为Model Transform模型变换,变换中所使用到的矩阵为平移、旋转、缩放矩阵。

1.1.2 World Space到View/Eye Space

View Space观察空间,就相当于是摄像机的镜头。为了能让模型随着视点的位置变换而呈现不同的场景部分,要将世界坐标中的模型顶点坐标转换到视点的坐标系当中,此时坐标系就以视点为坐标原点。该转换就相当于摄像机位置的变换,而能观察到场景中不同的画面。顺便说一下,顶点中法线坐标的转换就到这一步,也就是模型观察变换,法线的作用是在光照计算中会用到。

1.1.3 View Space到Projection Space

Projection Space投影空间,投影就是将3D的模型坐标映射到2D坐标中,有两种投影方式,一种是透视投影,一种是正交投影。透视投影的方式是运用了近大远小的原理,使模型真正看起来是3D的效果,而正交投影则看起来是2D的效果。在这个坐标转换的过程中,用到了一个称作是视锥体(viewing frustum)的几何区域,只有在该区域内的物体才能被绘制出来,这个过程就叫做视域体裁剪(view frustum clip)。视锥体中定义了近裁剪平面(near clipping plane)、远裁剪平面(far
clipping plane),还有其他的属性,这里就不说了。



在经过投影变换以及裁剪后,就将坐标转换到了2D的标准屏幕坐标系中,定义该坐标系是由于屏幕或窗口的大小是可以改变的,要对2D的坐标系进行规范化。该坐标系使用齐次坐标表示,即(x, y, z, w),各坐标值除以w,就是规范化的坐标,其中X, Y的范围是在(-1, -1)到(1, 1)之间,还有一个坐标值是Z值,这里的Z值在2D坐标中虽然看不出差别,但这个值很重要,是用于隐藏面消除,也就是ZBuffer Test或Depth Test(深度测试)。Depth是指镜头前后方向的深度值,该值将存储在Z
Buffer(深度缓存)中。Z值的范围在DirectX中是0~1,在OpenGL中是-1~1,超出这个范围就看不到了。

1.1.4 Projection Space到Screen Space

Screen Space屏幕坐标空间,也就是屏幕像素坐标。根据屏幕或窗口的具体大小,将标准化的屏幕坐标映射到像素坐标中,这个过程就称作视口变换Viewport Transform。

到这里,就完成了顶点的变换。

1.2 Primitive Assembly(图元装配)和Triangle Setup(三角形处理)

图元装配,就是将顶点根据primitive原始的连接关系,还原出网格结构。网格由顶点和索引组成,根据索引来连接两个顶点为一条线段,再将线段连接成三角形,也就组成了线、面单元,之后就是对超出屏幕外的三角形进行裁剪。

还有一个过程就是对三角形进行处理。根据三角形顶点的顺序来决定三角形法向量的朝向,如果该法向量朝向视点(法向量与到视点的方向的点积为正),则该面是正面,一般是顶点按照逆时针排列。在背面的面片由于镜头无法看到,就可以进行剔除,称作back-facing culling(背面消隐)。

到此,图形管线就完成了,所生成的一堆三角形面片会在光栅化阶段使用。

2.光栅化阶段

2.1 Rasterization(光栅化)

光栅化,就是确定哪些像素被几何图元(三角形)所占有的过程,也就需要先将顶点的坐标转化为屏幕上真正的像素位置。屏幕上的像素位置都是整数,而经过上面流程转换的坐标值有可能为浮点数,那就得将其近似取整,比如(10.25,20.55),转换后的像素位置为(10,21)。

还有一个问题就是如何将两个像素点连接成一条线段,将三个像素点连成一个三角形面片。所用到的算法有画线段的DDA(数字微分分析法);区域图元填充等,算法太多啦,还是在计算机图形学的书中找吧。

在这个过程中,一个三角形面片可能由成百上千个像素点进行填充。接着就是为每个像素进行着色,填充所计算出的颜色值。

2.2 Pixel Operation(像素操作)

该操作的目的就是计算每个像素的颜色值,计算颜色的方法有很多,具体如下:

(1)遮挡面消除,也就是ZBuffer Test/Depth Test(深度测试)。当物体表面一像素点的深度值小于与其对应的像素的当前深度值,此时该点的深度在当前的深度之前,新的像素颜色值也就覆盖了当前的颜色值。

(2)Texture Operation(纹理操作),根据像素的纹理坐标(UV坐标),查询对应的纹理值。

(3)Alpha Blend(Alpha通道混合),将当前的颜色值与一个新的颜色的透明度(Alpha)进行混合,作为新的颜色输出。

(4)Filtering(过滤),将当前正在计算的像素颜色通过某个滤镜或是某种数学运算后输出新的颜色。

经过计算后的各个像素颜色值,就写入帧缓存中(Frame Buffer)。

在帧缓存中一般会定义两块用于显示画面数据的缓存区,Front Buffer(前景缓存,用于显示已画好的画面)和Back Buffer(背景缓存,用于准备下一个画面),定义两块缓存区是为了做到画面的实时产生,并且不让用户看到绘制画面的过程。两块缓存区交互的过程就好比是一个人用两张纸画图,他要在一张纸上以惊人的速度画好图之后,再将画面印到另一张纸上呈现给观众看,如果开启的是全屏模式,干脆就将这两张纸交换。

3D渲染管线大致就是这样,有什么理解不对的地方还请多多指教。

现在也就大概了解了Shader能具体做些啥了,可在Vertex Transform和Pixel Operation这两个过程中进行操作,也就是Vertex Shader和Pixel Shader,而上面没咋提到的光照计算在这两个阶段的Shader中都可进行。下一篇正式开始Shader的学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: