Unity(和其他程序)的理想法线贴图

...以及如何找出您的内容创建管道有什么问题。


假设您有一个艺术家创作的令人惊叹的高多边形模型,并且想将其放入游戏中。艺术家在他的程序中显示了该模型的屏幕截图,它们看起来很棒。即使为低多边形版本烘焙了法线贴图,它仍然看起来很棒。


看到这个传统模型的强大之处,可以测试法线贴图!

然后,艺术家将她放到游戏中,然后她看起来……有点不对劲。


这些脸不应该平坦吗?

应该平坦的表面仍然有些圆,有些甚至凹陷,甚至更奇怪的条纹沿着它们走。熟悉情况?可能有人遇到了这个问题,并想:“嗯,也许效果不会更好”,然后继续前进。可能会用一点污垢掩盖最严重的情况。

但是,您的内容创建管道实际上存在问题。这并不总是很明显,但是问题可以解决!*

*如果您认为在某些情况下可以更改内容管道。

前言


本文介绍如何从其他应用程序中导出理想的法线贴图,以在Unity 5.3及更高版本中使用。它没有讨论如何获取高质量的法线贴图,还有许多其他教程,因此我不会涉及这个主题。



切线空间基础


问题是切线空间的法线贴图如何工作。特别是切线空间(或切线基础)如何工作。我不会太过深入地研究它们所做的技术方面。我和其他作者一样,已经讨论过这个问题,但是简而言之,切线空间决定了法线贴图方向的方向应该代表什么。法线图上的哪个方向实际上是“向前”,“向上”或“右边”。粗略地说,此方向是纹理的UV坐标和顶点法线的方向。

更重要的是要理解,用于将法线贴图从highpoly网格烘焙到lowpoly网格的程序必须计算其切线空间与使用法线贴图的程序完全相同由于不同的程序可以以不同的方式使用切线空间,因此网格的普通烘焙贴图不一定对所有应用程序都是相同的。即使对于使用相同切线空间的应用程序!

了解你的敌人


因明显错误而发动政变


最常见的错误是“ OpenGL vs Direct3D”问题。它们也称为法线贴图Y +和Y-。我将它们包括在这里只是为了完整性。最有可能的是,大多数遇到此问题的人都已经知道了,或者至少学会了解决方法。由于法线贴图是在一个方向上生成的,因此它们对于在设计为使用另一个方向的应用程序中基本上是无用的。


在Unity引擎中,Direct3D方向的法线贴图预期为OpenGL方向,

这可以通过以下事实来理解:照明似乎是从另一侧倒置或掉落的,但仅在某些照明方向上。在您移动光源之前,某些角或面可能看起来完全正常。

有了这个问题,一切就足够清楚了。大多数普通的地图烘焙应用程序都有一个不错的大按钮或菜单,可在OpenGL / Direct3D或Y方向选项之间进行切换,找出目标应用程序使用的方向并在其中烘焙地图。Unity使用OpenGL和Y +。虚幻引擎使用Direct3D和Y-。通过查看法线贴图本身的纹理可以清楚地理解这一点。如果似乎在绿色通道中它们是“从上方”点亮的,则这是OpenGL的方向。如果从下面开始,则为Direct3D。

sRGB的奇数


另一个常见的错误是使用标记为sRGB纹理的纹理。这改变了GPU纹理的采样方式,迫使其将人们通常从中选择颜色值的sRGB空间中的颜色值转换为线性颜色空间。对于法线贴图,这不是必需的。如果您在Unity中将纹理的类型设置为“普通贴图”,引擎将自动禁用此选项,但是您也可以手动禁用“ sRGB(彩色纹理)”选项,并且该纹理将用作普通贴图。至少在Unity 2017.1及更高版本中。


启用了默认纹理类型和sRGB的法线贴图,

