JoshWindsor 发表于 2023-1-29 07:51

unreal/UE5 数字孪生数据,场景和性能 经验技巧总结

随着近些年硬件性能不断增强,而游戏引擎有着很好的实时渲染能力,游戏引擎在数字孪生行业的效果表现端也在最近几年大放异彩,虽然多年前我就已经在用cryengine参与过一些电子沙盘和仿真模拟的项目,当时主要是在项目前期阶段建筑景观的漫游效果表现,和bim机电管线的碰撞检测,后来ue4和数字孪生概念横空出世,游戏引擎的应用面也越来愈广,我也有幸在那时接触到ue4,后来也参与了不少相关项目,最近正好有时间,把美术人员制作电子沙盘类型的数字孪生项目流程,从数据的接入到ui,蓝图制作的注意事项小总结下,详细步骤就不展开了,主要梳理一下思路和注意事项,可能需要一定的ue和dcc软件的使用经验,欢迎交流


美术场景导入和优化

1.高程和影像的导入和优化:

1.dem,dom数据的获取:虽然正式的项目中一般业务方会给到数据,但是在网上也可以找到30m精度的公开数据,只要注册就可以免费下载:



30m精度的公开免费数据

2.影像的导入:由于unreal默认只支持最大8192分辨率的图片导入,如果一张一张影像导入的话,非常费时,而且在材质编辑和地形拼接的时候采样也会很麻烦,所以在批量导入影像的时候要使用Streaming Virtual Texturing(虚拟纹理)和UDIM:



ue4开启虚拟纹理(ue5默认支持)


[*]UDIM:U-Dimension,可以使多张贴图映射到同一个模型的UV的不同区域,这样以来导入一个超大地形,只要把uv分好,就可以把分成tile的卫星影像映射到地形的mesh上:



模型的uv一般都是0-1之间,UDIM可以往外扩展

unreal支持的UDIM图片命名格式:BaseName.####.(Name.1001.png。。。Name.1002.png.。。。。Name.1003.png以此类推),只要导入第一张图,就会自动把其他的图片序列一起导入,在材质中引用这张vt,uv会自动按照UDIM的格式采样



[*]虚拟纹理的相关文档:
Streaming Virtual Texturing
3.高程图的导入和优化:
第一种方式,对于超大地形的导入,一般也是采用分块的形式,在ue4中一般采用world composition的方式,这样可以把若干块高程影像(一般是16位raw或者png)以ue的landscape分块的形式导入到ue中,首先在world setting中打开world composition:


然后在level选项面板里选择导入相应的高程图,需要注意的是高程图的命名规则(xxx_x1_y1....xxx_x2_y2....依此类推)和卫星图分辨率与ue地形尺寸比例之间的换算关系(ue单位是厘米,dem一般是米,所以ue导入地形时scale一般都是100):





地形图命名规则



官方给出的需要表现不同尺寸地形时,quads,section,和component之间的最优解


[*]第二种方式:地形也可以通过houdini engine导入ue4,因为30m精度的高程图一般无法满足游戏引擎厘米级别精度的美术表现,所以可以采用houdini对地形进行预处理(对地形的侵蚀,遮罩,分辨率等各个参数灵活调节),输出成houdini的heightfield,再通过houdini engine导入到ue4,地形的精度可以大大提高,而且处理过程更灵活,之前也写了一篇文章:



houdini离线计算对地形侵蚀的结果



一键导入ue4

而且houdini支持ue的world composition ,(使用houdini 的heightfield_tilesplit,可以对原始地形灵活分块,无缝导入到ue4中,自动生成WorldComposition)



[*]第三种方式就是ue5的world partition,这不仅仅是对大规模地形动态分块方案,而是对actor,datalayer,levelinstance,hlod等的整体解决方案,非常优雅,具体用法就不展开,文档如下:
World Partition
2.灯光的优化

1.ue4:
数字孪生场景中一般全动态光照和昼夜变化都是强需求,所以第一步,直接project setting中把静态灯光关掉:


近距离的动态阴影一般都是csm,要注意距离和精度的参数调节,是性能消耗的大户:



默认可调最大距离只有200m

但是当相机距离太远时,csm的距离远远不够,这个时候需要用far shadow和distance fieldshadow来弥补远处阴影精度的不足,far shadow可最远设置8km,csm默认只有200m,但是要注意,far shadow需要打开static mesh的对应开关,distance field shadow不支持材质的顶点偏移,







far shadow最大可调距离可到8km

<li data-pid="BJJnyoav">在表现物体自身阴影的时候,需要打开contact shadow提高自阴影精度,但是contact shadow是基于屏幕空间的,这一点需要注意,相关文档:



无contact shadow



有contact shadow

