Notifications
Article
在Shader Graph中使用表面梯度框架编排法线贴图
Updated 18 days ago
1.7 K
0
最近,我们的Unity Labs发布了一篇论文,介绍了一种便于技术美术师和图形工程师理解、使用的法线贴图混合框架。该方法突破了传统方法中的几个局限。
作者:Morten Mikkelsen,2019年11月20日
原文链接:https://blogs.unity3d.com/2019/11/20/normal-map-compositing-using-the-surface-gradient-framework-in-shader-graph/

自从实时图形中的法线贴图发布以来,组合、混合法线贴图一直是一个难题,即使是经验丰富的图形工程师也难以精确地排布贴图,创造出富有视觉美感的成果。在以前,大家经常在世界中混合法线贴图,产出的结果一般都不准确,效果也不尽如人意。在“Surface Gradient Based Bump Mapping Framework(基于表面梯度的凹凸贴图框架)”一文中,Labs团队介绍了一种可以解决传统法线贴图局限性的新框架。新方法中虽然结合了不同类型的凹凸贴图,但使用起来依旧简单、易懂,对技术美术师和图形工程师十分友好。
在现代计算机图形设计中,材质层级排布是实现环境多细节、多内容的关键。而我们又需要在多个纹理坐标上支持凹凸式贴图、多个凹凸贴图的混合,才能做到材质层级排布。此外,我们还需要在对象空间法线贴图上调整凹凸尺度,在正切空间法线贴图和三面投影上正确地排布/混合这些贴图。
传统上来说,实时图形仅在单个纹理坐标集上支持凹凸贴图。我们需要收集每个顶点数据才能预计算、存储(在正切空间上)凹凸贴图数据。每多一个顶点,纹理坐标集便会占用不少的额外存储空间。不仅如此,在程序化几何形/纹理坐标,或高级几何变换上,此类方法是不可行的。
高清渲染管线(HDRP)会利用凹凸贴图的表面梯度式框架来解决这个问题。在HDRP中,每个顶点的传统正切曲线空间会被用作首个纹理坐标集,来严格实行MikkTSpace规范。在低多边硬表面几何形上烘焙法线贴图时,或在其它较困难的用例中,我们会使用此种方法。
而在其它次级坐标集上,我们则会在运行时直接于像素着色器上计算正切空间。此种方法使得我们能在所有纹理坐标集上,包括在程序化几何形和高级变换(不止于简单的蒙皮)中,支持法线贴图。
我们可以遵循论文中的方法,累算表面梯度,正确地混合贴图。
直到本文发布时,该框架仅在构建于HDRP中的着色器上可用。但是,在Unity 2019.3.0b4和Shader Graph的7.1.2版本中,我们发布了一个框架的原型版本,用其构建了一个示例场景,该场景可在Github上下载(或在本文中下载)。框架本身是作为Shader Graph的子图应用的,而每个子图都使用了内置节点构建。
整个方法包含以下步骤:
  1. 为每个凹凸贴图建立一个表面梯度
  2. 用用户制定的凹凸规模缩放每个表面梯度
  3. 将所有表面梯度加入/混合为一个尺度
  4. 运算后产出最终完成的凹凸法线贴图
如果遵从此框架,每种凹凸贴图形式会产生一个表面梯度,便于统一处理。这些贴图形式包括正切/对象空间法线贴图、平面投射、三面投影,甚至是程序化3D纹理形式的凹凸贴图,应用此种方法能方便我们正确地混合贴图。
示例中包含了几个使用此框架的图表,每个图表展示了框架的不同使用案例。我们将在下文中过一遍这些例子。

基本法线贴图

在basic着色器的图表中,展示了整个流程,以及使用顶点正切空间和程序化正切空间之间的不同。
  1. 子图basisMikkTS.shadersubgraph会产出常规正切和二重切线空间。该图表仅在UV0上运作。
  2. 子图GenBasisTB.shadersubgraph可使用任何纹理坐标查出程序化正切和二重切线空间。
由于例中只有UV0可用,在黑板上我们有一个布尔(Boolean)属性来决定是否使用此图表。若要使用其它UV组,着色器需要使用第二种方法。
注意我们有一个特殊的子图:tex ts norm to deriv.shadersubgraph,来在正切空间法线贴图上采样。它会返回一个称作derivative(衍生物)的vector2向量,而不是vector3向量。在使用相同的UV组采样时,我们可以添加或混合这些衍生物。然而,我们需要添加或混合表面梯度后,才能支持不同UV组或凹凸贴图的添加和混合操作
要产出一个表面梯度,可以使用上图中的Surfgrad TBN.shadersubgraph子图。
要调整一个表面梯度上的凹凸尺度,可以使用一个简单的多节点结构。或者,也可使用Apply Bump Scale.shadersubgraph子图。
之后,我们便能利用子图Resolve Surfgrad.shadersubgraph将表面梯度转换为贴好的凹凸法线贴图了。

