《Fundamentals of Computer Graphics》第九章 图形管线 总结
开篇前几个章节为第二种也就是基于物体顺序的渲染搭好了数学的脚手架,稍微回顾一下之前的内容,和基于像素顺序的渲染不同的是,基于物体顺序的渲染以几何物体为中心,为每个几何物体找到它能影响的像素。为每个几何物体找到它所占据的图像上的像素的过程就叫做光栅化(Rasterization),因此基于物体顺序的渲染也被称为光栅化渲染。需要一序列操作,从物体出发到更新图像上的像素结束被称为图形管线(Graphics Pipeline)。
这章的标题可能让你觉得只有一种方法来实现基于物体顺序的渲染,其实不是这样的。例如有两种截然不同的图形管线的例子,为不同的目的打造。第一种是硬件管线用于支持交互式渲染,通过OpenGL和Direct3D等API实现。第二种是软件管线用于影视制作,支持RenderMan等API。硬件管线必须运行的足够快来为游戏和可视化以及用户界面进行实时响应。而软件管线必须尽可能渲染出最高质量的动画和视觉效果并且能应对庞大的场景,不过这会花费更多的时间就是了。尽管是出于不同决定设计的,不过大部分图形管线都有着非常多共同点,这一章将聚焦于这些共同点并且更贴近于硬件管线。
基于物体顺序的渲染所需要的任务可以组织成光栅化自己的任务、在光栅化之前要对几何进行的操作、在光栅化之后要对像素进行的操作。最常见的几何操作就是施加矩阵变换,就如同前两章所讨论的把定义在物体空间的几何体映射到屏幕空间。对于像素来说最常见的操作是隐藏表面去除(Hidden Surface Removal),它能让更近的表面呈现在观察者面前。在每个阶段也能有其它操作添加,由此可以使用相同的流程来达到许多不同的渲染效果。
对于这一章节来说,就是讨论图形管线的四个阶段,如下图所示
从交互式应用程序或者场景描述文件中被送进管线的几何物体通常都是用一些顶点描述的。这些顶点会在顶点处理阶段(Vertex-Processing Stage)被处理,接着使用这些顶点的图元会被送入光栅化阶段(Rasterization Stage)。光栅器会把每个图元分解成一些片段(Fragment),每个片段对应着被图元覆盖的一个像素。片段会在片段处理阶段(Fragment Processing Stage)被处理,然后对应着相同像素的不同片段会进入片段混合阶段(Fragment Blending Stage)从而被组合。
光栅化(Rasterization)
光栅化在基于物体顺序的渲染中处于中心地位的操作,而光栅器(Rasterizer)是所有图形管线的核心。对于每个被送入的图元光栅器有两个工作,首先是枚举图元覆盖的像素,接着在整个图元上插值叫做属性(看到后面就懂了)的东西。光栅器的输出是一些片段,每个片段对应着图元覆盖的一个像素。每个片段“存活”于一个特定的像素中并且携带着属于它自己的一系列属性值。
直线绘制(Line Drawing)
绝大多数图形包都有一个指令能绘制有着屏幕坐标的两个端点构成的线段。比如给定两个端点\((1,1)\)和\((3,2)\),则会取像素\((1,1)\)和\((3,2)\)以及这两个像素之间的一个像素作为一条线段。那么对于更加一般的端点\((x_0,y_0)\)和\((x_1,y_1)\)来说就要取一定合理数量的像素来接近理想的线段,画这种线段得基于直线方程。直线方程有隐式形式和参数形式可选,下面介绍使用隐式形式的方法
使用隐式直线方程绘制直线(Line Drawing Using Implicit Line Equations)
最常用的使用隐式方程绘制直线的方法就是中点算法,而中点算法最终和布雷森汉姆算法(Bresenham Algorithm)绘制了相同的直线,不过中点算法显得更直接一些。使用这个方法首先要找到直线的隐式方程
\
假设\(x_0 \leq x_1\),如果不成立交换两个点即可。直线的斜率\(m\)为
\
下面的讨论假设\(m \in (0,1]\),当然了还有其它三种情况即\(m \in (-\infty,-1]\)、\(m \in (-1,0]\)、\(m \in (1,\infty)\)。对于\(m \in(0,1)\)来说水平移动比竖直升高要多,在直线上移动的点的\(x\)坐标比\(y\)坐标变化快,这个时候你有可能觉得\(y\)轴的正半轴如果朝下会让处理变得麻烦起来,实际上代数运算并不关心\(y\)轴的朝向问题。中点算法的关键设想就是尽可能绘制细的没有间隙的直线,斜着连接的两个像素不算有间隙。
当从左端点往右绘制线段时只有两种可能,要么绘制当前像素位置右边的像素要么绘制当前像素位置右上的像素,这样每一列都会有一个像素被绘制从而保证在尽可能细的情况下无间隙,下图展示了有着相同端点的线段的不同绘制方法
对于\(m \in (0,1]\)的情况,中点算法会从最左侧的像素中心位置开始,往右循环为每列挑选一个像素。基础的算法应该长这样
要注意的是\(x\)和\(y\)都是整数,这个算法最核心的地方就在分支语句这里,应该有个十分效率的方法来判断是否要“上升”。有个好的方法是查看两个待选像素中心之间的中点和直线的关系。以像素中心位置\((x,y)\)来说,两个待选像素中心为\((x+1,y)\)和\((x+1,y+1)\),中点为\((x+1,y+0.5)\),如果直线在中点上方则绘制上面的待选像素,否则绘制下面的待选像素。我们可以通过\(f(x,y)\)的取值来判断这一关系,如果\(f(x,y) = 0\)那么中点在直线上,如果\(f(x,y)
页:
[1]