这是一篇科普性质的技术文章,最终目标是实现圈状效果。在实现的过程中对需要理解的两个概念Roughness和Anisotropy进行了本质性的剖析。希望对各位有帮助

内容不少,而且越往后越有一定的难度,量力而行。

丨前言:

本文中使用的技术是建立在李航(hang li 悬挂鲤)之前的一篇技术剖析的基础之上,感谢伟大的李航。

全体材质灯光师看过来:困扰你多年的 swirl micro scratches 效果的终极解决方案在这里!?

mp.weixin.qq.com
图标

这篇文章无私地公开了《惊奇队长》中使用的技术,为此我去电影院认真观摩了这部电影,然而并没有观察出明显的圈状划痕现象。

在比较早之前,我个人就研究过这个效果的做法,很多朋友都还有印象。

做圈状划痕效果以及法线问题的笔记?

mp.weixin.qq.com
图标

为什么这次又会拿出这个问题重新来聊,是因为李航公布的做法和我之前研究的做法有某种程度上的本质区别。

之前我推送的方法是用凹凸去模拟划痕,思维是很物理的方式:现实生活中会产生凹槽的地方,我就用凹凸贴图做出凹下去的效果,以此复现现实中的物理效果。

而李航的方式本质上是用roughness——反射的粗糙度——来驱动的。

这两种做法在实现层面上有根本的不同

这种思维很不物理,很不直观,很程序员,所以一直没见人这么想过这么做过,(也许大公司内部早这么做了,但我们不知道)。

而我单独另写一篇文章再来谈这个问题,并不是对他文章内容的搬运或者复述。而是详尽地解释背后所涉及的原理,以及讨论了另一个关键的核心点:绕过flowmap的生成,直接制作anisotropy rotation 贴图,实现目标效果。

这样整个流程会更简单轻便,并且我使用Substance Designer这款程序纹理软体去生成anisotropy rotation贴图,这样可以获得程序纹理 「强大的随机性,快速生成变种,几乎无限的自定义特性」 等等属性加持,创造出更多可能性。

丨大纲

Roughness的本质

凹凸强算粗糙度的效率问题

各向异性(anisotropy)产生的本质

flowmap转aniRotationMap

绕过flowmap直接制作aniRotationMap的原理

在Substance Designer中的简单实现方法

遗留问题解决,为什么要转90度?

换个快的渲染器,我说要有红移(Redshift)

总结

丨Roughness的本质:

接前言。为什么说李航介绍的这这个思维很程序员呢,这就要说到roughness这个参数了。

世界上本没有粗糙度,用的人多了也就有了粗糙度 —— 鲁迅。

通过鲁迅先生的这句警示名言,我们能够窥探到很多问题。可能有很多朋友这个时候感受到了三观的动摇,因为之前看过的很多文章了里都说,粗糙度表征物体反射的粗糙和锐利程度,是决定质感很重要的一个属性。怎么在鲁迅先生的嘴里,这个属性就没有了呢?

作为长期订阅我公众号的优秀各位来说,一定都是有著强烈的求知欲望,不可能满足于表象的概念。这里,我们就要探讨roughness的本质。

我们首先思考,为什么物体的反射会有清晰与模糊的区别呢?——因为微观结构。有的物体微观结构整齐,反射就清晰;有的物体微观结构凹凸不平,体现在宏观上的反射就模糊。

关键词来了,凹凸不平。这个词让你联想到什么CG属性?对,就是bump。

这里不卖关子了, Roughness == Bump

你可能不相信,这里摆证据。

我在maya里做了两个球,

左球用roughness控制反射粗糙度的变化。

右球用的是一张whiteNoise贴图贴到bump里面,通过控制bump的强度来实现的粗糙度变化(roughness值恒定为0,你可以理解成材质球上这个参数被抠掉,没有了)。

这张whiteNoise从Substance designer软体中生成。

在maya中这张whiteNoise做了100次uv重复,以确保纹理足够密集,接近所谓的微观结构。

同时很重要的事情是关闭图片本身的过滤(filter),以确保纹理在渲染时由于过小而被模糊掉(这样会丧失原本的微观结构,无法实现本文中所做的测试效果)

以Redshift渲染器为例:

这样一对比大家就会发现,纵使右球没有使用roughness参数,但是最终效果看起来非常接近于正常调节roughness参数带来的变化效果。我觉得这张GIF图已经能非常优秀地证明鲁迅先生的观点了。