此问题可以通过以下事实来识别:法线贴图在一个方向上强烈偏斜。在此模型中,几乎每个人的脸看起来都像是朝向光源。显然,并非总是如此。在更详细的法线贴图中,所有零件几乎都能正确响应照明,但会稍微偏移一些角度。有时看起来好像整个网格表面都变形了。

与正常情况差异太大


另一个常见的问题是游戏资产中使用了不同的普通烘烤网格。与切线一样,要使一切正常工作,它们必须完全匹配。如果美术师导出的顶点法线不正确,则经常会发生此错误。在这种情况下,任何打开网格的应用程序都必须自己计算。没有正确的方法来解决它,这完全取决于网格,因此请确保您(或艺术家)使用最终法线导出模型!


在平滑网格上烘焙的法线贴图,显示为在具有锐利边缘的网格上


在具有锐利边缘的网格上烘焙的法线贴图,在平滑网格上显示为

这是另一个容易发现的问题。如果模型看起来像具有尖锐的边缘,但是阴影从这些边缘弯曲,则意味着您使用平滑的法线烘焙了法线贴图,但是将它们渲染在具有尖锐边缘的网格上。如果阴影向边缘弯曲,则表示该地图以锐利的边缘烘焙并呈现为平滑的边缘。实际上,在一个模型中,两种情况都可能出现,因为可以指示单个边缘的平滑度或清晰度,甚至可以指示平滑度。但是实际上,如果您让另一个应用程序猜测应该是什么样的话,它们肯定会是错误的。上面介绍的模型是一个极端情况,通常情况并非如此,因为模型的大部分看起来可能完全正常。但是在一般情况下如果您有几个看起来特别奇怪的边缘,则可能是由于顶点法线不匹配。

MikkTSpace与Autodesk


一个不太明显的问题是,当烘焙3ds Max或Maya法线贴图时,它们在Unity引擎中总是不正确的。在虚幻引擎以及几乎所有其他程序中,它们都是错误的,除了烘焙程序之外。3ds Max法线贴图在Maya中不起作用,反之亦然!这些应用程序中的每一个都以自己独特的方式计算切线空间,这与其他应用程序不对应。当单独使用它们时,它们看起来很完美,如果您生成在这些程序中使用的法线贴图,则尝试在其中烘焙法线贴图。几乎没有其他程序能够为这些应用程序烘焙正确的法线贴图,因此您似乎别无选择。

在这种情况下,唯一的解决方案是如果要在其他地方使用它们,则不要使用这些应用程序烘焙法线贴图。如果需要免费程序,请使用xNormal这是行业标准工具。如果您在内容创建管道中的某处使用Substance,请使用它。


3ds Max制作了Unity使用的法线贴图。

最容易注意到此问题的方法是,查看平面的凹痕或曲率较小。在某些情况下,这可能非常不起眼,尤其是在有机物体中。因此,这类问题经常不被注意。

许多非Autodesk应用程序已切换到称为MikkTSpace的切线空间计算方法xNormal和Substance以及Blender,Unity,Unreal,Godot,Marmoset,Houdini,Modo和其他一些默认情况下都使用MikkTSpace或至少以某种方式支持它,这极大地提高了它们的兼容性。实际上,在过去的十年中,使用切线空间的法线贴图在所有情况下实际上已成为行业标准。大概在某个时候,3ds Max将添加其支持,但尚不清楚开发人员是否计划允许使用MikkTSpace烘焙法线贴图,还是仅在其帮助下提供查看/渲染支持。

导出网格物体和物质画家


3ds Max和Maya的另一个问题是从它们导出网格时,存在带有“切线和双法线”的导出选项。它们不会出现在MikkTSpace的实际切线中,但会基于它们。某些应用程序会强制对正确的MikkTSpace进行默认的重新计算(例如xNormal,Unity和Unreal),而其他应用程序将“按原样”使用切线网格(如果有)并仅当网格不具有切线时才计算MikkTSpace。例如,Substance Painter如果使用切线网格,则它们会按原样使用,也就是说,Painter创建的法线贴图与烘焙的3ds Max非常相似!相似但不完全相同,因此,如果将它们重新导入3ds Max,它们的外观将不如在Max中烘焙的那样好。

