[图形学] 《Real-Time Rendering》卡通渲染

原文:《Real-Time Rendering,Third Version》 Toon Shading章节

11.1 卡通着色

        正如不同的字体能给文字带来不同的风格一样,不同的渲染风格也有着自己的情绪,含义和词义。人们对于NPR的一种特殊形式——卡通渲染(cel or toon shading)给予了大量的关注。由于这种风格和卡通形式相一致,它具有丰富的幻想感和童真感(至少在西方世界)。在最为简单的情况下,我们使用实线绘制物体边缘,用纯色块填充不同的区域。McCloud在他的经典著作《Understanding Comics》中描述了这种风格流行的一个原因:"通过简化来扩展"。也就是说,通过简化和剔除复杂的部分,可以增加表达的信息量。观众会更加认可那些以简单风格绘制的卡通人物。

        在计算机图形学中,卡通渲染风格已经发展了十多年,用于将三维模型和二维卡通动画关联。和其他NPR相比,它更容易通过计算机自动生成,因为它的定义更加容易。像Okami和Cel Damage这样的游戏已经有了很好的表现效果。如图11.2.

         卡通渲染有着很多不同的方式。对于只有纹理没有光照的模型,可以通过简化纹理来近似实心填充的卡通风格。在着色中,两种最常用的方法是用实心颜色填充多边形区域(无光),以及使用双色调来表达光照和阴影区域。实心填充是比较朴素的方式,而双色调填充,有时候称作硬着色(hard shading),可以通过将传统光照方程中的元素重映射到不同的颜色上实现。这一方法和Grooch在NPR技术照明中的光照模型相关联。此外,轮廓通常使用黑色来表达,它使得物体卡通的效果更加明显。下一章将描述计算以及渲染轮廓的方法。

        Lake和Lander都提出了一种对每个顶点计算n· l 点积,并作为纹理坐标来访问一维纹理的方法来计算漫反射的思想。这可以在CPU中完成,也可以通过简单的顶点着色器实现。纹理映射本身只包含了两个色调,亮和暗。因此,对于朝向光源的面,将使用亮色调的纹理。对于漫反射而言,n· l < 0 意味着表面远离光照,它处在阴影中。不管怎样,我们可以将漫反射重映射到任何其它期望的值。例如,在图11.3中,双色调填充使用的阈值是0.5。类似地,简单的一维纹理可以重新映射镜面高光。Card and Mitchell描述了如何在GPU上实现这种阴影算法。Barla等人使用二维纹理来代替一维纹理,以增加视点相关性。我们通过表面深度或者方向来访问二维纹理。这允许在远处或者快速移动的物体能够表现得比较平滑。例如,Rusinkiewicz等人表达了一个有趣的可变着色模型,他沿着相反的思路进行,通过调整视觉光位置给表面阴影带来高对比度,超现实的感觉。

[图形学] 《Real-Time Rendering》卡通渲染_第1张图片

11.2 描边渲染

        NRP算法的主要主题和技术中包含了卡通轮廓线渲染。Isenberg等人对本课题做了深入的研究。我们的目标是给出一个更加通用,一般性的算法。使用的轮廓算法可以根据表面角度,过程几何,图像处理,矢量边缘检测或者他们的混合使用进行粗略的分类。卡通渲染中有着不同类型的边缘:

        •  不被两个多边形共享的边界线。例如,一张纸的边界。固体物体通常没有边界线。

        •  由两个多边形共享的折痕、特征边,且两个多边形之间的角度(二面角)大于某个阈值。一个较好的默认角度为60度。此外,折痕的边缘是顶点在两个相邻多边形之间顶点法线不同的地方。例如,一个立方体有着折痕边。折痕边可以进一步细分为脊和谷边。

         •  两个不同材质或者其它原因导致着色有差异的三角形之间的材质边。它也可以是美术希望一直显示的边缘,比如前额线或者分开相同颜色的裤子和衬衣的线。

         •  两个相邻三角形相对于某个方向矢量(通常是视线)有着不同的面向的轮廓边缘。