我们再来复读一次。

世界上本没有粗糙度,凹凸太慢了也就有了粗糙度——鲁迅

咦,等等,怎么感觉有哪里不对?

丨凹凸强算粗糙度的效率问题

如果按照上文论述的观点,那我们根本就不需要roughness参数了。反射越粗糙的东西,我们就给一个凹凸强度越高的纹理就解决了。

理论上说这个说法很正确,而且也非常物理、符合人的现实生活经验。但这种用凹凸强行做出粗糙度的做法,有一个专业的词可以去形容他,玩渲染的各位应该很熟悉了——brute force

道理是相通的。这种做法跟你渲GI的时候,用brute force的演算法一个意思,可能你表达的微观结构非常准确,但是渲染速度却极慢

maxAA = 4

maxAA = 117

maxAA = 1024

maxAA = 8192

从这套图就能看出来,用roughness参数调节反射粗糙度的时候,很低的采样就已经没有什么噪点了。但是用bump来控制的话,需要非常高的采样才能有效减少噪点。而且就算把采样给到系统可接受的最大值8192(图片都是使用Redshift渲染器渲染,rs的sample单位为samples相当於单位为subdivs的数值的平方,此处的8192samples相当于subdivs的90左右;另外,使用maxAA来提高质量而不是使用lighting samples是因为这里里产生噪点的原因不是灯光采样不够,而是贴图极为细密必须发射超级多的cameraAA去采样,扫盲科普),依然会看到明显噪点。

也就是说这个思路只是理论正确,但在生产和工业流程中是大错特错。

于是便引入了roughness这个参数来解决以上讨论的问题。

在CG世界里不管多么物理正确的渲染器也都只是在模拟,是对微观物理表面的的宏观总结。——悬挂鲤

亲们,相信您现在对这句至理名言又有了更深刻的体会。

另外,我之所以花很多时间精力尝试学习和提升这个方法,很大一部分原因也是出于效率考虑。虽然用之前的bump或者normal的方法也能做出圈状划痕,但那个渲染效率著实是非常差劲的。

跟本文现在剖析的方法比差太多了。

丨各向异性(anisotropy)产生的本质

为什么物体的反射会产生各项异性?前文已经做好了足够的铺垫,前戏这么足了,这次的学习肯定不会痛。

我们都已经接受了,粗糙度的本质是因为微观表面的凹凸,那么各向异性的产生,肯定也绕不开微观表面的凹凸问题。

一般的微观表面,因为其凹凸的随机性,表现出来的高光扩散是四面八方均匀的。我们之前用一张whiteNoise就模拟出来了这种效果,大家再看看这张图感受一下,物体的微观表面凹凸就是如此,随机且均匀(这不是二维码哦,别扫,没用的)。

但也有一些物体的表面,是另外一种形态。比如:

这种微观表面有极其强烈的规律与方向性,一旦有这种结构,物体的宏观反射就会出现各向异性的现象。

这种微观结构,就是产生各向异性的本质。

我还是使用同样的brute force做法,在渲染器中复现一下这个过程。

左边的材质球是只调节了anisotropy数值,从0到1的变化。(每个渲染器可能不一样,比如arnold需要配合roughness值的调节,光调节anisotropy参数没用,这里只讲原理,就不展开细节了)

右边的材质球用的是刚刚在Substance designer中使用anisotropic_noise节点生成的一张凹凸图。

同样重复300倍以后插入bump强行制造反射模糊,动画依然是k的凹凸强度。这一次,是带有各项异性的反射模糊!

再截个图给大家看一下,这张凹凸贴图贴在模型上到底是什么样的。

丨flowmap转aniRotationMap

(anisotropy rotation map 太长了,我把它缩短成aniRotationMap,标题是这个意思)

以上,我们已经理解了,roughness的本质就是凹凸。那么终于要开始我们这一期的主题了——用roughness来还原圈状划痕的凹凸效果。

核心技术在悬挂鲤的这篇文章中都有详细描述 ,想看后面的内容一定至少要搞明白这篇文章里的内容。

全体材质灯光师看过来:困扰你多年的 swirl micro scratches 效果的终极解决方案在这里!?

mp.weixin.qq.com
图标

