|
本文来自Unity Connect博主放牛的星星。
UE5宣传片发布之后,沸腾的不只是技术行业。朋友圈的刷屏,令众多行业外人士一脸懵逼。Nanite宣称可以渲染160亿的三角面,这些对行外人来说似乎有些看不懂,其实对于我们这些行内人也是一样。
在官方没有放出技术细节之前,不少大佬都在猜测背后的实现原理。主要来说,分两个方向,一个是 Mesh Shader的渲染管线,另一个是Geometry Image的技术方案。
关于Mesh Shader,此前的文章大概说了下原理。
(通过文末二维码关注博主查看往期内容)
而有关Geometry Image的方案,知乎上张心欣大佬说的比较详细。
https://zhuanlan.zhihu.com/p/140943267
但这两个方案其实是不冲突的,Geometry Image 可以在 Task Shader 阶段去做。
如果需要破功,就先要了解下Geometry Image这么神秘的专业词汇到底是什么。以下一小部分内容摘自张心欣的知乎文章。
和Texture一样, Geometry Image实质上是一种能够增加物体表面细节的贴图方法, 只不过, 纹理贴图贴的是图案, Geometry Image,贴的是几何。什么叫贴的是几何?
比如像这种, 原来好好一个兔子, 往它身上贴一个高度纹理, 并按照那个高度把顶点拉伸出来, 就出现了新的几何凹凸, 这就是Geometry Image贴图。
我想说不管哪个行业,做实验都要用小兔子。。。
至于Epic宣传的160亿面,是虚的,是不可能全部真实去渲染的。所以他们自己也提到,Nanite的超多面渲染技术叫做虚拟微多边形几何体 。
这么多面的场景可以放入工程,但是绝对不可能全部进入渲染管线里面。
也就是说,他们的技术方案厉害的地方不是在于为什么能支持这么多的多边形渲染,而是如何将这么多的多边形处理成能用Image表达的数据,并且能够在运行时快速的寻找和映射这些数据。
这里已经提过的一个方案叫做,Virtual Texture。这个技术方案知乎的李兵大佬也有详细讲解过。
浅谈Virtual Texture
https://zhuanlan.zhihu.com/p/138484024
主要内容就是将超大纹理分块存储在磁盘上,这部分叫做虚拟纹理,而在内存中有若干个纹理,这些纹理叫做物理纹理。任何时候当游戏视野发生变化的时候,需要根据一些方案或者规则去维护这些物理纹理,不用的剔除掉,用的再从虚拟纹理中加载。
这样的机制不仅仅减少了带宽消耗和内存(显存)消耗,也带来了其他好处,比如有利于合批,不用因为使用不同的Texture而打断合批,这样可以根据需求来组织几何,使得更利于Culling,当然合批的好处是states change 变少。LightMap也可以预计算到一张大的Virtual Texture上,用来合批。
配合SSD的高速硬盘的时候,这些操作并不会特别耗时。
技术方案不可能凭空的诞生,都是逐渐迭代出来的。所以这个方案应该是靠谱的。如果官方公布的方案和大家猜测的不一样,那也没关系,再去学习新知识就好了。(接受理性讨论,不接受嘲讽、抬杠)
知道(猜测)了Nanite的实现之后,我们也可以使用Unity现有的技术尝试去理解,都是Unity2017就已经支持的技术。同样这里要感谢 Jasper 贡献的教程。
我的译制工作已经全部完成,正在Unity官方Connect:放牛的星星上连载,欢迎关注。
接下来我们要使用的组合拳法包括:
一、Unity标准着色器的功能,视差。这是基础渲染教程第二十篇要介绍的内容。
二、曲面细分,OpenGL ES 目标级别4.6及以上可以支持的功能,Unity2017.1即可支持。
三、表面移位,基于曲面细分的具体应用,实现动态调整GPU顶点位置,处理曲面细分之后的阴影,以及剔除不可见细分。
其中,第一步阐述了Geometry Image在Unity上的实现方式,第二步介绍如何动态的生成超多面,第三步则是支持巨量“虚拟”三角面的核心,表现和剔除。
以上的这几个步骤理论上都是可以放入 Mesh Shading管线的Task阶段去完成的。
详细内容
» 视差
由于视角的原因,当我们调整观测点时,观察到的事物的相对位置会发生变化。这种视觉现象称为视差。可能我们平时游戏开发叫透视。比如,在高铁上看窗外的风景,附近的物体看起来很大并且移动迅速,而远处的背景看起来很小并且移动较慢。
游戏开发中常用的一个方式叫法线,它可以帮助我们产生一定程度的立体感和光照计算,比如下面就是一张正常的纹理和它的法线:
当我们只使用正常纹理的时候,Unity里的表现如下:
导入法线之后,会好非常非常多,如下:
法线非常好用也非常重要,但是由于它是向量,只能表示该点的或者面的方向,无法表达高度。就好比一张纸平放在1楼和平放在10楼法线都是一样的。
要真正的能够表达海拔高度,需要另外一个贴图叫做高度贴图。有了这个信息之后,配合法线我们就能准确的进行“伪造”视差效果。
这是一张灰度图,白色表示最高点,黑色表示最低点。因为这张贴图,通常用来做视差效果,所以我们叫它视差贴图而不是高度贴图。
有了高度贴图之后,我们就可以把它和原纹理、法线进行采样,调和计算之后,形成如下效果。
这个技术并不只是这么简单,它涉及了非常多的方面和技术来解决由高度差带来的投影,自阴影和接受投影,光照等等技术内容,这会在我更新到具体章节的时候介绍,因为和主题无关先略过。
到这里的话我们可以想象一下这个方案的极致运用,是不是只要有足够精度和数量的法线贴图,高度贴图就能创建出非常完美的真实场景?当然是在完美处理的光影的情况下。
» 曲面细分
答案当然不是,因为现在这个技术是基于平面的,3A游戏当然不可能只有一个平面。那么接下来要打的第二拳叫曲面细分。
看看心欣的例子,低模的小兔子:
曲面细分后动态生成的小兔子:
曲面细分的原理和我们游戏开发中常用的高模低模类似。只不过我们常用的都是两套资源,先做高模烘法线,光影等信息,然后再朝低模上面贴。
曲面细分则是根据算法动态生成。好处就是我们完全不需要将我们不关心的东西加载进来。如果算法合理,极致情况下,我们可以全部用一个平面来表示,然后根据需要来生成模型和顶点。
这是OpenGL ES的新的渲染管线。在顶点程序之前,还有一个Tessellation的过程。
下面可以看一看这个例子,这是一个普通的正方形,有2个三角面。
通过一些算法(具体算法和代码教程更新到这里的时候都会介绍),我们可以让它变成这样:
这样:
或者是这样:
来个动图看看:
既然我们可以控制细分三角的数量,当然也可以把视距、光照、遮挡等其他因素考虑进来,作为因子共同影响曲面对三角形的细分。比如下面就是根据摄像机距离来控制细分的数量。
那么介绍到这里,曲面细分的这拳打完了,你们可能会说,这不还是平面么?
严格来说这是个招式,为后面的拳法做初始准备。在极致情况下,我们可以用高模的法线贴图、视差贴图、摄像机的相关参数或者其他因素来控制三角面的生成。
背面或者被遮挡的地方,甚至可以完全不用生成。
再来看下心欣的例子:
原理几乎是一致的。只是我们的例子太简陋了。
» 表面移位
接下来就是最后一招了。我们现在已经能够自动生成面数了,但是所有的面和顶点都在一个平面上,就像这只兔子被液压机压成了一张纸一样。
如果我们能根据某些算法或者贴图或者参考将这些顶点移位到合适的位置,是不是就能还原出整个兔子了?
要实现这一个目标,就需要把前面的视差贴图和曲面细分结合使用。视差贴图实际上就是一个置换贴图,前面的动图里我们可以看到它可以用来伪造位移,既然可以伪造,那么当然也可以将相同的贴图用于实际的移位。
我们仍然使用前面的视差贴图:
一般来说把视差贴图按照法线方向移动就没什么问题了。
曲面细分是有基础三角形上做算法计算出来的,理论上算法足够好的时候,生成的三角形和高模的差距不会太大,但是如果算法不够好的情况下,基础三角形的数量会影响曲面生成的质量。越多的基础三角形生成的质量越高。
比如下面两个效果:
在浅视角下看看我们动态生成的效果,要记得这个是根据视差贴图动态生成出来的哦。
好了,到这里三套拳都打完了。当然所有其他不相关的内容都略去了,比如阴影,光照、剔除等等内容,细节实现都会在教程更新的时候,和源码一起给出。
下面给出稍微正式一点的效果,如下:
这里是已经考虑了光照和阴影的效果。
小结
如果目前借助Unity实现Nanite类似的效果,技术上要攻克的是如何将ZBrush或者CAD进行正确的烘焙,以便导出相应的低模,法线、视差贴图、LOD贴图等等。除此之外,还要做一套良好的内存管理和纹理映射,以便能够在运行时快速定位和生成曲面信息。
作者:放牛的星星
来源: Unity官方平台
原地址:https://mp.weixin.qq.com/s/jnOCTpAxUMMHcLGY-FgUgA
|
|