大多数情况下,Nanite能很好地随屏幕分辨率的变化而变化。 能这样做是基于两项关键技术:精细的细节级别和遮挡剔除。 通常这意味着,无论场景中源数据的几何复杂度如何,Nanite实际试图绘制到屏幕上的三角形数量始终与像素数量成正比。
Nanite遵循的设计理念是,三角形的绘制数量超过像素数量就是一种浪费。
某些情况下,有些类型的内容会破坏Nanite采用的缩放技术,但这不意味着完全不应将Nanite用于这些内容,也不意味着它的渲染速度会慢于传统管线。 对于这类内容,这只是意味着基于像素缩放而非基于场景复杂度缩放不再适用于它们。 使用虚幻引擎的分析功能监控这类情况的发生。
聚合几何体
聚合几何体是指有许多不连接的部分,但在远处成为一个完整体积的几何体,如头发、树上的叶子和草。 这类几何体会影响Nanite的细节级别和遮挡剔除机制。 Nanite本质上是一种分层的细节结构,它依赖于能够将小三角简化为大三角,并在确定差异小于可感知的情况下选择较粗略的三角。 对于连续的表面来说,这个方法很好用,但对于从远处看更像部分不透明的云而不是实体表面的聚合几何体,就不太适用。 因此,Nanite更有可能判定不能像对待典型实心表面一样大幅简化聚合几何体,从而导致在覆盖相同像素数量的情况下,绘制更多三角形。
另一个聚合几何体的优化方法是遮挡剔除(Occlusion Culling)。 虽然它非常精细,但它的颗粒度并未细致到每个像素。 布满孔洞的几何体—更糟糕的是,多层布满孔洞的几何体—会导致严重的过度绘制,因为在屏幕上的那个区域被挡住之前,需要建立许多深度层。 思考这个问题的一个方法是想象屏幕上一个8x8像素的区域,以及在每个像素被填充之前需要绘制多少深度层。 严重的过度绘制意味着对于相同的像素覆盖数量,Nanite试图绘制更多的三角,导致它的渲染速度变慢。
植被是导致遮挡剔除问题的最明显的情况,但即使如此,也并不意味着Nanite完全不能应用于植被类型的网格体。 详情请参阅下文的使用Nanite的植被小节。 对不同的用例进行试验是很好的方法,可以了解什么方法对你的项目最奏效。 使用分析工具可以确保Nanite在这些类型的网格体中发挥良好性能。
紧密堆叠的表面
由于各种实际存在的限制,传统网格体的遮挡剔除使得大规模的模型搭建(kitbashing)流程几乎不可能实现。 Nanite的高精细遮挡剔除可以实现使用这些类型的工作流,有助于减少开发流程中的麻烦。 正如上述"聚合几何体"小节中介绍的,导致过度绘制的一种情况是,可见表面与底部隐藏表面的距离过于接近。 如果某个几何体妥当地隐藏在可见表面之下,Nanite检测并剔除它的成本是相当低的,甚至可以认为没有开销。 然而,如果有一些相互堆叠的几何体,并且都位于最顶部的表面上,Nanite可能无法确定哪个位于上面或下面,导致两个几何体同时被绘制出来。
这种剔除问题属于最糟糕的情形,因为Nanite不知道哪个表面在最上面,而是直接绘制所有层。 像这样的精度误差会随着屏幕尺寸和距离的变化而变化,所以,尽管10厘米的距离足够分开各个层,并且在近处看起来很好,但在更远的位置,距离差可能会小于一个像素,从而导致过度绘制。
在下面的示例中,如果将摄像机移动到俯视角色站立区域的位置,Nanite的过度绘制(Overdraw)可视化将展示这些堆叠表面是如何渲染的。 区域越亮,表明在该区域发生的过度绘制越多。
过度绘制视图能够最有效地发现过度绘制的问题。 虽然一定程度的过度绘制属于正常现象,但过度的过度绘制将导致Nanite的剔除和光栅化开销增加,并且Nanite的缩放功能也会更加容易受到场景复杂度的影响。
面片法线和硬边法线
导入具有面片法线的高细节网格体时要格外注意,这意味着两个不同多边形之间的法线未进行平滑。 这个问题很常见,但是容易被忽略,要注意避免。因为网格体中共享的顶点太少,可能会显著增加渲染开销和数据大小。 理想情况下,一个网格体的顶点数量要少于三角形数量。 如果这个比例是2:1或更高,那就可能出现问题,尤其是当三角形数量较多时。 如果比例为3:1,意味着网格体完全是面状的,每个三角形都有单独的三个顶点,没有一个顶点是和其他三角形共享的。 大多数情况下,这是法线不一样导致的,因为法线不平滑。
考虑到这一点,顶点越多,意味着数据越多。 这也意味着顶点变换工作更多,而比率高于2:1时会陷入一些缓慢的渲染路径。 在硬表面建模中专门使用不会引起任何问题,没有不用的理由。 然而,若意外遇到100%面片极密集的网格体,开销要比预期的高得多。 另一个需要注意的问题是,导入在其他DCC软件包生成的密集有机型表面上的法线,这些法线的硬法线阈值在低模网格体上可能是合理的,但在Nanite中会增加不必要的开销。
以下面的两个网格体为例,左边的网格体有面片法线,右边的网格体有平滑法线。 通过Nanite的三角形(Triangles)可视化对比可以看出,Nanite绘制它们时使用的三角形数量存在明显差异。 相比右边的平滑法线,左边的面片法线绘制的三角形要多得多。
Nanite骨骼网格体
Nanite骨骼网格体支持:
新的骨骼网格体API,简化骨骼网格体的渲染。
一次绘制调用即可处理整个网格体。
虚拟阴影贴图的投影。
无几何LOD;Nanite骨骼网格体使用动画LOD。
通过动画库进行实例化。
为植被使用Nanite
为植被使用Nanite的功能还在测试阶段,我们正在对此进行积极的研究和开发。 本节旨在提供植被几何体配合Nanite使用的相关指南,而非Nanite植被功能集。
对于树木这类具有默认Nanite设置的资产,你可能会发现,树冠往往会随着距离的增加而变得稀疏。 这是聚合几何体的一种特殊形式,所有不连贯部分(叶子或草叶)的边界处都有开放边缘。 在启用Nanite时,启用保留区域(Preserve Area)有助于防止出现这种稀疏化现象。 当Nanite通过减少三角形的数量来简化远处的几何体时,最终还是会开始彻底移除一部分不连贯的元素。 如果Nanite没有获得更多信息,就会产生稀疏化的结果,因为失去了大块表面区域。 保留区域(Preserve Area)将外扩开放边界边缘,将失去的区域重新分配给其余三角形。 扩张对称形状(比如树叶)与放大对称形状的效果相同。 如果是条带等非对称形状,例如草叶,效果是将其加厚。
建议为所有植被网格体启用保留区域,但不建议对非场景植被网格体使用该选项。
Nanite簇(Cluster)可视化视图能更清晰地展示保留区域设置对失去区域的重新分配。
以下是在使用和创作植被资产时考虑使用Nanite的一些建议。 我们仍在通过自我试验和学习寻找最好的方法。 到目前为止,我们了解到,使用Nanite的植被应该采用不同以往的创作方式,但如果你能够发挥它的优势,就可以利用Nanite更快获得更高质量的结果。
使用保留区域(在静态网格体编辑器中启用)。
使用几何体替代遮罩卡片。
与不透明(Opaque)材质相比,遮罩(Masked)材质的开销相当大。 完全不使用它们或许可以最快地获得结果。
在采用传统卡片方法(用一张卡片表示许多元素)时,使用Nanite可能比不使用Nanite速度更慢。 不要指望在基于卡片的植被上启用Nanite总能获得性能提升。
遮罩像素的开销几乎与绘制像素相同。
事实证明,几何体植被在使用Nanite时比使用卡片方法速度更快,无论使用的是Nanite卡片还是非Nanite卡片。 此外,外观效果也更好。
Fab上的Megascans:Grass包提供了很好的测试示例。 该包既提供了各元素彼此独立的遮罩和高精度几何体,也提供了用单张卡片表示许多元素的遮罩低精度卡片。
使用世界位置偏移(WPO)时,顶点越多意味着开销越大。 必须限制和监控WPO逻辑。
本页面聚合几何体一节中所述的问题仍然存在。 相比于将所有网格体替换为三角形数量相同的实心形状的相同场景,茂密森林(如上面的示例)的渲染速度要慢得多。
使用Nanite的最大世界位置偏移位移
在材质和材质实例中,你可以通过最大世界位置偏移位移(Max World Position Offset Displacement)来设置WPO允许的偏移量上限。 由于Nanite网格会被分割成更小的簇,且每个簇群都有自己单独的边界,并在GPU上被单独剔除,所以这将会特别有效。 限制WPO是管理这个问题的好方法。
你可以在材质的细节(Details) > 世界位置偏移(World Position Offset)类别,或者在材质实例的材质属性重载(Material Property Overrides)中,找到最大世界位置偏移位移设置。
详情请参阅材质属性。
Nanite静态位移贴图
该Nanite功能目前还在实验阶段。
静态网格体编辑器中有个选项,可以通过使用离线自适应细分器为启用Nanite的网格体增加细节。 细分器使用已烘焙的位移图生成一个经优化的Nanite网格体。 这种纹理驱动方式具有非破坏性,还支持通过标量参数来控制细分曲面和置换的程度。
在Nanite设置下的细节(Details)面板中,按照以下步骤操作:
将修剪相对误差(Trim Relative Error)的值设为非零值,以控制细分曲面的程度。
合适的默认值是0.04,而你应该保持它在0.02以上。 这个值针对的是对网格体进行曲面细分时的误差等级。 数值太小会简单地使用大量的三角,使编译时间爆炸式增长。
添加置换贴图。
展开索引(Index)元素,添加一个用于置换的纹理。
如果你的网格体有多个材质插槽,则每个位移贴图的索引都会被映射到相应的材质插槽。 例如,材质插槽0映射到置换贴图索引0,材质插槽1映射到索引1,以此类推。
设置量级(Magnitude)以控制置换的程度。
点击“应用更改(Apply Changes)”。
Nanite曲面细分
该Nanite功能目前还在实验阶段。
Nanite曲面细分是一种动态可编程置换技术,可在运行时使用置换贴图或程序化材质修改Nanite网格体。 使用世界位置偏移时,只能在原始网格体顶点上操作,而Nanite置换与之不同,它在运行时会将网格体细分为更多三角形,以符合置换贴图的细节。 仅生成当前像素密度所需的三角形细节量。
Nanite曲面细分的优点包括:
在编辑管线中使用包含更少细节的源网格体。
依靠材质驱动并制作动画的置换。
创建精细的Nanite地形。
要启用Nanite曲面细分,需在ConsoleVariables.ini或项目的.ini配置文件中设置以下控制台变量:
// This is read-only and must be set in the config file for the project.
r.Nanite.AllowTessellation=1
// This can be dynamically toggled at runtime.
r.Nanite.Tessellation=1
设置好这些变量后,即可按以下步骤,使用材质编辑器设置曲面细分:
选择主材质节点。
在Nanite设置的细节面板中,勾选启用曲面细分(Enable Tessellation)复选框。
将一个Texture Sample节点连接到主材质节点的置换(Displacement)输入。
置换输入的数值范围为0-1。
在材质中使用曲面细分时,有两个设置可以配置:
量级(Magnitude):置换的高度,由置换引脚的0-1范围映射的最小值到最大值衡量。 它也规定了用于剔除的边界,因此请只将其设置为需要的大小。
该值对性能有显著影响,并且可能产生其他意料之外的效果。 如需更多信息,请参阅下文的"注意事项"小节。
中心(Center):指定与基础网格体无变化相对应的置换值。 因此如果以中间灰度为中心,且你希望网格体内外位移相等,请使用0.5。 如果只想往外推,则将其设为0。
此外,在材质中,你还可以通过在细节面板中启用置换淡化(Displacement Fade),优化Nanite曲面细分的效果。 它具有两个设置:
开始淡化大小(像素)(Start Fade Size (Pixels)):开始淡出置换时,最大置换的大小(以屏幕像素为单位)。 该值必须大于“结束淡化大小”的值。
结束淡化大小(像素)(End Fade Size (Pixels)):完成置换过程并禁用置换时,最大置换的大小(以屏幕像素为单位)。 该值必须小于“开始淡化大小”的值。
注意事项:
只对Nanite网格体生效。 非Nanite网格体会忽略曲面细分和位移。在不支持Nanite的情况下同样如此。
与离线渲染器不同,位移不会改变着色。 你需要提供对应的法线贴图或从位移派生物派生法线。 为了保证质量和压缩,我们建议提供额外的法线贴图。
仅限标量位移。 目前不支持向量位移。
位移沿着未规格化的内插顶点法线移动。 目前没有选项可以在着色器中控制置换方向,因为它始终沿法线方向。
位移发生在本地空间内,且发生在任何类型的对象缩放之前。 这意味着材质中指定的位移量级是以网格缩放前的对象空间为单位的。 这通常都符合你的需求,但也可能出现例外。 比如,如果你想将立方体上平铺的砖块纹理放大成一堵墙。 未来,我们可能会添加全局空间的选项来解决这些问题。
只要为地形生成了Nanite,曲面细分和位移就能在地形上运行良好。 需要注意的是,地形生成的网格体附带很大的缩放比例,因此必须为地形材质设置更小的量级,比如缩小64倍。 将来,使用上一条中提到的选项或许可以解决此问题。
务必让量级(Magnitude)的值尽可能小。 另一方面,0-1间的位移输出值都可以随意使用。 请不要将量级设置为100,然后缩小位置输出的值来进行补偿。 这是因为量级值还被用于剔除的边界配接。 如果量级很大,可能会对性能造成严重影响,尤其是在使用虚拟阴影贴图时。
目前无法实现无缝置换。 这意味着UV的接缝、硬边缘法线或任何影响位移且不平滑的顶点属性都会造成缝隙。
曲面细分可以与世界位置偏移(WPO)结合使用。 在此情况下,WPO会在曲面细分前被应用到基础网格体顶点。 位移则和往常一样,在曲面细分后被应用到细分出的三角形。
曲面细分与像素深度偏移(Pixel Depth Offset)不兼容。 如果启用曲面细分,PDO将被忽略。
曲面细分可以与不透明遮罩结合使用,但由于性能原因,遮罩将按照细分出的三角形比率完成,而不是逐像素进行。 大多数情况下都没问题,但不适用于抖色效果,因为该效果需要逐像素完成。
位移贴图的纹理压缩瑕疵可能会比较明显,并呈现锯齿状。 在大部分情况下,使用BC4的纹理压缩设置Alpha都能运行良好。 存储在带有默认/DXT5/BC3的RGBA alpha通道中应该会得到类似的结果。 有时可能会要求完全不压缩,但浮点可能过大。 只要将通道打包,尤其是将高度和法线打包,任何压缩格式都可能出现瑕疵。 当高度图还被用于其他目的时,这可能与以往的经验相反。
位移与基础网格体的平坦三角形成相对关系。 这意味着它不会从曲面(如PN三角形或Catmull-Clark细分曲面)上开始。 曲面细分本身并不能让表面平滑。
Nanite样条线
样条线网格体被用于沿着样条线形状使网格体变形,如地形地貌上的道路和小径。 启用Nanite的网格体默认支持样条线,且可以创建地形样条线和蓝图样条线。
带Nanite网格体(位于前景)和Nanite样条的示例场景。 此场景显示了有光照和Nanite三角形可视化视图。
Nanite样条线网格体可能存在视觉问题。 例如,使用支持Nanite的静态网格体创建样条线网格体时,随着摄像机的远离,样条线网格体的分辨率可能下降。 这是因为Nanite在为此生成较低的细节级别(LOD)时,不会考虑样条线网格体的变形。 因此,在未发生形变的情况下从一定距离内难以察觉的简化,在沿样条曲线拉伸时可能会越来越明显。
要想缓解这个变形问题,可以在静态网格体编辑器的细节面板中找到Nanite设置,修改其中的最大边长系数(Max Edge Length Factor)。 该参数可以强制Nanite保留足够的细节,确保屏幕上的网格体顶点保持预期的间距,防止在低于某个顶点密度阈值时渲染网格体,进而缓解这个问题。
最大边缘长度因子默认为0。 这说明此网格体的边缘长度将不被考虑。 大于0的值表示屏幕空间内任意两个相连顶点间的期望距离。 更准确地说,该距离以最小目标Nanite三角形边缘的倍数表示(由r.Nanite.MaxPixelsPerEdge配置)。
从旧引擎版本升级到Nanite样条
对于使用虚幻引擎5.3或更早版本开发的项目,使用启用Nanite的静态网格体的样条线网格体组件,原本会像渲染普通静态网格体一样渲染从Nanite网格体生成的回退网格体。 由于虚幻引擎5.4及后续版本默认使用Nanite渲染样条线,这些网格体现在将被当做Nanite网格体渲染,这可能会带来视觉上的变化。
要想维持之前的行为,将回退网格体当作样条线网格体渲染,可以将r.SplineMesh.RenderNanite设为0。