游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

王祢虚幻引擎5的开发路线图及技术解析

  2021年11月22日24日,由腾讯游戏学堂举办的第五届腾讯游戏开发者大会(TencentGameDevelopersConference,简称TGDC)在线上举行。本届大会以FivebyFive为主题,邀请了海内外40多位行业嘉宾,从主论坛、产品、技术、艺术、独立游戏、市场及游戏社会价值7大专场共同探讨游戏产业趋势和多元价值,以开发者视角与需求为出发点,助力游戏行业良性发展,探索游戏的更多可能性。
  大家好,我是来自EpicGames中国的首席引擎开发工程师王祢,主要负责引擎相关技术的开发者支持工作,帮助国内的开发者解决各种使用UE开发项目时遇到的技术问题,同时也会参与部分引擎工作的开发。
  今天我主要为大家介绍UE5的新功能。当然,UE5有太多新功能了,我会挑大家最关心的Nanite和Lumen多讲一些。
  在开发UE5的时候,我们的目标是:提高各方面的渲染品质,让构建的数字世界更动态一些,提高整个虚拟世界构建和表现的上限;同时我们也希望提高开发和迭代的效率,提供更多更丰富易用的工具,改善用户编辑和创造的体验,降低大家使用的门槛。
  相比UE4,UE5做了大量改进,主要是Nanite和Lumen等渲染技术,构建整个大世界的工具以及底层对渲染大量对象生成一些ProxyMesh技术。
  在协同工作方面,改进包括管理大量资产的性能、编辑器和用户体验、次世代的一些动画技术Chaos、网络同步的物理系统,以及一些全新模块、游戏框架、AI集群系统、进一步完善的Niagara系统以及各种音频模块,像MetaSound之类的功能都有非常大的改善。
  Nanite功能
  首先是我们主打功能之一的Nanite,Nanite是全新的Mesh表示形式,是一种虚拟微表面几何体,解放了之前美术同学制作模型时对大量细节的限制,现在可以直接使用真正用于影视级别的资产,几百万甚至上亿面的模型直接可以导入到引擎中,非常顺畅的放很多的实例去高效的渲染。
  例如来自照片建模或者Zbrush雕刻的高模,或者CAD的数据都可以直接放进来,我们有过测试可能几万甚至十几万的,这些实例每个都是百万面以上的都在view内能被看到的情况下,用Nanite的方式渲染依然能在2080s这样的GPU上跑到60fps,分辨率可能是1080P左右。Nanite还在开发中,还有很多功能支持并不完善,我们在后续会慢慢改进。
  Nanite支持的平台主要是新一代的主机和PC,相比去年我们放出来的LumeninthelandofNanite,这项技术的品质和效率都有不少提升,包括磁盘的编解码效率和压缩、支持Lightmap烘焙光照、支持可破碎物体、对光线追踪场景或者物理碰撞支持自动生成减面高质量的替代Proxymesh。
  另外通过这种方式,我们还可以用解析微分法决定像素误差,使误差肉眼不可见。最后,我们还高效支持了多光源投影,整个Nanite管线基于GPUdriven的管线产生,主要流程我会分以下几个部分来讲。
  为了让大量对象在场景上高效剔除,我们需要把所有场景数据都送到GPU上。其实从4。22开始,引擎就慢慢在不影响上层使用的情况下,在底层做出改进了,使渲染器成为retainedmode,维护了完整的GPUscene,Nanite在这个基础上做了大量新的工作。
  Nanite中cluster的生成
  接下来我们简单讲讲Nanite的工作机制。首先在模型导入时,我们会做一些预处理,比如按128面的cluster做切分处理。有了这些cluster以后,我们就可以在距离拉远拉近时,做到对每个clustergroup同时切换,让肉眼看不到切换lod导致的误差没有crack,同时还能对这些不同层级、细节的cluster做streaming,这其实就是Nanite最关键的部分。
  cluster的生成主要分以下几步:首先,原始的meshlod0数据进来后,我们会做一个graphpartition。partition条件是比如说我希望共享的边界尽可能少,这样我在lock边界做减面处理时,减面的质量会更高一些。
  第二是希望这些面积尽可能均匀、大小一致,这样在lod计算误差处理投影到屏幕上时,都是对每个cluster或clustergroup一致处理。我们会把其中一组cluster合并成一个clustergroup,又一次按照lock的边界尽可能少、面积尽可能均匀的条件找出,一组组cluster生成group,对这个group内cluster的边解锁,等于把这组group看成一个大的cluster,然后对这组group做对半的减面。
  减完面后,我们可以得到一个新的cluster误差,我会对这个减面的group重新做cluster划分。这时,cluster的数量在同一个group里其实就已经减半,然后我会计算每个新的cluster误差。大家要注意,这个过程是循环的,递归一直到最终值,对每个instance、模型只生成一个cluster为止。这里有一个比较关键的点:我们在减面生成每个cluster时,会通过减面算法(QEM)得到这个cluster的误差值并存下。
  除此之外,我们还会存group的误差值,这个值其实就是更精细的那一级clustergroup里cluster的最大误差值,和我新一级里产生的每个cluster误差值取maximum得到的值。这样我就能保证这个cluster每次合并的group,去减面到上一级的group里的cluster时的误差值,永远是从不精细到精细慢慢上升的状态。
  也就是说,我从最根结点的cluster慢慢到最细的cluster,里面的error一定是降序排序的。这一点很重要,因为它能保证后续选择culling和lod时,恰好是在一个cluster组成的DAG上。因为cluster会合并group,group生成打散以后在下一级里,又会有一个共享的cluster。
  有了这个降序排列的误差,我就能保证这个DAG上有一刀很干净的cut,使我的边界一定是跨lod的clustergroup的边界。最后,我们对这个生成的各个lod层级的cluster分别生成bvh,再把所有lod的cluster的bvh的root,挂到总的bvhroot上。
  当然,这里还有很多额外处理,现在没有讲是考虑到做streaming时的一些分页处理。这个分页可能会对clustergroup造成切割,所以clustergroup,还有一些grouppartition的概念,我们这里不做细化。
  另外,对于一些微小物体离得很远以后的情况,我们减到最后一级cluster,其实它还是有128个面,那如果场景里非常小的东西位于很远的地方,这又是一个模块化的构成。我们又不能直接把它culling掉,这种情况下,我们会有另外一种Imposteratlas的方式,这里我也不展开讲了。
  Nanite裁剪流程
  最后裁减到它bvh的叶子节点,其实就是我们刚才说的clustergroup,然后再对其中的cluster做裁减。裁减完之后,我们就会有一个特殊的光栅化过程,然后我们就能得到新的DepthBuffer,重新构建HZB,再对这个新的HZB做一遍裁减。
  前面那次HZB的可见性,我们用了上一帧可见的instance来做,做完之后形成新的HZB,我们再把上一帧不可见的,在这一帧内所有剩下的再做一遍,就能保守地保证没有什么问题。
  重新经过光栅化后,生成到新的visibilitybuffer,再从visibilitybuffer经过materialpass,最终合入Gbuffer。具体做culling时会有一些问题,比如刚才cluster生成时我们说到过,生成clustergroup的bvh结构,我们在CPU上不会知道它有多少层。
  也就是说,如果我要去做的话,CPU要发足够多的dispatch,这时比如小一点的物件,它空的dispatch就会很多,这种情况下GPU的利用率也会很低。
  所以我们选择了一种叫persistentculling的方法,利用一个persistentthread去做culling,也就是只做一次dispatch,开足够多的线程,用一个简单的多生产者、多消费者的任务队列来喂满这些线程。
  这些线程从队列里执行时,每个node会在做封层级别剔除的同时产生新的node,也就是bvhnode,Pushback回新的。在可见的children的列表里,我们一直处理这个列表,直到任务为空。
  这里的处理分为几种类型:首先在一开始的node里,只有我们开始构建的bvh的节点,直到我一直做剔除,剔除到叶子节点以后,里面是个clustergroup,再进入下一级,就是这个group里面所有的clusterculling。最后cluster并行独立地判断,自己是否被culling掉,这里其实和刚刚lod选择的条件是一模一样的。
  还记得我刚才说的error的单调性吧?因为这里的cluster中,所有lod都是混合在一起的,所以我们每个cluster在并行处理时,我不知道父级关系是什么样的,但我在每个cluster上存了自己的误差,和我整个group在父一级上的最大误差,所以这时我就知道,如果我自己的误差足够小,但是我Parent的误差不够小,我就不应该被culling掉。
  同理,跟我共处一个clustergroup的这些节点,如果它在我上一级lod里,也就是比较粗的那一级里,那它的error一定不够大,所以上面那一级lod所在的整个group都会被抛弃掉,而选中下一个。
  但是下一个里面,其实还是可能会有一些误差太大的它的误差如果足够大,就意味着它在再下一级更精细的地方,肯定属于另外一个clustergroup。所以它又在下一级的clustergroup里又有一个边界,和它下一级的clustergroup边界接起来会没有接缝,整个cluster的选择就是这样并行做的。
  同时,对应自己clustergroup的parent,刚刚我们说了,肯定会被剔除掉。这样就能保证我们能分clustergroup为边界,去对接不同lod层级的cluster,并使经过culling存活下来的cluster来到特殊的光栅化阶段。
  Nanite中的光栅化
  由于当前图形硬件假设了pixelshadingrate,肯定是高于triangle的,所以普通硬件光栅化处理器在处理非常的微小表面时,光栅化效率会很差,完整并行也只能一个时钟周期处理4个triangle,因为2x2像素的会有很多quadoverdraw,所以我们选择使用自己用computeshader实现的软件光栅化,输出的结果就是VisibilityBuffer。
  我这里列出的结构总共是64位的,所以我需要atomic64的支持,利用interlockedmaximum的实现来做模拟深度排序。所以我最高的30位存了depth、instanceID、triangleID。因为每个cluster128个面,所以triangleID只要7位,我们现在其实整个opaque的Nanitepass,一个draw就能画完生成到visibilityBuffer,后续的材质pass会根据数量,为每种材质分配一个draw,输出到Gbuffer,然后像素大小的三角面就会经过我们的软件光栅化。
  我们以cluster为单位来计算,比如我当前这个cluster覆盖屏幕多大范围,来估算我接下来这个cluster里是要做软件光栅化还是硬件光栅化。我们也利用了一些比如浮点数当定点数的技巧,加速整个扫描线光栅化的效率。
  比如我在subpixelsample的时候是256,我就知道是因为边长是16。亚像素的修正保证了8位小数的精度,这时我们分界使用软光栅的边界,刚好是16边长的三角面片的时候,可以保证整数部分需要4位的精度,在后续计算中最大误差,比如乘法缩放导致小数是8位、整数是4位,就是4。8。
  乘法以后精度缩放到8。16,依然在浮点精度范围内,实际的深度测试是通过Visibilitybuffer高位的30位的深度,利用一些原子化的指令,比如InterlockedMax实现了光栅化。大家感兴趣可以去看看Rasterizer。ush里面有WritePixel去做了,其实我们为了并行地执行软件光栅化和硬件光栅化,最终硬件光栅化也依然是用这个WritePixel去写的。
  Nanite中的材质处理
  有了Visibilitybuffer后,我们实际的材质pass会为每种材质绘制一个drawcall,这里我们在每个cluster用了32位的材质信息去储存,有两种编码方式共享这32位,每个三角面都有自己对应的材质索引,支持最多每个对象有64种材质,所以需要6位去编码。
  普通的编码方式一共有两种,一种是fastpath直接编码,这时只要每个cluster用的材质不超过三种就可以,比如每一种64个材质,我需要用6位来表示索引是第几位,用掉3X618位还剩下14位,刚好每7位分别存第一,和第二种材质索引的三角面片数的范围,因为7位可以存cluster128个面,这是最大范围了。
  前几个面索引用第一种,剩下的范围用第二种,再多出来的就是第三种。当一个cluster超过3种材质时,我们会用一种间接的slowpath,高7位本来存第一种材质,三角面片的范围的那7位,我们现在padding0剩余其中19位存到一个全局的,材质范围表的BufferIndex,还有6位存BufferLength,Slowpath会间接访问全局的GPU上的材质范围表,每个三角面在表里面顺着entry找自己在哪一组范围内。
  这个结构里存有两个8位三角面index开始和结束,6位(64种)材质index,其实这种方式也很快。大家想一下,其实我们大部分材质、模型,就算用满64个材质,我切成小小的cluster以后,128个面里你切了好多section,超过三种材质的可能性其实很低。
  这里可以看到不同的绘制对象,它在MaterialIndex表里面其实顺序是不一样的,我们需要重新统一映射材质ID,也能帮助合并同样材质的shading计算开销。
  在处理Nanite的meshpass时,我们会对每一种materialID做一个screenquad的绘制,这个绘制只写一个材质深度,我们用24位存材质深度可表示几百万种材质,肯定是够了。每一种材质有一个材质深度平面,我们利用屏幕空间的小Tile做instanceddraw,用深度材质的深度平面做depthequal的剔除,来对每种材质实际输出的Gbuffer做无效像素的剔除。
  那为什么要切tile做instanceddraw呢?因为就算用硬件做EarlyZ,做了rejection,也还是会耗一些时间的。所以如果在vs阶段,某个tile里根本没有的材质的话,就能进一步减少开销,具体可以看ExportGbuffer。usf里的FullScreenVS这里的处理。
  Nanite中的串流
  处理完渲染部分,我们来看看串流。因为时间关系,我这里可能要稍微简化一下:因为资源很大,我们希望占用内存是比较固定的,有点类似VT这种概念。但是geometry对比virtualtexture有特殊的challenge。
  还记得之前lod选择的时候我们说过,最终结果刚好是让DAG上有一个干净的Cut,所以如果数据还没进来,这个cut就不对了,我们也不能在clusterculling时加入已有数据信息的判断,只能在runtime去patching这个实际的数据指针。
  所以我们保留了所有用来culling的层级信息,让每个instance加载的时候都在GPU里面,只streaming实际用到的geometry的细节数据。这样做有很多好处在新的对象被看到的一瞬间,我们最低一级的root那一级的cluster还是有的,我们就不用一级一级请求。
  并且我有整个cluster表,所以我可以在一帧中就准确知道,我feedback时实际要用到的那些cluster实际层级的数据。整个层级信息本身是比较小的,在内存里的占用,相对来说不那么可观。
  回忆之前culling的过程可以知道,我们在streaming粒度最小的时候,也是在clustergroup层级的,所以我们的streaming会按照我刚刚说的clustergroup来切配置。因为有些切割的边界最好是在clustergroup的中间,所以我们会有一些partialgroup的概念,在最后让GPU发出请求。
  在哪个clustergroup里,我就发这个group所在的那个page。如果我是partial的切到几个page,我就会同时发这几个page的请求。加载完之后,我会重新在GPU上patch,我刚刚整个culling的算法,条件如果变成了是叶子节点,我刚刚说的误差满足条件里还有一个并行条件是不是叶子节点。
  除了真的lod0的cluster是叶子节点,还有就是我现在没有填充patch完、没有加载进来的时候,内存里最高、最精细的那一级是什么?也是叶子节点,总体概念就是这样的。
  Nanite中的压缩
  实际上,我们在硬盘里利用了通用的压缩,因为大部分的主机硬件都有LZ77这类通用的压缩格式,这种压缩一般都是基于重复字串的indexlength编码,把长字符串和利用率高的字符串利用Huffman编码方式。
  按频度来做优化的,我们其实可以重新调整。比如在我们切成cluster以后,每个cluster的indexbuffer是高度相似的,我们的vertex在cluster的局部位移又很小,所以我们可以做大量的position量化,用normal八面体编码把vertex的所有index排到一起,来帮助重复字符串的编码和压缩。
  其实我们每个三角形就用一个bit,表示我这个index是不是不连续下去要重新开始算,并且另外一个bit表示重新开始算的朝向的是减还是加,这样顶点数据跨culster的去重,做过这样的操作后,我们磁盘上的压缩率是非常非常高的。当然,我们还在探索进一步压缩的可能性。
  Nanite的未来与其他
  由于时间关系,借助Nanite其他的一些feature,尤其是VirtualShadowMap,我们可以高效地通过Nanite去做多个view的渲染,并且带投shadow的光源每个都有16k的shadowmap,自动选择每个texel投到屏幕一个pixel的精度,应该在哪个miplevel里面,并且只渲染屏幕可见像素到shadowmap,效率非常高,具体细节这里就不详细讲了。
  接下来我们看看Nanite未来有什么样的计划:尽管我们目前只支持了比如纯opaque的刚体几何类型,对于微小物体,最后我们还是会用Imposter的方式来画,但是在超过90的情况下,场景中其实都是全静态对象。
  所以目前的Nanite,其实已经能处理复杂场景的渲染,在大部分情况下都能起到非常大的作用。至于那些不支持的情况,我们依然会走传统管线,然后整合起来。当然,这远没有达到我们的目标,我们希望以后能支持几乎所有类型的几何体,让场景里不再有概念,不再需要去区分哪些对象是启用了Nanite的,包括植被、动画、地形、opaque、mask和半透。
  伴随Nanite的研究,我们也希望达成一些新技术,比如核外光线追踪,就是做到让实际raytracing的数据,真的是Nanite已经加载进来的细节层级的数据。当然,离屏的数据可能还是proxymesh。
  另外,因为我们现在已经不支持曲面细分了,所以也希望在Nanite的基础上做微多边形的曲面细分。
  Lumen
  UE5的另一大功能Lumen,是全新的全动态GI和反射系统,支持在大型高细节场景中无限次反弹的漫反射GI,以及间接的高光反射,跨度可以从几公里到几厘米,一些CVar的设置甚至可以到5厘米的精度。
  美术和设计师们可以用Lumen创建更加动态的场景。譬如做实时日夜变化、开关手电筒,甚至是场景变换。比如炸开天花板后,光从洞里射进来,整个光线和场景变化都能实时反馈。所以Lumen改善了烘焙光照带来的大量迭代时间损失,也不需要再处理lightmap的uv,让品质和项目迭代效率都有了很大提升。
  为了跨不同尺度提供高质量GI,Lumen在不同平台上也适用不同的技术组合。但是目前Lumen还有很多功能不足正在改善。我们先来简单了解下Lumen的大框架:为了支持高效追踪,我们除了支持RTX硬件的raytracing,其他情况下我们也用Lumen在GPU上维护了完整的简化场景结构,我们称之为Lumenscene。
  其中部分数据是离线通过mesh烘焙生成一些辅助的信息,包括meshSDF和meshcard,这里的card只标记这个mesh经过grid切分之后,从哪些位置去拍它的一些朝向,和BoundingBox的一些标记。
  利用刚刚这些辅助信息,和Nanite的多view高效光栅化生成Gbuffer,以及后续需要用到的其他数据,运行时会通过两个层面更新LumenScene:一层是CPU上控制新的Instance进来,或者一些合并的streaming的计算;另一层是更新的GPU数据,以及更新LumenScene注入,直接和间接Diffuse光照到光照缓存里面。
  我们会基于当前屏幕空间放一些RadianceProbe,利用比较特殊的手段去做重要度采样。通过高效的Traceprobe得到Probe里面的光照信息,对Probe的光照信息进行编码,生成IrradianceCache做spatialfilter。
  当然,接着还会有一些fallback到global世界空间,最后再FinalGather回来,和全屏幕的bentnormal合成生成,最终全屏幕的间接光照,再在上面做一些temporal滤波。这就是我们Diffuse整个全屏的光照,最后再跟Direct光照合起来,就得到了最终的渲染结果。
  Lumen中的Tracing
  Lumen的整体框架是软件追踪,靠MeshSDF来做快速的RayTracing。在硬件允许时,我们会用RTX,这个今天不展开讲。Lumen的追踪是个Hybrid的方案,包括优先利用HZB做屏幕空间的Trace,如果失败的话,我们在近距离用一个全屏做MeshSDF的Trace,这里因为MeshSDF的instance做遍历效率其实还比较低。
  因为用bvh在GPU上访问时,树形结构的缓存一致性很不好,所以我们只在很近距离1。8米内做第一层级的加速结构,这时我们利用一个简单的Froxel去做grid划分,快速求交所有instance的BoundingSphere和对应cell相交结果,并存在对应cell的列表里,这是全屏做一次的。
  接下来在tracing时,我每次只需要访问当前tracing点,比如marching以后所在的位置,所在的cell就能很快算出来,然后直接查询里面的instance列表,将第二层加速结构实际的,以及查出来列表里instance的SDF,都做一遍marching,取一个minimum值。
  对于稍远一点的,我们会对场景做一个合并生成Global的SDF,它是个clipmap。但因为提高精度以后,数据存储等各方面每翻一倍精度会有8倍增加,我们会有一些稀疏的表达,我之后会简单讲一下。
  在都没有trace到的情况下,我们会循环GlobalSDF的clipmap,对每一级clipmap做loop,直到GlobalSDF。比如二百多米全都没有trace到,那就是miss。当然,我们在之前的Demo里也用了RSM做最后的fallback,现在这个版本我们还没有放进去。
  在SDF生成时,tracing我们都会做一些保守的处理,保证不会有薄墙被穿透。SDF其实是个volumetric,按voxel间隔来采样的生成过程,如果我的面很薄,在你的voxel精度以内,其实我们会有一些保守处理。
  Lumen与场景结构
  随之而来的问题是,我们trace到了某个表面之后,SDF里面没有办法拿到我们实际需要的数据,只能帮助快速找到交点位置,这个时候我们能拿到什么?近场MeshSDF时MeshId是我知道的,因为遍历列表的时候存了;另外我还知道SDF,所以可以靠SDF的gradient算出对应的normal,但是我有ID、normal和位置,要怎样得到我要的Radiance呢?包括Gbuffer的一些数据,这时我们是没有三角面片数据来插值计算的,没有各种材质的属性,所以我们需要一种高效的参数化方法。
  我们使用了一种平铺的CubeMapTree结构:首先在Mesh导入时我们会预先处理,刚刚提到生成一组Card的描述,在runtime的时候,我们对放在地图里的每个实例,会根据mesh的Card信息实际利用Nanite高效光栅化,生成对应的Gbuffer。
  Atlas在一张大的Atlas里面,其实是几张里面存了MRT,存了三张包括albedo,opacity,normal,depth这样的信息。存的这个Atlas我们叫做SurfaceCache,其实就是大家最终看到的LumenScene。当然,LumenScene还会经过SDFtracing,然后做triplanarreprojection,这其实就是我们tracing的结果。
  我们tracing时tracing到哪个位置,就会找到它对应三个方向的Lumencard,把光栅化完的那些信息triplanarreproject出来,得到的就是这个点要的信息。包括Gbuffer、Radiance信息。
  Radiance信息从哪里来呢?是在生成这个card时,还会做直接的光照注入,然后生成它Irradiance的Atlas,并且这个Atlas中会根据维护的budget更新对应的Card,从texel出发,利用GlobalSDF去trace上一帧的lighting状态,也就是上一帧LumenScene的信息。
  所以我们用屏幕空间Probe去trace时,trace到的那个Irradiancecache里的东西,就是多次反弹的结果。这个Atlas里card存的cache,其实都是2的整数次幂,为了方便我们做mip。因为我们有些阶段要用prefilter的mip,利用conetracing快速地做prefiltering结果的tracing。对于更远的Ray,我们其实在trace的时候,就已经借助的GlobalSDF,超过1。8米时,这个时候我们也没有对应的MeshID了。
  所以类似地,在对应生成GlobalSDF的clipmap时,我们也会用SurfaceCache生成一个voxelLightingCache,也就是LumenScene更低精度的voxel的表达。这个voxelScene就是来自CubeMapTree预处理后,radiance合并生成出来的。
  这时我们每一帧都会重新生成voxelLightingCache,整个Lumen的结构是持续存在GPU上的,在CPU上维护对它的增减。我们哪些东西重新Streaming进来了,视角调整以后哪些card变得可见,为了控制开销,我会每帧固定更新一定数量的card,并且根据对应的Lighting类型,对这个Surfacecache做一些裁减。对于那些tracing时不在屏幕中的shadow遮挡,我们都是靠GlobalSDFTrace来做的。
  FinalGather
  有了Tracing的手段,又从中获得了想要的数据的信息后,我们就要解决最终的GI问题了。传统模式中,比如Cards里存的是SurfaceCache,已经有了多次反弹的照度信息,这里我们已经把追踪到的表面缓存不一致的求解计算分离到CardCapture和Card光照计算部分,就只需要在屏幕空间直接来TraceRay,Trace这些SurfaceCache里的Irradiance就可以了。
  传统做RTXGI时,往往只能支撑12spp在Gbuffer发出BentNormal半球空间均匀分布的光线,如果靠SpatialTemporay,方差引导的这种滤波,在光线相对充足的情况下效果会非常好,但是当光线很不充足,譬如只有一束光从门缝或小窗口照进来时,离远一点的地方你Trace出来的Ray能采样到,实际有光源的地方概率太低,导致在滤波前的画面信息实在太少,最终滤波完的品质也是非常差、不能接受的。
  我们的方法,是利用远低于Gbuffer分辨率的ScreenSpace的Probe,约每16个像素,根据实际像素插值失败的情况下,我们在格子里面还会进一步细化放置,放到一个Atlas里,我的每个Probe其实有88个Atlas,小的一个八面体投影的就是半球,自己WorldSpacenormal的半球,均匀分布我的立体角朝向的那个Tracing的方向,每一帧我还会对这个采样点做一些jitter,之后再去插值。
  我们也会在像素平面,将最后全屏每个像素按照BRDF重要度采样,找周围Screen的Probe做跟我方向一致的weight调整,再去做插值,然后在计算probe的时候,我们利用半球投到八面体的方式,存了88的像素全都Atlas到一起,在细化时一直往下放。
  所以最坏的情况,是比如每个像素都是一个前景,下一个像素就是一个后景这其实不太可能,只是极端情况。这种情况我就变成要细化到每个像素,又变成逐像素去做这个tracing的ProbeCache。为了避免这种情况,我们其实是粗暴地限制了整个Atlas的大小,也就是最细化的东西,我填不下就不要了。
  这样的好处是,我按照116的精度去做的ScreenProbe,其实是1256的精度,即使88我处理的像素数还是以前的14或者18,在做SpatialFilter最后每个像素插值时,我只要做ScreenProbe33的filter,其实就相当于以前48x48的filter大小,而且效率很高。并且在求解间接的环境光蒙特卡洛积分时,可以靠上一帧这些ScreenProbe里reproject回来的IncomingRadiance的值,作为lighting的importancesampling的引导。
  同样,BRDF也可以这样做。譬如BRDF值小于0的部分,无论入射光如何都不会贡献出射,随便这个方向上lighting在上一帧的incomingradiance。在这个点上有多少,这个朝向有光过来,我贡献也是0我不需要它,所以我最终就把这两个东西乘到一起,作为我新的这一帧probe的importancesampling的方向。
  最后,我就会根据这个方向去tracing,之后radiance会存到跟它对应起来另外一张88的图里,Atlas到一起。对于小而亮的部分离的表面越远,每帧又有jitter又有方向,引导方向不一样。有时没追踪到,它的噪点就会比较多,并且trace长度越长光线的一致性也不好,所以相反离得远的光源,相对贡献得光照变化频率也比较低。因为我离的很远以后局部光有一些位移,对我这里的影响是很小的。
  所以我们可以用一个世界空间的probe来处理,因为这个时候可以做大量的cache,这里我的世界空间也是一个clipmap,它也是稀疏存储的。因为只有我ScreenSpace的ProbeTracing访问不到的东西,我才会去布置更多的WorldSpace的Probe去做更新处理,这里就不展开讲了。
  最终,我们需要在全分辨率的情况下做积分,这时有一个办法,就是根据全分辨率像素得到BRDF采样,方法就是我刚才说的,从ScreenProbe里面找。比如88像素周围的都去找跟它方向一致的weight去插值,但这样噪点还是很多,所以我们其实是从它的mip里面去预处理,从filter过的结果里去找。
  这样还会有一个问题:我自己朝向的平面,比如88像素周围的都去找跟它方向一致的weight去插值,所以最终我们把八面体的radiance转成了三阶球谐,这样全分辨率的时候能非常高效的利用球谐系数做漫反射积分,这样的结果质量和效率都很好。
  最后的最后我们又做了一次,我对每个像素都做完之后,再做一次temporal的滤波,但是会根据像素追踪到的位置的速度和深度来决定我这个像素的变化,是不是快速移动物体区域投影过来的,来决定我这个temporalfilter的强度。
  我temporalfilter越弱,其实就相当于前面我去采样的时候积分起来的时候,我采样周围33SpatialFilter效果就越强。整体上Lumen的框架就是这样,我略过了大量细节和一些特殊处理的部分。譬如半透明物体的GI没有讲到,Spectular我也没有特殊讲,但是像spectular在粗糙度0。3到1的情况下,和这里importancesampling的diffuse其实是一致的。
  Lumen的未来
  在未来,我们也希望能做进一步改进,比如镜面反射,Glossy反射我们已经能很好处理,但是镜面反射在不用硬件追踪的情况下,现在Lumen效果还是不够的,包括SkeletalMesh的场景表达方式、破碎物体的场景表达方式,以及更好处理非模块化的整个物体。因为现在模块化整体capturedcard或者SDF的各种精度处理,可能还不够完善。
  我们希望提升植被品质,以及更快速地支持光照变化,因为我们有很多hardlimiter的更新,比如card数量之类的,会导致你过快更新时跟不上。最后,我们还希望能支持更大的世界,譬如可以串流SDF数据,以及做GPUdriven的SurfaceCache。关于Lumen我们今天就先讲到这里。
  其他功能与QA
  讲完两大招牌功能,我们快速过一下别的功能:比如最常被大家提到的大世界支持。从UE5开始我们有了更好的工具,比如WorldPartition就升级成了全新的数据组织方式,配合一套streaming系统,我们不需要手动处理runtime的streaming,引擎会帮你自动切分出不同的Partition,自动处理加载策略。
  而且在这个基础上,我们又有DataLayer对于不同逻辑的处理,有WorldPartitionStreamPolicy根据layer对不同的Policy的定制,有LevelInstance可以把Level看成Actor、嵌套组成模板、模块化搭建地图,并且在LevelInstance层级上设置Hlod的参数。
  为了协同工作,我们还引入了OneFilePerActor,大家每次在地图上编辑或新增时,其实只改到了一个独立的actor所对应的文件,文件锁的粒度比较细,就不会去动整个地图文件,这样引擎也会自动帮你管理这些散文件的changelist生成。
  最后,我们还做了大世界的精度支持,把整个Transform的各种计算都改到了双精度浮点支持。另外,我们在Mobile上也做了更多支持,比如Turnkey全新的打包工作流程,移动端延迟渲染也进入了beta阶段。
  除此之外,iOS我们也做了很多改进,在正式版本我们新增了opengles延迟渲染管线的支持,比如mali上的pixellocalstorage。同时我们也加入了DFShadow支持,以及一些新的shadingmodel:例如和pc统一利用BurleySSS参数驱动的移动版本的preintegrated皮肤。
  同时我们终于对DXC下的半精度做了支持,而且把所有的MetalVulkanopenGLES都用DXC做了转换。同时我们还加入了pointlightshadow、CSMcache和带宽优化过的565的RVT,做了全新的gpuinstanceculling和更高效的autoinstancing等功能。
  对于其他的各种平台,我们UnrealTurnkey工作流是跨所有平台开发打包发布的流程。目标是一键就把项目发布到任意支持的平台的全新设备上,自动完成所有工具链和SDK的安装部署,从4。25后面版本开始我们已经支持下一代主机了,伴随接下来《堡垒之夜》在这些平台上的优化和迁移,UE5上我们对这些支持会更完善一些。
  在这些主机平台上我们对体积云、物理场等,包括加载效率TSR等都做了大量的优化。也有大量内存优化(尤其DX12,buddyallocator改pooling)。rdginsights提供了对RHI层的每帧中间渲染资源的复用的这种profiling编辑器。
  编辑器我们改善了用户体验,用了比较深色的主题的统一配色,大家可以自己去灵活配置。扩大了视窗的利用率,集成QuixelBridge能方便的浏览bridge库中的资产并直接拖到场景中。
  另外我们也加入了GameFeatureplugin,是一个全新的数据驱动的框架,类似之前的游戏框架,现在可以干净的分离到gamefeature插件里方便的激活和卸载,做GameFeatures和模块化的Gameplay,你可以把各种类、数据、内容以及对应的debugcheat相关的内容封装到不同的插件模块里面,可以针对性的通过component来在特定的Actor上启用,这样gameplay模块的扩展性、重用性、稳定性都能有很好的改善。
  MetaSounds也是在EA版本就发布的,是让音频系统有跟渲染管线类似的可编程性的一套工具。类似audio用的shader,所以可以更灵活的使用和操纵原始的音频数据。MetaSounds用来替换以前比较简陋的soundcue,可以更高效、更灵活、更可扩展,Quartz是暴露给bp系统的一套用来精确采样音频数据和事件的系统,可以让你完善地完成类似吉他英雄这种的需要非常准确的帧时间的采样音效、同步控制的这样一套系统。
  另外我们还有别的一套系统(AudioSynesthesia),可以帮助你离线也可以实时对音频做分析,然后把音频做可视化。比如利用niagara或者材质做可视化。
  chaos的物理系统,在UE5开始我们整个物理系统都会切换到chaos,它的一大目标是能有更多的gameplay的交互接口,跟gameplay系统结合更紧密,并且支持网络同步。EarlyAccess版本中我们Rigidbody模拟已经修了很多bug,减少了碰撞对的生成、预先做了更多剔除、修复了一些查询巨大三角面时的错误结果、改进了超高速移动物体或很低帧数下默认启用CCD时不正常的效果、也改了ragdoll模拟稳定性的一些bug。
  在正式版本中,对于PBD的性能和稳定性做了更多优化,做了很好的载具的支持,并且支持网络同步的物理模拟的框架。然后还有各种特殊的solver,比如布料和流体的模拟也得到了增强和改善。
  关于整套UnrealInsights工具,我们改善了现有的Timing,Loading,Network和Animation的功能,同时新版本里面还有MemoryInsights。通过MemoryInsights,我们能按照LLM的方式按类型来看内存是怎么分配的,然后我们如果加MemoryMalloc这样一个参数的话,MemoryInsights还可以帮助大家看到所有的调用、堆栈、分类甚至查MemoryLeak。有很多这种好用的工具,刚刚也说到RDGInsights,来看整个渲染的管线资源分配、复用、生命周期各种各样比较好用的功能。
  最后是MetaHumanCreator,高质量的数字人创建工具,可以帮助小团队在几分钟或者几小时内就创作出3A品质的、带完整rigging,可以用来做动画的数字角色。伴随UE5的发布,我们MHC的创建角色在引擎里面会有更多更好的表现。这样品质的数字角色本来只在3A作品里能看到,现在每个人都能制作,并且通过bridge直接在contentbrowser拓出来,在引擎里面使用。
  QA
  UE5。0正式版会在什么时候发布?
  王祢:目前预计是明年上半年,可能在4月份左右发布。
  UE5。0之后还会支持曲面细分吗?
  王祢:由于不少硬件平台曲面细分效率的问题,我们打算彻底去掉。未来我们会尝试用Nanite去做,但是目前还没有做到。所以现在的workaround如果不做变形,那就只能靠Nanitemesh或者靠VirtualHeightfieldMesh来处理。

