Unity Shader入门精要 第十四章

  1. 1. 非真实感渲染
  2. 2. 14.0
  3. 3. 14.1 卡通风格的渲染
    1. 3.0.1. 14.1.0
    2. 3.0.2. 14.1.1 渲染轮廓线
    3. 3.0.3. 14.1.2 添加高光
    4. 3.0.4. 14.1.3 实现
  • 4. 14.2 素描风格的渲染

  • 非真实感渲染


    14.0

    • 尽管游戏渲染一般都是以照相写实主义(photorealism)作为主要目标,但也有许多游戏使用了非真实感渲染(Non-Photorealistic Rendering,NPR)的方法来渲染游戏画面
    • 非真实感渲染的一个主要目标是,使用一些渲染方法使得画面达到和某些特殊的绘画风格相似的效果,例如卡通、水彩风格等

    14.1 卡通风格的渲染

    14.1.0

    • 卡通风格是游戏中常见的一种渲染风格。使用这种风格的游戏画面通常有一些共有的特点,例如物体都被黑色的线条描边,以及分明的明暗变化等
    • 要实现卡通渲染有很多方法,其中之一就是使用基于色调的着色技术(tone-based shading)
    • 除了光照模型不同外,卡通风格通常还需要在物体边缘部分绘制轮廓

    14.1.1 渲染轮廓线

    • 在实时渲染中,轮廓线的渲染是应用非常广泛的一种效果
    • 通常有以下几类方法:
    • 基于观察角度和表面法线的轮廓线渲染
      • 优点是简单,缺点是效果不太好
    • 过程式几何轮廓线渲染
      • 这种方法核心是使用2个Pass进行渲染,第一个Pass渲染背面的面片,并使用某些技术让轮廓可见,第二个Pass正常渲染正面的面片
      • 优点在于快速有效,并且能适用于绝大多数表面平滑的模型;缺点是不适合类似于立方体这类平整的模型
    • 基于图像处理的轮廓线渲染
      • 12、13章介绍的边缘检测方法就属于这类
      • 优点在于可以适用于任何种类的模型,但也有自身的局限所在,比如一些深度和法线变化很小的轮廓就无法被检测出来,比如桌上的纸张
    • 基于轮廓边检测的轮廓线渲染
      • 一个最大问题就是无法控制渲染轮廓的渲染风格,对于一些情况,我们希望可以渲染出独特风格的轮廓线,如水墨风等等,就可以使用这种方法来做轮廓线渲染
    • 最后一个种类就是混合了上述的几种渲染方法
      • 比如首先找到精确的轮廓边,把模型和轮廓边渲染到纹理中,再使用图像处理的方法识别轮廓线,并在图像空间下进行风格化渲染

    14.1.2 添加高光

    • 卡通风格中的高光往往是模型上一块块分界明显的纯色区域
    • 对于卡通渲染需要的高光反射光照模型

    14.1.3 实现

    • 本节中,将使用过程式几何轮廓线渲染
    • 它会在第一个Pass中,使用轮廓线颜色渲染整个边缘的面片,并在视角空间下,把模型顶点沿着法线方向向外扩张一段距离
    • 这里将模型顶点沿着法线方向向外扩张一段距离,以此让背部轮廓线可见
    • 如果直接使用顶点法线来进行扩展的话,对一些内凹的模型就可能会发生背面面片遮挡正面面片的情况。为了尽可能防止这样的情况,在扩张背面顶点之前,首先对顶点法线的z分量进行一些处理,使它等于一个定值,然后把法线归一化后,再对顶点做扩张
    • 这样做的好处在于扩展后的背面更加扁平化,从而降低了遮挡正面面片的可能性

    • 卡通风格中的高光,往往是模型上一块块分界明显的纯色区域,为了实现这种效果,就不能使用前面的光照模型
    • 之前的Blin-Phon模型使用的是法线点乘光照方向以及视角方向和的一半,再和另一个参数进行指数操作,以得到高光反射的系数
    • 对于卡通渲染所需要的高光反射模型,同样需要计算normal和halfdr的点积结果,但不同的是,我们会把该值和一个阈值进行比较,如果小于该阈值,高光反射为0,否则为1,
    • 但是这个比较的过程中,会产生锯齿效果,为了防止锯齿效果,使用了smoothstep函数做了一个光滑处理
    • w可以选择邻域像素之间的近似导数值,得到后作为阈值
    • 乘上step目的是在_SpecularScale为0时可以完全消除高光反射的光照
    • Shader:
    • 在顶点着色器中把顶点和法线都变换到视角空间下,这时为了描边可以在观察空间中达到最好的效果


    14.2 素描风格的渲染

    • 在顶点着色器首先计算逐顶点的光照,然后根据光照的结果决定六张纹理的混合权重
    • 使用提前生成的素描纹理来实现实时的素描风格的渲染,这些纹理会组成一个色调映射,它们会从左到右逐渐增多纹理中的笔触,以用于模拟不同光照下的漫反射效果
    • Shader:
    • Hatch 0至Hatch 5对应了渲染时所使用的六张素描纹理,它们的线条密度是逐次增大的
    • 由于素描风格往往也需要在物体的周围渲染轮廓线,因此直接使用14.1节中渲染轮廓的那个Pass,使用方法就是使用UsePass命令调用
    • 需要计算六张纹理的混合权重,首先在v2f结构体中添加相应的变量,也就是hatchWeight0和hatchWeight1,因为是两个fixed3类型的变量,所以两个足够了
    • 为了添加阴影效果,添加了worldPos变量以及SHADOW_COORDS宏来为阴影纹理采样坐标
    • 对顶点坐标做基本的变化,变换到裁剪空间下,然后使用_TileFactor得到纹理采样的坐标
    • 在计算六张纹理的混合权重前,首先需要去计算逐顶点的光照,因此,使用世界空间下的光照方向和法线方向来得到漫反射系数diff
    • 把权重值初始化为0,并把diff缩放到0~7的范围之间,得到hatchFactor
    • 通过判断hatchFactor所处的子区间来计算对应的纹理混合的权重
    • 最后计算了顶点的世界坐标,并使用TRANSFER_SHADOW来计算阴影纹理的采样坐标
    • 在片元着色器部分,得到了六张纹理混合权重后,就可以对每张纹理进行采样,并和它们对应的权重值做一个相乘,以得到每张纹理的采样颜色
    • 同时计算了纯白在渲染中的贡献,这段方法用1减去六张纹理的权重来得到的,这是因为素描中往往会有留白的部分,因此我们希望在最后的渲染中,光照最亮的部分是纯白色
    • 最后混合各个颜色值,并和阴影值相乘来得到最终的渲染结果
    • 效果: