卡通渲染的一点心得

   通常情况下,我们见到3D场景都是按照真实的光照模型来照明渲染的,虽然目前实时的光照模型还只是对真实世界的一种近似,但是这种模型已经有了良好的可接受的真实感。
   在人们想法提高场景渲染结果的同时,其他的非真实感渲染技术也是非常有用的,比较常见的就是卡通风格的渲染,这种渲染结果类似于我们常见的卡通画,本文将对卡通渲染进行介绍。

一. 什么是卡通渲染
   首先我们要弄清楚什么是卡通渲染,卡通渲染就向动画片一样,看上去像2D的画面,这个有以下两条主要特点:
   1)要有很急剧的明暗对比度,即颜色变化比较快,不能像一般的3D场景里面,在灯光作用下,物体或者人物的颜色是连续变化的(阴影除外)。
   2)要有比较明显边缘黑线,即明显的轮廓感觉。

二. 实现算法
(一). 颜色算法
   要得到第一点的效果,有一定数学基础的人应该立刻就有想法了:“把连续的区间变成离散的不就行了?”事实也是如此,你可以试着把0到1的连续区间均匀进行5等分:
      [0.0~0.2]归到0.2,
      (0.2~0.4]归到0.4,
      (0.4~0.6]归到0.6,
      (0.6~0.8]归到0.8,
      (0.8~1.0]归到1.0;
   原来的黑色由黑边代替。但是这样有点不理想,颜色变化太均匀,没有变化,如下图中圆球的纬度线,而且整体颜色偏暗。所以实际操作中不推荐机械均匀地进行离散化处理,比较好的方式是尽量控制得稍微亮一些,当然特殊情况可以自行调整。

(二). 边缘算法
   对于第二点,就没有第一点这么直观了,方法也比较多。主要有以下三种方法,每个方法各自的表现也不同。

1. 直接画轮廓边
   最直观的方法就是找出轮廓线,在第一遍渲染物体之后,再渲染一遍轮廓线就可以了。由于我们渲染用的基本单位是Polygon(也就是三角形),所以屏幕图像的边缘部分必然也是渲染物体的边缘,轮廓线就是边缘三角形的某一条边,称之为轮廓边。
   怎么才能求出轮廓边呢?首先要求出轮廓三角形,用观察方向(Camera的方向)去点乘转换后的Polygon的法向量(都是单位化的)得到点积,点积的结果表示了一个Polygon靠近边缘的程度,越是靠近边缘的面点积的绝对值越接近于0,大于0代表背向视点,小于0代表面向视点。由于在一般的3D物体中,表面是闭合的,边缘边必定是由一个背向视点的Polygon和一个面向视点的Polygon的公共边。
   具体程序的算法就是:遍历所有的三角形,找出所有两边点积异号的公共边,但是这种方法非常耗费CPU的时间,特别是有大量Polygon的情形下。

2. 用边缘三角形画轮廓
   我们可以用一个稍微简化的方法,就是把靠近边缘的三角形渲染成黑色,这样就可以给物体制造一种很重的边缘效果。这种方法只要渲染一次,速度比较快,流程也很清楚。这里面也有两种方法:
   1)用法向量乘以Camera到观察点的方向的单位向量,这样的情形下,同一个平面的点积值一致,颜色基本也一致,但是对同一个物体的远近两边的轮廓线不对称,失真较严重,问题如下图:

   2)用法向量乘以Camera到当前顶点的方向的单位向量,这个情况下,远近两边的轮廓线不对称的问题没有,但是同一个平面的远近处理上有问题,特别是这个平面和观察方向的夹角已经很小的情况下,这时远处由于夹角更小,直接被认为是边缘地带,渲染成黑边。
   这种情况下还有一个问题,就是对模型的精度要求比较高,在大Polygon的情况下,黑边要么没有,要么很粗,就算在小Polygon情况下也不是很均匀,范例如下图:

   这是经过一定角度调整的画面,总体来说还是有一定的实用价值:

3. 画两遍物体
   具体方法是,利用Vertex Shader,在画每个面的时候,把点朝法向量相反的方向缩进一点,这个值很小,根据物体的比例差不多是1%到2%的比例,把物体渲染一遍,注意的是,渲染物体要根据颜色进行离散操作。这里提供一种比较快的方法,可以省去在shader里面进行比较操作,提高渲染速度,而且结构也比较清晰:自己在程序中创建一个texture,精度不需要很高,32*1或者16*1都可以,在程序中设定好每个离散的值,渲染的时候用作texture,然后在Pixel Shader里面直接查找值就可以了,可以对RGB都使用这样的离散操作。
   第二遍,把物体以原来大小用黑色再渲染一遍,就可以得到黑边了,仔细的程序员不禁要问,那不是把原来的物体都覆盖了么,对了,这里面有个小小的技巧,这遍渲染要把Polygon的渲染方向反一反,把D3DCULL_CCW改成把D3DCULL_CW,即是渲染物体向里的面,渲染好了再返回成D3DCULL_CCW,这样就没有覆盖的问题了,直观方便讲卫生。这个方法思路很清晰,代码也很直观,渲染出来的边框粗细很均匀,从任何方向看都一样,缺点就是要渲染两遍,速度会受些影响。
   最终效果如下图:

PS:这篇文章参考了网上的一些概念和算法,并编写了程序进行演示,算是对卡通渲染的一个归纳,希望对学习DirectX的同志有帮助并引起大家的思考。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值