MikkTSpace vs MikkTSpace?


下一个问题是MikkTSpace有多个版本!是的,如果以某种方式不会引起混淆,那将不是标准MikkTSpace决定如何将数据存储在每个顶点的网格中,以及如何将数据用于渲染。所有启用了MikkTSpace的应用程序都会为顶点计算相同的网格数据。但是有两种不同的方法可以在渲染中使用此数据。MikkTSpace定义了如何基于UV方向计算每个顶点的切向量和符号。但是,当使用切线空间时,将为每个顶点或每个像素重新计算两个点的切线(切线)。对于烘焙和查看,此参数也应该相同。

xNormal和Substance可以选择使用两种方法烘焙法线贴图。这些选项在Substance中称为“每个片段计算切线空间”,在xNormal中称为“在像素着色器中计算双法线”。如果要烘焙内置的Unity渲染方法,则无需使用它。但是,根据您选择的类型,对于SRP 可能值得这样做!


带有内置前向渲染器Unity的XNormal“像素着色器双法线”

看起来像在使用完全不同的切线空间,但通常音色要差得多。有些面孔看起来好像法线有些变形,并且不会有很大的凹痕。这里的解决方案非常简单-如果要烘焙Unity的内置渲染方法,请不要选择此选项。如果您为HDRP烘焙Unreal或Unity引擎,请选中该框。

许多消息来源说Blender和Unity是相同的,但实际上这从来都不是真的! Blender和Unity一样,使用MikkTSpace和OpenGL方向,但像Unreal一样,对每个片段二项式使​​用双正态。

好消息是,现在LWRP,URP和Shader Graph着色器为每个顶点使用双法线,并且为每个像素使用内置的HDRP着色器。在以后的Shader Graph(7.2.0)更新中,将执行向逐像素计算的过渡,并且一段时间后,内置的URP着色器也将切换到该模型。如果选择这样的路线,则可以使用自己的着色器更改标准渲染方法。

三角剖分,三角剖分!


最后一个问题是三角剖分的不同方法。如果导出的网格没有初步三角剖分,则无法保证其他应用程序也会以相同方式三角剖分模型。这也会损害法线贴图!因此,可以使用导出选项或通过“三角剖分”修改器对网格进行三角剖分。


Substance Painter , Unity , 3ds Max (quads)

这似乎与完全错误的切线空间非常相似,就好像法线贴图是在3ds Max中烘焙的一样。但是在一般情况下,它们稍微锋利一些,几乎弯曲,看起来不像光滑的凹面。在此网格中,在外表面上可以看到X形。当几个人在不同应用程序的内容生产管道中使用该模型时,此问题可能会很困难且令人讨厌,因为不对网格划分三角并保存漂亮的多边形通常很有用。在这种情况下,您必须适应不便,或者在将模型导出到游戏中(也用于生成用于烘焙法线的网格)之前,制作管道中的最后一个工具。就像带有顶点法线的切线空间(属于切线空间),三角剖分也必须完全匹配。

用于为Unity创建完美的法线贴图的列表


因此,以下是从Unity中使用的原始highpoly模型生成lowpoly网格的切线空间法线贴图的技巧:

  • 无需使用3ds Max,Maya或其他没有切线选项MikkTSpace的其他应用程序烘焙法线贴图
  • 导出网格为三角形,与法线,并没有切线。
  • 烘焙时(以及为Substance Painter创建项目时),请选择OpenGL或X + Y + Z +作为法线贴图的方向。
  • 烘焙内置渲染方法(主动或延迟)或LWRP时,无需启用“每个像素 ” /“每个片段两个点的切线选项
  • 烘焙HDRP时包括与两个 “每个像素” / “每个片段”点的切线的选项,而对URP很快。
  • 保留默认的Unity模型导入选项,法线设置为“导入”,切线设置为“计算Mikktspace”。