文中使用了一张他自己绘制的flowmap图片,用这张图经过一系列的节点转换,最终插入anisotropy rotation通道,让各向异性的高光产生旋转来实现目的。

实际上flowmap的本质是平面坐标的位置,xy的数值放在红绿两个通道之中记录。而转换成anisotropy rotation贴图,则是通过某个点的位置,算出一个角度,用这个角度来控制旋转。

核心就是使用一个叫做atan2的函数(有些工具里有这个,比如arnold 和substance designer,有些工具没有,比如vray和redshift)

我在尝试使用非arnold渲染器渲染这个效果的时候,就因为缺乏数学工具而无法实现flowmap到anisotropy rotation map的转换。于是尝试了使用Substance Designer作为中间软体进行转换。

他的原图是这样的(都有签名了,我随便转应该无所谓了吧)

以下为SD中的pixel process中节点截图。我大概做了标注。主要作用是将flowmap转换成anisotropy rotation map。点大图应该是可以看清楚字的。

转换的结果是这样,已经能看出来黑白划痕了(并且有一部分划痕是负值,所以整图看起来很黑):

最后用这张SD中生成的anisotropy rotation map直接使用,也可以渲染出我们想要的效果

丨绕过flowmap直接制作anisotropy rotation map的原理

由于flowmap没有那么直观,并且在有些渲染器(vray、redshift)中不能直接使用。我开始尝试直接制作anisotropy rotation map。

使用的工具当然是程序纹理霸王——substance designer。

首先我们要明确目标,知道要实现的贴图效果到底是如何,然后再想制作方案。现在我们就来分析悬挂鲤制作的已经被验证可行的贴图到底有什么特点。

我们将之前在SD里的pixel process节点重新梳理一下,不使用-0.25 而是加0.5 ,这样做可以使最后输出的图片亮度完全处于[0,1]的范围之内,以便于我们观察图片特点(这个操作唯一的意义就是为了好观察)。

现在图片看起来是这样,亮了很多。所有的亮度都在[0,1]之间。

这个时候我们使用SD中的一个叫做histogram select的节点来观察图片,这样可以看到图片中不同亮度的划痕到底是怎么分布的。

下图是亮度从0-1 把原图扫了一遍的效果。

这下我们可以发现这张图的两个特点:

  • 仔细盯著某一根线的一端,你会发现,这根线在这个过程中完整地旋转了360度。
  • 同一色阶下,划痕的方向基本统一。

这样的特性为什么就能塑造出圈状划痕呢? 这跟我们材质球上的属性有关。

材质球上有一个anisotropy rotation属性,专门控制各项异性高光旋转方向的。这个属性的输入区间为[0,1],数值与角度有个这样的对应关系:

0 : 0°

0.25 : 90°

0.5 : 180°

0.75 : 270°

1.00 : 360°

中间是线性差值,大家应该很容易就理解这个参数了。

下图是anisotropy rotation 从0变到1的效果,高光整整地转了360度:

所以其实我们只要做出符合这两个特点的划痕图就能达成目的:

  • 每一根划痕的亮度都随著角度的变化而变化
  • 同样的角度的划痕亮度相同

用图表示大概这样(rotate 0 = rotate 1)

丨在Substance Designer中的简单实现方法:

知道原理和目标以后,我们就要想办法实现了。

这篇我只想简单讲讲思路,因为会使用SD软体的朋友应该在极少数。如果要详细写的话,另外开一篇才比较合适。

不过如果你吃透了上面的思路的话,理论上用ps都可以做,只不过相对麻烦很多而已。

节点图比较简单

主要是使用tile sampler来做散布;shape节点就是个方形,压得很扁做划痕元素。一个高斯noise让散布产生随机。

这个gaussian noise 要同时控制划痕的旋转和亮度,最后造成的效果就是:gaussian noise越黑的地方旋转角度越小,划痕亮度同时也越低;反之亦反。

最后生成的aniRotation贴图效果,SD自然是无缝的。

再用histgram select节点检查一下效果,因为我们用的是黑底,所以亮度选择为0的时候,画面大面积被选中,这个没关系。整体效果看上去跟我们预期的是一样的:

因为这是一个最简单的实现,我的划痕没做花哨的东西,就是直的。我自己测的制作方法比这个复杂很多。不过用的核心原理就是上面介绍的这些内容了。