[图形学] 《Real-Time Rendering》卡通渲染_第2张图片

        如图11.4,这种分类是基于文献中的常见用法,但也有一些变化。例如,我们所谓的折痕以及材质边缘有时被称为边界边缘。虽然我们在这里关注的是卡通渲染,但是已经研究了在表面上表示轮廓、脊、谷的绘制线或来自光照的高光。

       对于卡通渲染,我们使用从眼睛到边缘上某个点的向量来定义轮廓边缘。换言之,轮廓边缘相邻的三角形一个是正面的,另一个是背面的。注意,这与计算机图形学定义和通常指的轮廓(即对象的外部边界)稍有不同。例如,在头部的侧面,计算机图形学定义中包含了耳朵的边缘。轮廓边缘的定义有时还可以包含边界边缘,也就是那些连接相同三角形前面和后面的边。我们定义轮廓边缘不包括边界边缘。12.3节讨论处理多边形数据,并创建具有一致面向的连接网格,以及确定边界、折痕和材质边缘。

11.2.1 表面角描边

        类似于11.1中的表面着色器,我们可以使用视点方向和表面法线之间的点积来计算轮廓边缘。如果这个值接近0,那么这个表面几乎处在眼睛视线的边缘处,所以可以认为是边缘。这一技术相当于使用球形环境贴图在物体边缘周围用黑色环进行表面着色,参照图11.5。在实践中,可以使用一维纹理来代替访问环境映射。Marshall 展示了如何使用顶点着色着色器来表现描边,他没有计算反射方向来访问环境映射,而是使用视线和顶点法线的点积来访问一维纹理。Everitt使用mipmap金字塔来执行这一过程,把最顶层绘制为黑色。当表面变为边缘,它将访问最顶层,因此着色为黑色。由于没有使用顶点插值,边缘会更加清晰。这些方法非常快,因为在一次pass中将完成所有工作,并且纹理滤波会帮助消除边缘的锯齿。

        这种技术只适用于某些模型,他们的表面法线和轮廓边缘存在一定的关联。对于像立方体这样的模型,这种方法是失败的,因为我们通常无法找到轮廓边缘。然而,通过显式地绘制折痕边缘,这种尖锐的特征将被正确地呈现,尽管风格和轮廓边缘有所不同。这种方法的特点或者说是缺点是随着表面曲率的变化,轮廓线的宽度会变化,大而平的多边形在接近边缘时会完全变黑,这通常不是我们所期望的效果。在实验中,Wu法线对于游戏《Cel Damage》,这种技术对于1/4的模型给出了极好的结果,而其它的却失败了。

[图形学] 《Real-Time Rendering》卡通渲染_第3张图片

11.2.2 过程几何描边

       Rossignac和van Emmerik提出了实时轮廓渲染的一种技术,后来由Raskar和Cohen进行了改进。其基本思想是先渲染正面,然后用某种方法渲染背面,使其轮廓边缘可见。有许多渲染背面的方法,每个方法都有自己的长处和弱点。每一种方法的第一个步骤,都是绘制正面图,然后打开正面剔除关闭背面剔除,从而只绘制背面。渲染轮廓边缘的一种方法是只绘制背面的边缘(而非正面),使用偏移(biasing)或者其它技术确保这些线条画在正面的前面。这样,除了轮廓边缘以外,所有的线都是隐藏的。

       制作更宽线条的一种方法是使用黑色渲染背面,在没有偏移的情况下,这些背面将始终保持不可见。所以,我们要做的是在屏幕z轴上移动背面来偏移它们。这样,只有背面三角形的边缘是可见的。Raskar和Cohen给出了一些偏置的方法,比如固定量的平移,或者z-深度的非线性补偿,或者使用像glPolygonOffset一样的调用进行深度斜率偏移。Lengyel讨论了如何通过修改透视矩阵提供更精细的深度控制。所有这些方法的一个问题是,它们创建的线不具有均匀的宽度。要做到均匀,向前移动的数量不仅取决于背面,还要取决于相邻的正面,参见图11.6。背面的斜率可以用来使多边形向前偏移,但线的厚度也取决于正面的角度。

[图形学] 《Real-Time Rendering》卡通渲染_第4张图片

        Raskar和Cohen通过使每个背面三角形沿着边缘变大,从而解决了这种邻居以来的问题。也就是说,三角形的斜率和视点的距离决定了三角形的扩展程度。

[图形学] 《Real-Time Rendering》卡通渲染_第5张图片

        一种方法是沿着平面向外扩展每个三角形的顶点。渲染三角形一个更安全的方法是向外移动三角形的每个边并且连接边缘,这样避免了顶点远离原始三角形,可见图11.7。注意,这种方法不需要对三角形进行偏移,因为背面已经扩展到了正面的边缘之外。图11.8展现了三种方法的结果。Raskar在后面的论文中提出了一种改进的边缘扩展因子的计算方法。