就这样!每次您获得完美的法线贴图!


万岁!完美的法线图!


...与思考?咳咳..

好了,最后一个,我们就忽略它。压缩纹理格式(每通道8位)尽可能“完美”。抖动的法线贴图看起来可能比条纹好一点,但不幸的是,没有多少工具提供此选项。否则,您可以使用16位法线贴图。但这是另一篇文章的主题。

了解有关MikkTSpace的更多信息。


mikktspace.com 的半官方网站很好地解释了MikkTSpace的主要优势。尤其是,此空间既适用于计数又可用于在具有不同网格处理的程序之间传输切线数据,同时又保持结果的完整性。该站点文本是Morten S. Mikkelsen自己写的Blender Wiki页面的副本。不幸的是,它仅提及每个像素的切线到两个点的版本,但没有提及每个顶点的版本,这是Unity和xNormal的默认值。由于Blender使用每像素切线的导数,因此仅提及它们是合乎逻辑的。

以下是原始mikktspace.h文件中有关这两个选项的注释

, /.

bitangent = fSign * cross(vN, tangent);



(/ ) , .

, , , «» , : vT, vB vN.

( )

vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );

vNt — . «» , , .



, , , .

因此,在原始示例中,两个点的切线在顶点着色器中重新创建,并作为另一个内插值传递到像素着色器。这就是法线Unity着色器当前处理法线贴图的方式。在像素着色器中执行此任务的示例更多是即兴的,而不是“主要”示例。另外,由于Unity 5.3(和xN​​ormal?)的实现是由Morten S. Mikkelsen自己创建的,并且都对每个顶点使用切线,因此这是我们理论的又一证明。但是随后Blender使用了逐像素切线,Morten也参与其中。实际上,可能这只是一个选项,在完成的Unity着色器中造成了很小的变化,而对于实时图形,没有一种方法被认为比其他方法要好得多。

逐像素实现的优点是消除了两个插值,但代价是ALU(像素着色器数学)需要一点额外的成本。这意味着代替Vector3的三个值(切线,两个点的切线和法线),我们只需要Vector4和Vector3(带正负号的切线和法线)。在现代GPU上,这稍微快一点。而且它在CPU中执行时肯定更快,因为它可用于非实时渲染器。从这个角度来看,逻辑上大多数行业决定在像素中而不是在顶部创建两个点的切线。

有趣的是,当我写这篇文章时,Morten促进了Unity SRP过渡到逐点切线到两点!不幸的是,Unity的内置渲染方法留下了很多不便的选择。



不同应用中的切线空间


尽管本文主要侧重于Unity,但自从今天以来,该引擎已成为主流,但我希望我的研究更加详细。因此,我创建了各种应用程序的列表,其中包含有关切线空间使用的信息。

团结(5.3+)


方向: OpenGL Y +
切线空间: MikkTSpace
计算 MikkTSpace 到两个点的切线:用于顶点或像素*

注意:默认情况下,引擎在导入时强制重新定义网格的切线以使用MikkTSpace。对于高级用户,它具有使用切线网格的选项,但这不能保证与其他工具中烘焙的法线贴图兼容,尤其是在使用内置着色器时。可以使用完全自己的着色器替换它们。对于其内置的着色器,HDRP使用逐像素切线到两个点。在撰写本文时,已计划将URP和Shader Graph着色器也切换到两个点的逐像素切线。在Unity 5.3之前,引擎使用Lengyel切线,仍可以通过在网格导入器中选择“ Legacy Tangents”选项来使用,但是内置着色器不再支持该切线空间。

另外:在URP 7.2.0之前,Shader Graph中法线贴图的处理已完全中断!MikkTSpace或Lengyel切线空间均未正确使用,并且无法在“着色器图”中修复此问题。如果可能,请升级到7.2.0。

虚幻引擎4