对象空间法线贴图

我们还将对象空间法线贴图整合进了表面梯度工作流中。在此工作流下,我们可以调整凹凸贴图的强度,在法线贴图上混合/添加其它形式的凹凸贴图。
下方图表名为OS nmap basic
首先,将样本法线贴图从对象空间转换到场景空间中。为了最佳效果,转换可以作为法线贴图完成,但由于Shader Graph内置的转换程序不支持法线贴图,所以最佳选择是方向贴图。接着,使用Normal to surfgrad.shadersubgraph子图将法线贴图转换为表面梯度。当凹凸贴图的源换成了表面梯度,我们便能像处理其它凹凸贴图一样处理了。用上文提到的方法调整凹凸尺度,添加/混合多个表面梯度,直到最后完成,产出法线贴图。

三面投影

三面投影主要用于特殊的3D纹理凹凸贴图。在论文“Surface Gradient Based Bump Mapping Framework(基于表面梯度的凹凸贴图框架)”中,介绍了制作投影的运算步骤。下方是普通法线贴图混合(左)和使用表面梯度的方法(右)之间的不同(在Siggraph 2018的Unity演讲中有过介绍)。
Triplanar(三面)图表会使用Triplanar to surfgrad.shadersubgraph子图执行混合操作,用一个三面投影来产出一个表面梯度。和前面一样,我们可以使用凹凸尺度修改表面梯度,将梯度混合/添加到其它表面梯度上,最后完成法线贴图的制作。

混合/添加多个凹凸贴图

该框架最宝贵的一个优点是,可以利用任意数量的纹理坐标集,包括程序化UV,来正确混合任何类型或数量的凹凸贴图。下方示例中展示了三种不同的凹凸贴图混合后的效果:一个可堆砌的正切空间贴图、一个对象空间法相贴图、以及一个作为程序化3D纹理的凹凸贴图。
Mixing(混合)图表以下方的方法来混合三种贴图。注意每个凹凸贴图的表面梯度结果是如何受相应的贴图强度影响的,及如何通过添加或混合表面梯度来组合各梯度。最后,系统将处理组合后的表面梯度,产出最后的法线贴图。

更多示例

在本Unity示例场景中(见上文),还有几个其它示例,如法线贴图表面上的三面投影应用,在视差矫正或视差遮蔽贴图(POM)后的细节法线贴图应用,高度贴图上的凹凸贴图,使用程序化3D纹理的凹凸贴图,等等。

未来要面临的明显问题

整个框架可以单使用子图构架,子图包含有可即取即用的节点,节点又能表示出Shader Graph的强度和灵活性。在此前提下,框架并不会完全遵照UV0的MikkTSpace方法,关于这个问题,我们正在努力解决以下几点:
  1. Shader Graph现今不会使用加入插值后的非标准化正切、二重切线和法线贴图,这在MikkTSpace中是有要求的。
  2. Shader Graph需要在UV0的正切空间上导出最终的凹凸法线贴图。由于我们在Shader Graph中并没有使用正确的转换方法,这里可能出现问题。
而由于Shader Graph需要在UV0正切空间上的主节点中传入凹凸法线贴图,我们在使用对象空间法线贴图或三面法线贴图是就会出现问题。一个将推出的解决方法是支持在场景空间中将法线贴图传入到主节点。
需要指出的是HDRP的内置着色器并没有此类问题,可以完全遵循MikkTSpace的方法。

2019.3中的新功能

现今我们可以在Shader Graph中以可视化的方式编写着色器,在Visual Effect Graph中创造出自定义的外观和渲染行为。我们还添加了Shader Keywords(着色器关键词)功能,可在图表中创建静态的枝干。该功能可以帮助用户构建自己的多细节层次(LOD)着色器系统。此外,还有对DOTS(面向数据技术栈)动画顶点蒙皮的支持,帮助用户制作更好的水体和枝叶效果。不仅如此,我们还有便签功能,用户可留下评论和解释给项目制作人,提高工作流效率。最后,程序化模式子图示例中展示了如何应用数学来创建程序化形状和模式。

请在Shader Graph论坛中向我们提供反馈吧!

开发过程中遇到问题?打开Unity Connect App或者Unity编辑器内置群聊工具,在“技术交流”群聊组中提问。
Unity China
710
Comments