什么是基于笔触的渲染
基于笔触的渲染(stroke-based rendering,下称SBR),简单的讲就是根据图像生成笔触,然后再用笔触对图像进行重绘。这个过程实际上是模仿画家实际画画的过程,也就是观察->理解->表达的过程,画画的时候有一句话叫意在笔先也就是这个意思。具体可以看这篇关于SBR的综述:http://luthuli.cs.uiuc.edu/~daf/courses/ComputerGraphics/01210867.pdf。
为什么要在Unity中实现SBR
研究生的时候我是研究非真实性渲染(Non-Photorealistic Rendering,下称NPR)的,发现本质上有两种方法,一种是基于经验的研究方法,也就是没有理论根据,根据实验结果来设计渲染方法。好像有个图形学大佬说过:看起来是对的,就是对的。大概说的就是基于经验的研究方法。还有一种是基于物理模拟的研究方法,比如研究颜料的实际混色和水分的流动等等。
我发现基于经验的方法有点凭感觉,无论是设计算法还是评判结果都不好弄。基于物理模拟的研究方法又是太笨重,只是在计算机中再现了工具和颜料,而怎么画还是靠艺术家手工去画。于是我在想,怎么让计算机真的像艺术家一样去思考,去表达呢。
刚好以前接触过一点计算机视觉,于是在想有没有一种基于视觉的研究方法,让计算机去理解图像,然后像人一样去画,也就是渲染,而不是用一堆滤波器。
那时候用了opencv去做图像分割,然后计算图像的显著度(saliency),再根据显著度生成笔刷,最后用cuda并行地渲染笔刷,做了这样一个离线版本的SBR。效果还不错,但是工作之后这个研究就放下了。
最近开始学习Unity的Compute Shader,发现跟cuda很像,于是又想起了SBR,感觉用Unity可以在后处理中实现的SBR,于是做了一些尝试。
具体的实现方法
所有处理都写在post processing stack的render里面,流程大概如下:
其中梯度张量的经过高斯平滑后,称为平滑化梯度张量,求法如下:
IGa为高斯滤波的卷积运算,px为sobel算子计算的x方向的梯度,py为sobel算子计算的y方向的梯度。至于为什么用SVD分解求得的第二特征向量来计算旋转矩阵,那是因为第一特征向量(主特征向量)表明的是变化最大的朝向,而第二特征向量与之正交,所以可以用来表明笔触的流向。
渲染结果:
左边为原帧,右边为SBR渲染后的效果:
另外,笔触的间隔和的大小可以调节出不同的效果:
不同笔触纹理可以有不同的渲染效果:
代码
代码在这里:
alpacasking/SBRgithub.com时间有限,现在只写了最基本的流程,其实还有很多东西值得做,比如:
- 根据深度纹理检测前景和背景,从而生成不同密度和大小的笔触
- 利用CV相关知识分析理解图像再生成笔触
- 同时用不同的笔触纹理渲染
- 让每帧之间的笔触衔接得流畅
- 可以为油画,水彩风格等做进一步的研究
- 等等。。。
有时间的话会慢慢加上的,各位有兴趣的话也可以自行魔改。