2.ue5:
同样,ue5提供了统一的,优雅的,简洁的阴影解决方案:virtual shadow map,只需要打开相应选项即可,



项目设置中打开即可

但是据我测试下来,vsm在5.03的默认消耗也很高,目前也处于beta阶段,需要通过command进行大量的参数调节,相关文档如下:
虚拟阴影贴图
总的来说,阴影是是渲染消耗的大户,还要结合阴影精度,距离,场景中物体数量,面数,材质,后期等各个方面综合调节,才能在效果和性能之间找到平衡,主要debug手段还是通过editor自带的gpu visualizer(pie下ctrl+shift+,)查看各个pass的时间:


3.模型的优化

1.instance mesh:在数字孪生城市场景中,会有大量的电线杆,围栏,垃圾桶等小物件,这些都需要合并成instance,否则会增加巨大的drawcall,当然也可以在场景中手动摆好mesh actor,再用一些instance工具或者插件,或者写脚本把static mesh actor转换成instance。



黑客帝国场景中的电线杆



商场里instance转换工具

2.spline mesh:建议使用editor自带的merge actor功能,合并成static mesh在放到场景中



merge actor 工具

3.static mesh:bouding比较大的mesh建议分块,这样更有利于裁切,不需要cast shadow的mesh要把cast shadow关掉,比较小的物体要设置合理的draw distance,镜头较远的时候直接隐去,场景的整体draw call数量可以通过stat rhi中的draw primitive calls获得,对于城市鸟瞰场景,建议对建筑群使用hlod,以降低drawcall。



stat rhi



3. 材质的制作和优化:

1.雨雪材质
一般使用ultra dynamic sky内置的雨雪材质函数即可
2.用好world align texture,根据世界坐标投影的材质,无视mesh的uv,可以用在建筑玻璃幕墙,地砖,路面等材质上,灵活的调整全局uv的缩放。


3.夜景材质:如果想做出很真实的夜景灯光材质,并且平衡好性能是一件比较困难的事情,通常3dmax制作的建筑景观动画中,会使用很多光源来模拟街道商铺的热闹与繁华,但是在游戏引擎中肯本吃不消这么多光源的消耗,下图所有的建筑全部都是用同一个shader,所以也造成这个材质非常复杂,但是也比打灯的性能消耗好很多,我在材质中根据建筑的高度,位置,等信息做了大量的贴图,发光颜色,亮度,位置,霓虹灯流动速度,方向,范围等等的随机,整体uv也是根据世界坐标投影,这样就做到了全称建筑夜景效果的相似而不相同。当然还是有很大的优化空间。


4.合理使用decal

<li data-pid="MXqYe6iO">城市鸟瞰场景中,特别是表现夜景的时候,避免不了很多的点光源等用来表现城市的繁华,但是由于整个城市场景并没有分光照uv,动态光源消耗太高,也不是很好的选择,比如下面这个场景,2020双十一8k大屏,我当时在陆家嘴的沿街的道路,和建筑外立面使用的大量的decal(可能看不太清,),来模拟灯光,并且设置合理的裁切距离,最终才使得整个场景保持在8k,45+fps,整个场景中只有一盏平型关和一个天光。



官图



实在没有高清视频

道路上的车道线,也可以使用decal材质+meshinstance的形式:



黑客帝国中的车道线

5.zfighting问题


[*]在城市鸟瞰场景,经常会由于地面上的mesh的面离得很进,会产生zfighting的问题


1.如果两个物体完全重叠,且不方便改变物体transform,可以使其中一个物体的材质顶点偏移解决


2.动态设置camera clip:如果两个物体没有完全重叠,可以通过调大camera near clip plane的方法解决,通过执行命令:r.SetNearClipPlane xxx ,当然如果要从鸟瞰视角切换回车内视角或者第一视角,要再把近切面再设回去,否则会出现相机裁剪过大的问题。



near clip plane 30



near clip plane 300



数据接入

1.fbx等美术资产的导入


[*]fbx导入选项:一般数字孪生场景都是鸟瞰视角,所有一般来说,大部分的模型导入是不需要带碰撞的;鸟瞰视角会采用的光照也基本是都动态光照,所以也不需要生成lightmapUV;除非在dcc软件中做好了UCX碰撞,一般也不需生成ucx碰撞,大量重复建筑导入的时候,尽量导入单体,在ue中做实例化,不要在dcc软件里面combine后再导入。


2.gltf的导入导出


[*]数字孪生项目中,会和前端同学有很频繁的沟通,前端用到的3d模型大都是glb/gltf,unreal默认不支持gltf的导入导出,但是官方有两款插件:





源模型uasset



转换后的glb