方向: Direct3D Y-
切线空间: MikkTSpace MikkTSpace
的切线到两个点的计算:逐像素
注意:默认情况下,当使用MikkTSpace导入时,引擎会重新定义网格的切线。对于高级用户,它具有使用切线网格的选项,但这不能保证与其他工具中烘焙的法线贴图兼容。

戈多


方向: OpenGL Y +
切线空间: MikkTSpace
MikkTSpace 计算到两个点的切线:对于每个顶点
注意:如果没有切线数据,则可以在导入时在MikkTSpace中计算切线网格。引擎文档建议导出切线网格,但是由于大多数工具都无法导出正确的切线网格,因此我将忽略此技巧。即使您使用原始切线网格,也无法保证法线贴图看起来正确。

游戏画布


方向: OpenGL Y +
切线空间: Lengyel / Schüler *
计算到两点的切线:对于每个顶点/基于导数
注意:提供了几种处理切线空间的方法。代码生成的切线不使用MikkTSpace。它具有为每个顶点使用两个点的切线的选项,这些选项可以对“ fastTbn”像素着色器中的切线空间向量进行规范化,而无需对片段着色器中切线空间进行规范化(我们需要,因为这与MikkTSpace的实现相对应,并为每个顶点进行了计算),或者它们使用了从Christian Schuler借来的基于导数的TBN 它会完全忽略网格的切线,并计算像素着色器中的切线空间。现在,默认情况下,将使用基于导数的法线贴图,据我所知,目前尚无用于烘焙精确法线贴图的工具。您可能可以从MikkTSpace导入具有现有法线和切线数据的网格,然后使用“ fastTbn”材质选项来匹配Unity的内置渲染方法,但是我认为这应该在代码中完成,而不是通过编辑器界面完成。

灯丝


方向: OpenGL Y +
切线空间: MikkTSpace MikkTSpace
的切线到两个点的计算:对于每个顶点
注意:根据将来的性能,引擎可能会将像素逐个切线到两个点。

3ds Max


方向: Direct3D Y- *
切线空间:本机
网格物体导出选项:导出启用了Triangulate却关闭了Tangents和Binormals的FBX文件。必须始终导出法线。按顶点分割法线可以保持禁用状态。
注意:默认情况下,3ds Max假定法线贴图使用Direct3D方向,但是在材质上使用法线贴图纹理时,可以选择翻转X和Y方向。烘焙始终使用Direct3D方向。MikkTSpace支持将在以后的版本中出现。

玛雅人


方向: OpenGL Y +
切线空间:本机
网格物体导出选项:在启用Triangulate的情况下导出FBX文件,但在“ Tangents”和“ Binormals”关闭的情况下。法线始终被导出。按顶点分割法线可以保持禁用状态。
注意:有人告诉我Maya已经部分支持MikkTSpace,但我不知道在多大程度上支持。

搅拌器(2.57+)


方向: OpenGL Y +
切线空间: MikkTSpace
计算 MikkTSpace 到两个点的切线:对于每个像素网格
导出选项:导出FBX文件,其“ Smoothing”值为“ Normals Only”。如果目标应用程序还使用MikkTSpace(例如Unity或Unreal),则可以在有或没有切线空间的情况下导出。
注意:导出到FBX时,Blender没有三角剖分选项,因此请首先使用“三角剖分”修改器。在Blender中烘焙的法线贴图不能与Unity 100%兼容,但是如果您在第三方应用程序或自定义材质中翻转绿色通道,则它们可以在虚幻引擎中完美运行。

x普通(3.17.5+)