丨遗留问题解决,为什么要转90度?

我们把刚在SD中做好的贴图放到渲染器中尝试渲染,其实还是会出现好几个说起来都挺严重的问题。我们一个一个来解决吧。

首先,如果直接把这个图插入anisotropy rotation通道,把别的所有参数都调正确,用arnold渲染器直接渲染,结果还是会非常奇怪。

为什么会这样呢?其实前文一直有一个较大的疑惑我留在那里没有解释,就是在flowmap转aniRotation map的过程中,前面的步骤都可以很容易理解了;最后一个操作 -0.25,代表的意思现在大家也应该领悟了,就是旋转90度角。

但是,为什么要进行这样的旋转操作呢??????

我建了一个简单的场景说明这个问题。图中是一排圆柱一字排开,圆柱在图中是横向的,而他们的高光方向却是竖向的,两者相互垂直。 其实这个图也是对各向异性本质的简略展示。

这个图说明了一个问题,各向异性高光拉伸的方向,和凹槽本身的结构方向,是垂直的

当我们有横向凹槽的时候,我们想要的高光形态应该是竖直的。图中黑线代表凹槽,白线代表高光。

而我们使用的aniRotate贴图,如果颜色为纯黑色代表的是什么效果?对,默认不旋转的横向高光。而看我们之前的制作过程,横向的凹槽一直是黑色的。所以,这个高光方向跟凹槽一个方向啊!!

所以我们要把高光旋转90度!

在arnold中对贴图的亮度+0.25(或者减也一样)。

ok!!

丨换个快的渲染器,我说要有红移(Redshift)

在arnold中我们已经制作出了标杆效果,但是无法忍受缓慢的渲染速度,我们尝试在一些GPU渲染器中也重现这个技术。本文中主要剖析Redshift渲染器中的问题。

因为Rs的各向异性旋转方向和arnold是相反的,所以在完成上面同样的操作以后,还要做一个反转操作。

虽然划痕都有了,但是出来的结果也还是很奇怪:

后来我研究李航的文件发现,他输出了一个mask来解决这个问题。将原来做好的划痕贴图转换成mask,只要有划痕的地方现在都是纯白。把这个mask压在图片的alpha通道里带出去。

然后在渲染器里,把mask输出到anisotropy属性上去,这样,只有有划痕的地方才有各项异性,没有划痕的地方都只是普通高光。

其中我加了一个remapHSV节点稍微调整一下划痕区域的各向异性强度,属于效果调整节点了,这个看个人口味去调。

有了mask以后你可以分开细调很多参数。

调整完之后,效果就很ok了。

丨总结

李航发的那篇技术文章对我最近的影响算是比较大的。虽然解决的问题看起来是个比较偏门,一年都不一定做得上一次的问题。

但其实最有意义的并不是这个问题本身的被解决,而是解决方案之后蕴含的思想。

纵使我好多年前早就明白了Roughness Anisotropy这些东西背后的本质,但依然还是对他们的特性掌握得不够深入透彻;像文中讲的方法,以前其实好像在Mental ray的帮助文档里都看到过,但当时是不理解,不相信能做出好效果,更没有去尝试的。

这次学会了这个技术,又给我打开了一扇大门。我觉得用Roughness配合Anisotropy确实在很大程度上能模拟和取代bump或者normal的效果。这样会让渲染效率提高很多,甚至原来可能由于参数突破上限而无法实现的效果,现在也都有可能去做了。

并且我觉得自然界中应该有很多很多反射现象都是具有某种程度的各向异性的。这个就要看艺术家处理的时候,到底把百分之多少的结构做在凹凸里,百分之多少的结构做在Roughness里,只要Roughness有,那么或多或少会体现出各项异性的现象,只是程度上有所差异。

而我们之前的制作流程里,对各向异性都只在特别明显的某些材质上才会使用。这可能是材质真实度缺失的其中一个环节吧。

之前看grant warwick的教程,发现他已经注意到了这个问题,并且已经尝试在使用aniRotationMap了。只不过我觉得他处理的方法还比较粗糙,算不上对,只是保证有了这方面的变化。

后面我想看看能不能做出一些普适性的东西,比如直接根据bump + roughness贴图,计算出aniRotation贴图。

感觉这是一个非常有意义,也相当有挑战性的方向。


推荐阅读:
相关文章