由法线贴图生成高度图的算法
Chaosinism
编辑于 2020年05月02日 21:13

注:这是两个月之前写的一个脚本,本来只放在个人主页上,但后来想到它提供的是比较通用的功能,于是也转载过来,这样如果有一般通过人士用搜索引擎查找相关问题,可能会看到这篇文章。

B站文章只能进行有限次数的修改,要获得最新的信息与资源可以查看我的个人主页(https://chaosinism.github.io)、B碗页面(https://bowlroll.net/user/261124)或Github仓库(https://github.com/Chaosinism)。如有问题可在个人主页留言或站内私信我。

2020/05/02

cut-off

自动为绘画线稿生成3D信息,从而自动计算光影,这是我持续在关注的一种技术。一直想系统地介绍一下,但不知从哪里说起。今天先简单介绍其中一种方法。

Live2D动画师Denchi(@DenchiSoft)使用法线贴图的尝试(https://github.com/DenchiSoft/Live2DLighting)。这里的法线贴图是手绘的,但已经体现了较好的光影效果。

法线贴图

法线贴图(Normal Map)利用贴图每个像素的RGB值储存该点的三维法线矢量,然后拿它来计算贴图表面的光线反射,这样低多边形的3D模型也能体现出光照细节。人们经常用它来改善游戏中的3D材质。

不过我更关心的是另一种应用——对于一张绘画线稿,如果也能得到一张法线贴图,就能自动计算其光影,从而省去很多手动上色的步骤。V-Sense研究小组(https://v-sense.scss.tcd.ie/)曾在下面的论文中提出利用深度学习生成法线贴图的方法:

Hudon, Matis, Mairéad Grogan, and Aljosa Smolic. “Deep normal estimation for automatic shading of hand-drawn characters.” Proceedings of the European Conference on Computer Vision (ECCV). 2018.

论文的成果就是开源项目DeepNormals(https://github.com/V-Sense/DeepNormals),虽然它看起来不太受学术界关注,但我个人的使用体验倒是很不错,强过不少更热门的AI上色方案,比如P站那个。

原论文插图,由左至右分别为手绘线稿、法线贴图、高度贴图与3D光影计算

高度图/置换贴图

最近,DeepNormals的作者发表了一篇后续文章,提出在生成法线贴图后可以进一步将其转化为高度图(Height Map或Depth Map):

Hudon, Matis, et al. “Augmenting Hand-Drawn Art with Global Illumination Effects through Surface Inflation.” European Conference on Visual Media Production. 2019.

高度图可以在3D软件中作为置换贴图(Displacement Map)来使用,贴图的每个点会沿法线进行位移,从而造成真实的三维凹凸效果。这种方法能做到一些法线贴图无法做到的事:

  • 法线贴图没有自阴影,而置换法支持;

  • 可以用图形学模拟距离感相关的绘画技法,如镜头虚化和色彩远近法;

  • 置换后可以在立体空间小幅旋转图片而不产生违和感,甚至可以由此将2D图片转为3D模型。

当然它也有缺点,比如运算慢,但是如果我们考虑将其应用于绘画/动画而非实时渲染,这一点就不是特别重要了,因此我还是很愿意学习这个方法的。

算法

对于如何生成这样的高度图,论文中给出的算法其实很简单粗暴。假设(u,v)为贴图坐标,相应位置的高度为Z(u,v)(也就是待求量),那么沿u方向可以计算出切线向量

,用离散形式表示其实就是

;同理,沿v方向可以计算出另一个切线向量

我们已经知道了贴图每个点的法线向量n(u,v),它应当与两个切线都垂直,即点乘得0。于是定义一个“能量”函数:

理想情况下它的值应该为0,因此将其最小化就能得到较准确的高度图。它对Z(u,v)的偏导只含一次项,用梯度下降之类的方法很容易进行优化。

自制脚本

根据论文的说法,这个算法早就有了,但我以前也考察过一些能转换法线和高度图的工具,比如AwesomeBump或GIMP法线贴图插件,它们都没有使用这种方法,而是只沿一个方向由法线累计高度,误差要大很多,不太清楚其中的缘由。

这一篇新论文自身也并没有附带开源代码,所幸算法简单,于是我用Scipy的优化器自己实现了一下,放在下面这个仓库。以后再有计算法线相关的内容可能也会在这里更新:

https://github.com/Chaosinism/NormalMapTool