[*]用gltf export这个插件导出gltf/glb的最大的好处是有合并bake贴图的功能,会把uasset的若干个material slot合并成一个slot。

2.GIS数据接入(shp,osgb)


[*]unreal默认不支持gis数据的接入,可以采用格式转换成fbx,shp文件还可以转换,osgb动辄数tb的数据量,直接导入引擎是不现实的,可以采用cesium lab来处理数据,发布成3dtiles服务,通过http请求的方式,cesium for unreal来加载通用的gis数据服务:



cesium官方的免费工具 cesiumlab



可以发布影像,瓦片服务

对于unreal来说ceium for unreal补全了游戏引擎在数字孪生场景表达上的几个痛点:
    1.超大数据量的3d模型流式加载,
    2.通过不断变换经纬度参考中心点,解决ue transform精度为float无法精确表达经纬度位置球面坐标的问题,
    3.基于经纬度的太阳光照(后来ue也有了自己的georeference插件),玩家重力等物理问题,
    4.通过一个很trick的方式实现了unreal中单体化数据查询和对不同数据layer可视化展示。



图片来源cesium文档,


[*]文档链接:
Cesium for Unreal



cesium for unreal 加载的3dtiles服务

3.业务数据接入(csv,xml,json,wss ,mqtt...)

ue蓝图的数据处理能力比较弱,特别是大量数据并行处理的时候,对于美术来说,一般业务数据的接入都要借助插件:

[*]对json的操作:一般使用varest这个插件,里面包括了大多数json数据处理的方法,包括encode,decode,网络求,读取保存等,只需要一点json数据结构和网络请求相关的基础知识就可以灵活使用,需要注意的是,蓝图处理大数据量的json会肯卡,如果数据量很大,老老实实用c++。




varest主要的函数都在这几个头文件里



[*]csv:ue自带的datatable可以将特定格式的json,csv文件快速导入导出,:


那怎么才能快速知道ue支持的序列化后的csv和json的格式呢:直接通过一个struct创建一个datatable然后导出,按照导出的格式拼接csv或者json即可。



datatable右键导出json



导出后的json格式


[*]视频多媒体:unreal支持本地视频流,stream media,图片序列的导入,这几种mediasource都可以在content browser直接创建,这里就不过多赘述,但是unreal的一个mediasource--mediaplayer--mediatexture--material--play的链路实在太长,





支持的编码格式



unreal支持的视频流


[*]http/wss/mqtt:http请求和websocket链接,在商城中都有很多插件,只要有一些基础的网络编程的知识即可。



免费的websocket插件



免费的http请求插件



mqtt插件



[*]和前端网页图表的整合:unreal嵌入前端网页图表一般有两种方式,
1.通过pixels streaming 推流的方式,把unreal的渲染画面推送到浏览器上,这种方式优点是网页的兼容性很好,因为本身就是用浏览器渲染网页,缺点是推送ue的渲染画面对带宽的要求较高,一般来说最高支持4k编码,而且有延迟,pixels streaming的相关文档:
2.是把浏览器的网页嵌入到unreal的umg里,虽然umg有内置的web browser,但是cef的版本比较低,渲染网页性能较差,商城里虽然有很多浏览器插件,但是大部分的插件都是基于unreal提供的默认webbrowser模块,最好找一些cef版本比较高的插件,这样对网页的兼容性更好,性能也更优(也更贵)。

蓝图优化

1.优缺点


[*]首先说一下蓝图的优缺点:最大的优点同时也是缺点都是,在只需要基础的编程知识的情况下,就可以开发出完整的游戏逻辑,在这种情况下,的确是大大降低了开发的门槛,同时也对开发大型项目后期的维护迭代带来风险和挑战。
2.老生常谈的性能问题


[*]通常情况下认为,功能开发迭代效率可能比c++高10倍,但是性能比c++差100-1000倍,但是并不完全正确,原生的c++和蓝图的确如此,但是目前ue自带了把蓝图自动转成c++的功能,再把蓝图转成native c++ code后,纯逻辑运算下蓝图和C++的性能差距不超过两倍,在reddit上有人做过简单的对比,但是项目发开中肯定会比这复杂得多,这个仅供参考:


3.从左往右从上往下


[*]下面几种情况可能是常见的新手连出来的蓝图,显然看起来根本没法维护:



.......


[*]所以建议蓝图连线也遵从从左往右,从上往下的规律,既能清楚的看到执行逻辑的顺序,也能充分的利用屏幕大小,



ultra dynamic sky 的bp

4.使用re route来减少连线的交叉




使用 re route



不使用 re route

5.函数尽量有return node

虽然蓝图的函数没有return也可以运行,但是还是尽量添加return,这样可以在函数early return 的时候可以方便清晰的找到



给函数添加return node示意