茶叶抽检茶叶农药残留超标占比86。3,茶叶怎么喝才安全?中国古代丝绸之路最热销的商品是什么,陶瓷,丝绸,茶叶。茶是一种历史悠久的天然饮料,即便是现代依旧有着广泛的受众,无论中外都有对于茶叶的狂热爱好者。并且近些年来因为各项研究证明了……兰蔻507口红是什么颜色厚涂是酒红色质感兰蔻2018的秋冬限量口红煞是迷人,酒红色的管子十分有质感,低调迷人的气质,十分适合秋冬季节,这个系列还没开卖就有很多小仙女准备购入,下面5号网小编带大家来看一下兰蔻507口红……进一步提高员工工资,是中国移动目前必须解决的核心问题根据调查,北京邮电大学的硕士生毕业主要去向有过三次比较明显的趋势:1、主流去向是电信运营商,这主要发生在08年以前;2、主流去向是华为、三星等公司,主要在0914年……亚洲人涂眼影应该注意什么眼妆正确步骤眼妆是我们平时化妆一定会画的一个重要步骤,眼妆带给大家的改变是很大的,我们亚洲人的眼窝不像欧美人一样,很多夸张的颜色都不适合,hold不住。亚洲人涂眼影应该注意什么1、选……保湿粉饼哪个牌子好用5款粉饼秋天也不怕干到脱妆化妆是必须要定妆的,但是干皮因为出油不多,所以到了晚上皮肤就会变得暗沉,所以干皮定妆需要用到保湿的粉饼,保湿粉饼添加了保湿成分,对干皮很适合,下面5号网小编带大家来看一下保湿粉……红肿痘痘怎么遮瑕想完美遮瑕就靠这2招红肿痘痘往往是起床之后早上被发现,经过一晚上的排毒,痘痘在脸上出现了,红肿痘痘不能乱挤,因为会导致细菌感染发炎,f发炎之后很容易留痘坑痘印,下面5号网小编带大家来看一下红肿痘痘……震撼!亚当斯帐篷城,内部照片首次曝光,仅收单身汉,市长放狠话纽约的AdamsTentCity(亚当斯帐篷城)正式被谷歌地图命名。其实,这个地方是纽约市市长埃里克亚当斯位于兰德尔斯岛的人道主义应急响应和救济中心,目前还不清楚这个标签……clio珂莱欧第二代魔力凝脂气垫色号试色图clio珂莱欧第二代魔力凝脂气垫特别的火,自己也想去买一个,想先看看它的上手颜色。那么clio第二代魔力凝脂气垫色号有哪些?下面提供珂莱欧第二代魔力凝脂气垫试色图。产品色号……22届世界杯马上到来,快来补习世界杯历史课!2022年世界杯马上要拉开帷幕,即将在卡塔尔举办。这是第二十二届世界杯足球赛,是历史上首次在卡塔尔和中东国家境内举行、也是第二次在亚洲举行的世界杯足球赛。除此之外,卡塔尔世界杯……买手机不能太小气,建议一步到位,这3款用五年不成问题很多人买手机又想这个好,又想那个好,关键还小家子气不舍得花钱,但是电子产品这东西,真的是一分钱一分货,好手机是贵了一些,但是不管是配置还是体验真的超强的,而且各种新技术都会有,……香奈儿印记唇釉好用吗?香奈儿印记唇釉怎么样?香奈儿印记唇釉是今年秋冬推出的新品,印记两字可见唇釉的持久性是非常不错的,并且也没有拔干的现象。今天5号网小编就要为大家介绍一下,香奈儿印记唇釉好用吗?香奈儿印记唇釉怎么样?……黄皮适合什么口红颜色?黄皮肤适合什么颜色口红?我们身为龙的传人,大多数妹子都是黄皮的,哈哈,找个小借口不可以吗!今天5号网小编就要为大家介绍一下,黄皮适合什么口红颜色?黄皮肤适合什么颜色口红?黄皮适合什么口红颜色……
娇兰亲亲唇膏542色号试色娇兰亲亲唇膏542试色图娇兰家2017年将会给它的亲亲唇膏增加两款心得色号,并且还是限量色哦!一个粉色一个橘色,都是日常显白的颜色,关键是限量对人的吸引力太大了,下面来看看这款唇膏的试色吧!娇兰亲亲唇……植村秀染唇笔怎么用怎么按出来之前一直是用的液体的染唇液,没想到植村秀居然出了一款固体的染唇笔,习惯的设计,加上是按压的口红,真的很像是得鲜的按压口红啊!那么,这款植村秀染唇笔怎么按出来?怎么缩回去?植村秀……植村秀染唇笔怎么样?植村秀染唇笔好用吗?植村秀染唇笔口红级显色力,打造多款染唇妆效,全天舒候适持久,按压笔尾,体验上妆新姿势。那么植村秀染唇笔怎么样?植村秀染唇笔好用吗?产品介绍2017年7月,植村秀无色限唇部……ysl星辰明彩笔真假ysl星辰明彩笔真假辨别时值ysl明彩笔25周年之际,在三月份ysl将推出限量星辰明彩笔,之前它们家的蕾丝、豹纹的明彩笔就被大家一抢而空,这次的明彩笔包装里面还含有一片片金色星星,不能更美了!那么,它……眼影含重金属吗?眼影里面有重金属吗?眼影是眼妆的必备彩妆产品之一,不同的眼影能帮助我们营造出不同的妆容,今天5号网小编就要为大家介绍一下,眼影含重金属吗?眼影里面有重金属吗?眼影含重金属吗眼影中是含有……impress环采粉霜多少钱?impress环采粉霜专柜价格嘉娜宝旗下的一款超级好用的粉底霜,粉质细腻不容易脱妆,Impressgranmula端正环采顶级粉霜,让你的妆容更加自然!下面为大家介绍一下这款粉霜价格impress环采……阿玛尼红管怎么涂?阿玛尼红管唇釉用法阿玛尼红管唇釉是一支超经典的唇部彩妆单品,更是很多妹子的心头好。今天5号网小编就来为大家介绍一下,阿玛尼红管怎么涂?阿玛尼红管唇釉用法有哪些?阿玛尼红管怎么涂第一步:接着……肝脏最怕的四件事女人以肝为天,养肝就是养命大家好,我是米医生前几天门诊下来最大的感慨很多上班党跟我反馈返工后最普遍的感觉是什么?失眠,早醒,入睡困难为什么会这样?除了一想到上班……国家统计局三季度就业形势总体稳定城镇调查失业率下降国家统计局今天(24日)发布的数据显示,三季度就业形势有所好转,重点群体就业得到有力保障,就业形势总体稳定。前三季度,城镇调查失业率均值为5。6,其中,三季度均值为5。4……幸福到万家万传家不经意的一句话,揭露了王秀玉悲剧的源头宇哥带你读原著,一起来看由赵丽颖,罗晋,刘威,唐曾等主演的热播电视剧《幸福到万家》。看解析,更深入。王庆志不是好哥哥当王庆志发现妹妹王秀玉上大学的名额被万传美……国际奥委会将为中国接力队补办奖牌仪式,或在下一届奥运会上进行直播吧3月21日讯根据国家田径队官方微博的消息,国际奥委会将通过中国奥委会进行奖牌补发仪式,仪式将力求在国际奥委会正式宣布后的12月内举行(或在下一届奥运会上进行)。近日……AmberGroup任命BenjaminBai为首席法务官兼据海外媒体报道,近年来,数字经济大行其道,其中数字经济发展较为前沿的国家,例如美国、欧盟、德国、日本这些国家都出台了相关的政策,鼓励各行业将人工智能、大数据等新一代技术应用于农……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网