[图形学] 《Real-Time Rendering》卡通渲染_第6张图片

        在刚才给出的方法中,背面的三角形沿着它们原始面进行扩展。另一种方法是沿着顶点法线移动顶点,移动距离与到眼睛的距离成比例。这种方法被称作"壳"或者"晕",因为移动的背面形成了围绕原始对象的外壳。想象一个球体,先正常渲染球体,然后相对于球体中心5像素宽扩展球体半径。也就是说,移动球体中心的一个像素,等于在世界空间中移动球体3毫米。参见图11.9。对于顶点着色器来说,它能很好地完成将顶点沿着法线外扩的任务,因此加速器可以在没有任何CPU帮助的情况下绘制轮廓。这种类型的扩展有时称作壳(shell)映射。顶点信息是共享的,因此可以渲染整个网格,而不是单个多边形。该方法实现简单、效率高、鲁棒性好、性能稳定,是游戏《Cel Damage》所使用的方法,可参照图11.10。

[图形学] 《Real-Time Rendering》卡通渲染_第7张图片

[图形学] 《Real-Time Rendering》卡通渲染_第8张图片

11.10 游戏Cel Damage中实时卡通风格渲染的一个例子。使用背面shell扩展来得到轮廓。

        这种壳(shell)技术有许多潜在的缺陷。想象从正面观察一个立方体,只有一个面是可见的,形成轮廓边缘的四个背面的每一个都将沿着其对应的立方体面方向移动,因此在角落处留下间隙。这是因为每个拐角处都有一个顶点,每个面都有不同的顶点法线。问题在于,展开的立方体并不真正形成外壳,因为每个角顶点都在不同的方向上展开。一种解决方案是在同一位置上强制顶点共享一个新的、平均的顶点法线。另一种技术是折痕上创建退化几何,然后按区域扩展成多边形。

      壳(shell)和扩展技术都会比较浪费,因为所有的背面都进行了渲染。扩展技术不能作用于曲面,壳技术可以作用于曲面,只要曲可以沿着曲面法线向外移动。z轴偏移适用于所有曲面,因为唯一的修改是z深度的偏移。所有这些技术的局限性在于,无法控制边缘外观,半透明表面很难使用轮廓渲染,并且没有某种形式对边缘做抗锯齿。

       这一类几何技术的一个值得注意的特点是不需要邻居信息或者边缘列表。每个多边形独立于其余部分进行处理,因此这种技术适合于硬件处理。然而,这里讨论的所有方法都一样,每个网格都应该进行预处理,保证面是一致的。

       此类算法只渲染轮廓边缘,其它边缘(边界,折痕和材质边)必须以其它方法呈现。这些可以使用11.4节中的线绘制技术之一来绘制。对于可变性物体,折痕线可随着时间变化。Raskar给出了绘制脊线的一种很好的方案,无需创建和访问边缘连接数据结构。其思想是在渲染三角形的每个边上生成一个附加多边形,这些边缘多边形通过用户定义的临界二面角来确定何时应该看到折痕。现在,如果两个相邻的三角形大于这个临界值,那么边缘多边形将是可见的,否则,它们将被三角形隐藏。对于谷边,该技术可以通过使用三次模板缓冲区实现。

11.2.3 图像空间中的描边

        上一节中的算法有些被分类为基于图像的因为屏幕分辨率决定了它们是如何执行的。另一种算法是更直接地基于图像的,因为它们完全根据存储在缓冲区中的数据进行操作,并且不修改(甚至不知道)场景中的几何形状。

        Saito和Takahashi第一次引入了G-Buffer的概念,也称作延迟渲染。Decaudin扩展了G-Buffers在卡通渲染中的应用。基本的想法非常简单:NPR可以通过在各种信息缓冲器上执行图像处理技术来完成,通过寻找相邻z缓冲区中的不连续性,可以找到大多数轮廓边缘的位置。相邻表面法线值不连续的地方指向了(并且常常是轮廓)边缘。使用环境颜色渲染场景也可以检测其它两种技术可能遗漏的边缘。

        Card和Mitchell首先使用了顶点着色器将场景中的世界空间法线和z深度渲染成纹理,从而实时执行这些图像处理操作。法线被写入颜色的一般通道,z深度被写入alpha通道。

       一旦创建了这个图像,下一步就是找到轮廓、边界和折痕边缘。其思想是使用法线图和z深度图(在alpha通道中)渲染填充屏幕的四边形并检测边缘的不连续性。想法是在一次pass中对同一纹理进行六次采样,并实现sobel边缘检测滤波器。通过对四边形的使用6对不同的纹理下标来访问进行六次采样。这个滤波器实际上被两次应用到纹理上,一次沿着一个轴,最终合成两个结果图像。另一个特征是,所产生的边缘的厚度可以通过进一步的图像处理技术来膨胀或者腐蚀。相关结果可以参照图11.11。