6.蓝图要添加注释

蓝图函数和逻辑节点建议添加注释和tooltip描述,注释的颜色可以根据项目需求实现定义好规范(比如tick逻辑用蓝色,beginplay逻辑用浅红色,错误处理用红色,临时测试用灰色等等)





函数可以添加描述

7.使用BP function library和macro library

把项目开发中常用的函数封装成静态的蓝图函数,可以在任何bp中调用


但是要注意bp function library的函数不应过于冗余和复杂,而且减少复杂蓝图class不必要的cast,因为cast会引用bp的hard reference,加载一个bpfun lib,macro lib,会把所有引用的资源加载进来,避免在里面使用hard ref的操作,把整个bp加到内存中,可以的话可以cast到c++的父类,参考自:
简单说一下hard reference和soft reference:前者是蓝图中常用的,引用的话会加载整个object;后者只是记加载一个文件路径。
8.蓝图review和diff

review的话无需多说,
diff的话比较麻烦,git的默认不支持二进制文件的diff,建议可以用unreal的perforce插件,可以在unreal的editor中很方便的checkout/in,commit,push和diff,p4真的非常非常方便。





蓝图diff

9.蓝图和c++的平衡


[*]首先要明确蓝图和c++的优势所在,蓝图在项目前期原型迭代的时候很方便,而且蓝图就算出现了空引用或者数组越界等问题也不会出现程序的crash,所以相对c++来说很安全;但是c++具有很好的runtime性能,能更完整的调用api和充分的利用引擎的功能,更广泛的访问第三方库帮助蓝图拓展功能,更方便的版本管理。
项目原型设计阶段:蓝图
项目功能开发阶段:可以把部分必要的蓝图转成原生c++,底层架构设计c++,数据处理相关功能c++
项目完成开发阶段:蓝图自动转为native c++code



图片来源uod2022的演讲

10.c++header preview:

ue5.10增加了 c++ header preview的功能,简单来说就是bp class所有的函数和节点转成c++代码的头文件预览,更方便蓝图开发人员熟悉c++。


umg的优化

umg是一个比较难用而又不得不用的UI框架,
1.贴图可以关掉mipmaps,texture group 选择UI






2.ui的发光

由于umg的渲染不经过unreal自身渲染3d场景的延迟渲染管线那一套,所有也没有postprocess的bloom效果,我这边尝试了用把贴图模糊掉,和原有的颜色做了一个简单的叠加,应该有其他更好的方法,欢迎交流。





材质节点很简单

3.使用listview

在制作列表类型的ui时候,如果item数量很多的情况下,不要使用vertical box,要使用listview,可以显示成千上万行entry,而又不耗费很多性能,使用时要注意item和entry的区别,可能有1000个entry,但是只显示5个item,所以一个item可以表示多个entry,listview的使用稍显复杂,这里就不过多介绍,




treeview是listview的子类,增加了树状结构,有展开和折叠的功能,可用于做类似于世界大纲视图的umg
4.ui上显示模型

一般在umg上显示模型,使用scenecapture2d,捕捉一张rt,然后再把这张rt显示在UI上,整个过程比较简单,但是要注意的是scene capture 2d很耗性能,记得关闭实时捕捉,并且捕捉的分辨率不要设置太大。


还有一种是slate有一个smeshwidget的类,可以直接渲染模型,但是可惜的是暂时没有暴露给蓝图,文档:
5.image,border,和box

新手在设置umg的widget的style的时候,可能会困惑这几个的区别,调参起来也不直观,可以把uv的颜色直接给到brush的颜色,就能看到这几种style对uv采样的区别:



uv采样的区别

6.使用retainer box

对于比较复杂也不频繁更新的ui可以使用Retainer box包起来,本质上是把它的child widget渲染成一张rt,需要刷新的时候再刷新。


常用效果的制作

1.poi点


[*]poi点一般采用static mesh instance的方式,poi点击查看等交互可以通过line trace返回的item 来获得点击到的instance 的id,再去根据id请求对应的数据。



仅作为示意




[*]或者3dwidget的方式,但是3dwidget的形式据我测试下来消耗比较高,如果有大量文字内容的poi需要显示,建议使用textrender组件,但是也要注意,textrender需要预先制作中文字体:




2.飞线

飞线一般使用beam粒子,设置起始和终点位置,和切线即可


3.热力图

很早之前写过一篇热力图的文章,最核心的就是如何把经纬度的热力数据转成灰度图,并且驱动niagara gpu粒子的参数
待续。。。.

参考:

大概先总结这些,欢迎大佬们随时交流,最后祝兔年快乐,开工大吉

页: [1]
查看完整版本: unreal/UE5 数字孪生数据,场景和性能 经验技巧总结