方向:自定义
切线空间: MikkTSpace *
为MikkTSpace计算到两个点的切线:自定义(每个顶点或像素)
烘焙法线贴图的选项:具有在导出过程中翻转法线贴图的所有三个轴的选项。 Unity需要X + Y + Z +。还可以选择对每个顶点或像素(即片段)使用切线到两个点。默认情况下,xNormal对每个顶点使用切线到两个点,但是可以在“插件管理器”菜单(左下角的电源插头图标)中进行更改,方法是单击“切线基础计算器”,“ Mikk-TSpace”并单击“配置”。将出现一个带有唯一选项“在像素着色器中计算双法线”的弹出窗口。必须为Unity关闭它,为Unreal打开它。
笔记:尽管xNormal仅支持MikkTSpace,但其插件系统理论上支持任何切线空间。到目前为止,我知道的唯一切线空间插件旨在烘焙Unity 4切线空间,并且已经无用。也就是说,如果切实可行,该应用程序仅支持MikkTSpace。

物质画家


方向:可自定义(OpenGL或Direct3D)
切线空间: MikkTSpace
计算 MikkTSpace 到两个点的切线:可自定义(用于顶点或像素)
法线贴图的烘焙选项:在OpenGL或Direct3D方向上具有烘焙选项。以及为每个顶点或像素(片段)使用到两个点的切线的选项,该选项由“计算每个片段的切线空间”参数配置。导出内置Unity渲染方法时,需要选择OpenGL并在项目和导出选项中禁用每个片段的“计算切线空间”,导出到Unreal或Unity HDRP时,请执行相反的操作。
笔记:默认情况下,Substance Painter使用导入的网格所使用的切线数据。除非从Blender导出,否则不需要它!但是没有禁用此功能的选项。在导入到Substance Painter中之前,请导出不包含切线的网格在Substance文档的较早版本中,错误地声称
Blender中两个点的切线的计算对应于Unity,但是现在该错误已得到解决!

mo猴工具袋3


方向:自定义
切线空间:自定义
MikkTSpace的两个点的切线计算:逐像素
注意:该程序似乎具有在几乎任何现有配置中查看或烘焙法线贴图的选项。包括3ds Max和Maya切线空间的现成设置!但是,切线空间选项“ Mikk / xNormal”使用逐个像素的切线到两个点,并且无法更改。也就是说,Marmoset Toolbag 3无法为内置的Unity渲染方法正确查看或烘焙法线贴图。也许在将来的版本中情况会改变,因为开发人员已经意识到了问题所在。

3DCoat


方向:自定义
切线空间:自定义
MikkTSpace的切线到两点的计算
注意:它具有许多查看和烘焙法线贴图的选项。它完全能够匹配Blender和UE4,因此它支持到两个点的逐像素切线,但是我不知道Unity预设中是否使用了到两个点的顶点切线。

胡迪尼(16.0.514+)


方向:可自定义的
切线空间:可自定义*
计算MikkTSpace的切线至两点:逐像素
注意:支持切线或MikkTSpace自身的切线基础,用于查看和烘焙,但仅在逐像素版本中。似乎默认情况下,它不使用MikkTSpace进行渲染,而是从Houdini 17.5开始。可以使用内置节点修改网格以使用切线MikkTSpace。

莫多(10岁以上?)


方向:自定义
切线空间:自定义
MikkTSpace的两点切线的计算:自定义(顶点或逐像素)*
注意:它看起来像支持在不同的切线空间中进行渲染和烘焙,以及将逐像素切线选择为两个点以进行导出的选项。我还没有测试。

纳尔德


方向:自定义
切线空间: MikkTSpace
计算 MikkTSpace 的两个点的切线:逐像素
注意:默认情况下,使用MikkTSpace并重新定义导入的网格的切线,但是如果需要,可以选择使用现有的切线网格。可以使用适用于整个项目的参数来翻转法线贴图的方向。



最后


一个重要方面是,如果要烘焙的低多边形模型只是一个平面(例如,用于平铺纹理),那么编写的所有内容都是无关紧要的,并且可以使用任何工具进行烘焙...如果只是将所有内容保持正确的方向或稍后翻转相应的纹理通道。

此外,本文中列出的大多数问题仅在实体模型上才可见。有机形式可以隐藏最细微的差异,例如,顶点与逐点切线到两个点之间的差异。

Source: https://habr.com/ru/post/undefined/


All Articles