[图形学] 《Real-Time Rendering》卡通渲染_第9张图片

11.11 我们根据法线图(左上)和深度图(左中)的值进行了边缘检测。右上图显示了法线图边缘检测得到的结果,右中则为深度图得到的。左下角的图是加粗的结合。最终渲染的结果如右下所示,是通过Gooch渲染结合边缘得到。

       该算法有许多优点。该方法处理所有基元,甚至曲面,不像大多数其它技术。网格不必保持一致或者连接,因为该方法是基于图像的。从性能的角度来看,CPU不参与创建和遍历边缘列表。

       该技术的缺陷相对较少,对于处于边缘的表面,z深度比较滤波器可能会错误的检测表面上的轮廓边缘像素。z深度比较的另一个问题是,如果差异最小,那么可以忽略轮廓边缘。例如,通常会忽略一张纸的边缘。类似的,法线滤波器也会跳过这张纸的边缘,因为法线是相同的。检测这种情况的一种方法是在场景的环境光或者对象id颜色渲染上添加一个滤波器。但这仍然不是万无一失的,例如,折叠一张纸依然会产生边缘重叠的不可检测的边缘。

       由于z深度信息是保留的最重要的字节,所以比纸张更厚的特征也可能丢失,特别是在z深度范围更大的大场景中。可以使用更高精度的深度信息来避免这一问题。

11.2.3 轮廓边缘检测

        迄今为止所描述的大多数技术都有着需要两个pass来渲染轮廓的缺点。对于过程几何方法来说,第二个pass中的背面渲染通常会检测出比实际边缘更多的像素。随着边缘变厚,会出现更多的问题,而且也无法控制渲染的风格。图像方法也有着类似生成较粗线条的问题。另一种方法是检测边缘轮廓并直接渲染它们。这种形式的轮廓边缘渲染允许我们更好的控制如何渲染线条。由于边缘和模型无关,因此可以创建像网格在冲击中冻结导致轮廓发生意外跳变的效果。

        轮廓边的两个相邻三角形一个面向观察者一个远离观察者,测试公式为:

        其中n0,n1代表三角形的法线,v代表从眼睛指向物体的实现方向(到任一末端)。为了使测试正确工作,表面朝向必须保持一致(参见12.3节)。

        找到模型中的边界线的标准方法是循环遍历边缘列表并进行测试。Lander指出一种可行的技术,即提出平面多边形内的边缘。也就是说,给定一个连接的三角形网格,如果一个边缘的两个相邻三角形位于同一平面上,不要将这个边缘添加到边缘列表中,来测试它是轮廓边缘。在一个简单的时钟模型上实行这个测试将边计数从444个降到了256个。提高轮廓边缘搜索效率的方法还有很多。Buchanan和Sousa通过对每个单独面重复使用点积测试,避免了对每个边缘进行单独点积测试。Markosian等人从一组轮廓环开始,使用随机化搜索算法来更新该集合。对于静态场景,AILA和Miettinen采取了不同的方法,将有效距离和每个边缘相关联。这个距离是观察者可以移动到的,仍然存在轮廓,且内部边缘保持状态的最远距离。通过仔细的存储,可以最小化轮廓的多余计算。

       在任何模型中,每个轮廓总是由一个单一闭合曲线组成,称为轮廓环。因此,每个轮廓顶点必须有偶数的轮廓边缘。请注意,表面上可以有不止一个轮廓曲线。类似的,轮廓边缘可以仅属于一条曲线。这并不意味着轮廓曲线上每个顶点只有两个轮廓边缘。例如一个形状类似于数字8的中间点就有4条边缘。一旦在轮廓线上找到了边缘,那么也可以去测试它的邻居是不是也是边缘。我们重复这一步骤直到整个轮廓被找到。

        如果帧与帧之间相机和对象移动较小,那么可以合理地假设来自先前帧的轮廓边缘仍然可能是有效的轮廓边缘。因此,这些部分可以用于下一帧开始检测轮廓边缘。当模型改变方向时,轮廓环也在创建和破坏。 Hall讨论了这些检测,以及大量的实现细节。与暴力算法相比,Hall报告的性能提高了七倍。主要缺点是,如果没有成功找到它们,新的轮廓环可能丢失一帧甚至更多。

        该算法可以倾向于更好的速度或者质量。一旦找到了轮廓,立即画出线条。显式地找到轮廓线的一个优点是可以使用线条、纹理或者其它方式进行绘制。需要某些类型的偏移来保证线条在表面前的适当位置绘制。如果绘制了较厚的边,也可以适当地拼合而没有间隙。这可以通过在每个轮廓顶点处绘制一个屏幕对齐的圆来完成。

        轮廓绘制的一个重要特点是它突出了模型的多边形性质,也就是说,模型的轮廓是由直线构成的这一点特性更加明显了。Lake给出了一种绘制曲线轮廓边缘的方法。这个想法是根据轮廓边缘的性质来使用不同纹理的笔触。这种技术仅在对象本身被赋予与背景相同的颜色时才起作用,否则笔刷和填充区域可能不匹配。轮廓边缘检测的一个相关问题是,它不适合顶点混合,N-patch或者其它加速器生成的表面,因为这些多边形在CPU上是不可用的。

        显示边缘检测的另一个缺点是它是CPU密集型的。一个主要的问题是潜在的非连续内存访问。如果可能的话,以一种有利于缓存的方式同时对表面、边缘和顶点进行排序是困难的。为了避免CPU处理每一帧,Card和Mitchell使用顶点着色器来检测和渲染轮廓边缘。其思想是将模型的每个边缘作为退化的四边形沿着渲染流水线发送,每个顶点连接两个相邻的三角形法线。当我们发现一个边是轮廓的一部分时,四边形的点被移除,此时它不再是退化的(此时可见)。这使得一个退化四边形“展开",这意味边缘的绘制。这和顶点着色器的阴影体积创建技术的思想是一致的,这在页码347中提及。只有一个相邻三角形的边界边缘,也能通过传入这个三角形法线的相反数作为第二个法线来处理。以这种方式,边界边缘总是能被处理成一个待渲染的边缘。这种技术的主要缺陷是,通过渲染流水线发送的多边形数量大大增加,并且如果网格进行了非线性变换,其性能会下降。McGuire和Hughes提出了一种使用endcaps能提供更高质量的方法。

       如果几何着色器是流水线的一部分,这些额外的多边形不需要在CPU生成并存储在网格中。几何着色器本身可以根据需要生成退化四边形。例如Gooch等人使用了高斯映射来确定轮廓边缘。在14.2.1的最后一分钟,讨论了快速将多边形集合分类为前向或是后向的分层方法,请参照Hertzman的文章或是NRP著作,以了解有关这方面的内容。

11.2.5 混合描边

        Northrup和Markosian同时使用了图像和几何元素的方式来渲染边缘。他们的方法是使用一个轮廓边缘的列表,然后,渲染所有物体的三角形和轮廓边缘,并为每个物体一个不同的id号(例如,制定一个唯一的颜色)。我们读取id的缓冲区,并根据它来决定可见的轮廓边缘。之后,对这些可见的片段进行重叠检查,并连接在一起形成平滑的路径。然后根据这些重构出的路径进行渲染。这些路径本身可以用不同的方式来处理,包括锥度、摆动、渐变以及深度和距离等。图11.12显示了一个示例。

         Kalnins等人在他们的工作中使用的方法涉及到了NPR的重要研究领域:时间相干性。在某个方面,获取轮廓仅仅是个开始。当物体以及观察者移动的时候,轮廓边缘发生改变。通过笔画提取技术,可以通过跟踪单独的轮廓环来获得连贯性信息。然而,当两个环合并在一起时,需要采取一些纠正措施,否则会在帧与帧之间出现明显跳动。可以使用像素搜素和“选举”算法来尝试保持轮廓帧与帧之间的连贯性。

[图形学] 《Real-Time Rendering》卡通渲染_第10张图片

你可能感兴趣的:(计算机图形学)