/images/avatar.png

Papalqi

UE4 多线程架构

在UE4中使用多线程的方式非常丰富,在Engine初始化时我们就能看出一些端倪。除了最原始的使用FRunnable和FRunnableThread的方式,我们几乎还可以使用两种方式进行线程操作。 在我们引擎初始化时,我们就可以看到两种线程的创建方式。 一. 标准多线程实现FRunnable FRunnable 是指标准多线程,适合长期连续的操作。我们只需要进行简单的继承,就可以实现一个标准的多线程实例。 1.1 FRunable的细节 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class FSimpleRunnable :public FRunnable { public: FSimpleRunnable(); ~FSimpleRunnable(); private: // 必须实现的几个 virtual bool Init() override; virtual uint32 Run() override; virtual void Stop() override; virtual void Exit() override; }; Runnable对象初始化调用 Init(),并通过返回值确定是否成功。初始化失败,则该线程停止执行,并返回一个错误码;成功,则会执行 Run()。 如果Run()中的方法不是永远循环的,就可以直接退出。如果Run永远循环,线程无法退出。就算游戏主线程停止了,这个线程还在继续运行。 当Run执行完毕后,则会调用 Exit() 执行清理操作。 我们继承FRunnable实现这些接口,但是其FRunnable本身并没有线程功能,其线程本身是FRunnableThread。 1 2 void WaitForCompletion(); // 阻塞调用例程,直到线程执行完毕 bool Kill(bool bShouldWait); // 强制杀掉线程 如果调用 FRunnableThread的Kill(bool bShouldWait=false) 函数,会先执行 runnable 对象的 stop(),然后根据 bShouldWait 参数决定是否等待线程执行完毕。如果不等待,则强制杀死线程,可能会造成内存泄漏。 调用 FRunnableThread的WaitForCompletion() 函数,将阻塞调用线程直到线程执行完毕。 1.

UE4使用datasmith工作流

DataSmith的作用 一比一的还原场景,以厘米为单位 能为所有实例化对象建立单一的虚幻资源 能保持位置和朝向 支持图层查看 能将Vray材质变为PBR,自动转换贴图 能导入如强度颜色和IES文件 自动生成光照贴图UV DataSmith下载 [https://www.unrealengine.com/zh-CN/studio]{.underline} 进入网站,点击: 获取我们的DataSmith。获得资格后我们就在自己的库里能够看到如下。我们选择安装到高于4.20版本的引擎当中。 DataSmith创建 首先是创建unreal studio工程,要求引擎版本必须4.20以上。选择启动 在新建里就可以创建Unreal studio工程。 空项目是不包含与构建的内容和功能。如果我们是建立空项目的话,我们就必须手动的创建所有的交互功能,或者从其他的模板里导入交互功能。这里的交互是指,内置的一些交互功能,但是我们在这里只关心的是工作流的问题,这里只在空项目里就可以了 我们找到插件里的unreal studio ,可以看到所有的插件 从3ds Max导入场景 要想能从3dsMax导入场景,我们必须首先安装Datasmith导出的插件,我们可以在启动器里找到。 点击获取,我们就能得到网址 [https://www.unrealengine.com/zh-CN/studio/downloads]{.underline} 我们可以从这里下载关于任何的软件的插件。 下载完成后,选择自己的版本进行安装。 然后,可以在max的导出文件里找到.uadtasmith的东西。之后我们就能使用 进行导入。 在这里我们可以选择我们能导入的东西都有哪些。下面还有高级设置。 这里是设置DataSmith生成光照贴图时的分辨率。 上面是最小分辨率,下面是最大。最大最小都设成一样的可以保证光照贴图有最大的内存空间,同时保证贴图纹理空间拥有足够多的空隙。 datasmith自动计算。每次导入引擎时,datasmith都自动的在通道5中展开UV然后将UV打包进通道6,之后压缩之前的空通道。 如果我们只有一个通道的话,也就时0通道。那么datasmith会建立通道1 和通道2 并且默认使用通道2。当我们的UV出现问题时,我们导出去自己调节一下就可以了。

UE4灯光的移动性

UE4的光源的移动性上主要分为:Static(静态) 、 Stationary(固定) 和 Mobile(移动),不同的设置在光照效果上有着显著的区别,以及性能上也各有差异(现在应该是基本不谈这个了,没什么卵用)。 光源:静态, 固定, 动态 物体:静态, 固定, 动态 9种对应关系,并且还有特例 Static光源(静态): 在运行时不会以任何方式改变或移动 光的位置 — 不能变 光的颜色 — 不能变 光的强度 — 不能变 光的其他属性 — 也不能变 UE4的静态光照是在光照构建(build)中进行预计算的部分,会对预计算的光照结果进行存储,例如光照贴图(LightMap,将在之后讲解)、阴影贴图这样的形式,可以在运行时支付较低的效率而获得较好的光照结果。它在运行时完全无法更改或移动的光源。这些光源仅在光照贴图中计算,一旦处理完,对性能没有进一步影响。可移动对象不能与静态光源集成,因此静态光源的用途是有限的。 它可以在World Setting里进行进行关闭。静态光照不能让移动(动态)的对象产生阴影。但是,如果照明的对象也是静态的,就能够产生面积(接触)阴影。这是通过调整源半径(Source Radius)属性实现的。但是,应当注意的是,获得柔和阴影的表面很可能必须设置相应的光照贴图分辨率以便阴影呈现较好的效果。静态光源的主要应用对象是移动平台上的低性能设备(笑了)。 静态光源对静态物体 直接光照: lightmap 间接光照: lightmap 直接阴影: lightmap 静态光源对固定物体和动态物体 直接光照:ILC,VLM 间接光照: ILC,VLM 直接阴影:无 Static光源的阴影 Static光源的阴影是能用与Static物体,存储在lightmass中,这意味着它们对动态对象不会产生 直接影响(静态光照由于烘焙到了间接光照缓存中,所以会有一些影响)。在编辑一个固定光源或者静态光源时,光照信息会变成未构建状态,预览阴影能够为您提供一个在光照构建后阴影的大致样子。 Static光源的特性 采用全局光照时,所有具有静态移动性的光源在默认情况下都是区域光源。点光源和聚光灯光源使用的形状是一个球体,其半径是由全局光照设置(Lightmass Settings)下的光源半径(Light Source Radius)设置的。定向光源使用一个圆盘,位于场景的边缘。光源的大小是控制阴影柔度的两个因素之一,因为较大的光源会产生较柔和的阴影。另一个因素是从接收位置到阴影投射物的距离。随着距离的增加,阴影变得柔和,就像在现实生活中一样 2.2 Stationary光源(固定): 光的位置 — 不能变 光的颜色 — 能变 光的强度 — 能变 光的其他属性 — 能变 固定光源(StationaryLights) 是保持固定位置不变的光源,但你可以改变光源的亮度和颜色等。这是与静态光源的主要不同之处,静态光源在gameplay期间不会改变。但是,如果在运行时更改亮度,请注意它仅影响直接光照。间接(反射)光照不会改变,因为它是在光照系统(Lightmass)中预先计算的。所有间接光照和来自固定光源的阴影都存储在光照贴图中。直接阴影存储在阴影贴图中。这些光源使用距离场阴影,这意味着,即使有光照对象上的光照贴图分辨率相当低,它们的阴影也将保持清晰。 Stationary Light在同一个被覆盖区域中只能有4个,当超过这个数目时,范围最小的那个StationaryLight会被转化为动态光源。 固定光源对静态物体

UE4Lightmass可能遇到的问题

光照贴图的UV问题是造成lightmass的最大的问题。注意事项是,不能重叠,每个之间要留有空隙从而避免泄露可扩散。最好的方法当然是在max里自己来展开每个UV。 光照UV重叠 如果我们发现例如,角落边缘透光,重叠,接缝瑕疵等问题,那么需要返回3D工具。手动的使用第一种方法自己建立光照贴图UV. 对于UV重叠。只需要进行构建,然后看日志信息,大概率会出现UV重叠的信息,这个时候我们可以手动去创建。 光照贴图扩散 这主要时由于这两个部分在光照贴图里过于靠近,所以我们的光照UV中需要每个部分都要有一定的间隔,要不就会出现这种问题。 接缝问题 我们打开它的光照贴图可以看到,对于圆柱型的东西,是比较容易出问题的,仅有一个接缝的Uv是比较合适的。 这个时候我们也是要手动的调整光照UV。 Indirect Seams 间接光照的运算结果在模型之间的接缝处会出现不自然的裂缝 这种的主要原因是两个Mesh之间虽然是平滑的,但是在间接光照进行阴影计算时并不知道这些信息。可以通过在世界设置中调节间接光照的质量和平滑度来减少这种现象 提高间接光照质量会加重光照构建的成本,而如果过于提高平滑度的话,会导致间接光照的很多细节被丢弃。所以一个更好的解决方案是,在构建关卡时,如果是一个平滑的面的话就直接使用一个整体的模型来做,而不是用好几个模型拼接而成。 Bleeding 光照泄露的主要原因是光照贴图的分辨率造成的 像这样室外的光照感觉上就像直接透过到了室内,显然不符合预期。虽然通过修改光照贴图的分辨率来进行应对,但是这样就相当于绕过了问题的来源。更根本的解决方法是,让"地板"与房间的尺寸匹配,这样在光照计算时,房间的地板就不会接收到外部的光的光照计算。 Emissive Material 自发光颜色的材质是通过HDR来实现泛光效果的,因此它本身并不参与光照运算。 通过在使用了自发光颜色材质的物体上打开 可以让其能够照亮周围环境,但仅限于静态光照。当物体是Movable时,没有办法开启这个选项。视频中实现的类型于动态照亮的效果是通过在物体上绑定一个改变GI的PP来实现的,然后两个PP之间的Blending就会改变空间内的灯光造成的影响,形成类似于被物体本身照亮的效果。 Error Coloring 错误着色可以用于排查静态光照计算时报出的UV方面的错误,因为光照构建时只是提示物体上有UV的Overlapping和Wrapping有时候还是很难找到对应的问题的,尤其是模型并不是自己构建的情况下。 打开这个选项之后要将光照质量调整为预览,才能看到错误着色。 重新构建一次光照,就能看到 橙色的部分是Overlapping而绿色的部分是Wrapping。

UE4的LightPropagationVolume

目前刚接触UE4,想要得到最后更优质的图像,简单的研究了一下Light Propagation Volume。 Light Propagation Volume: CryEngine的开发者发明了Light Propagation Volume (LPV) ,主张不使用预计算,在运行时直接计算动态间接光照。通过对LPV进行marching,可以产生半光泽材质的反射:它的做法简单总结是先生成一些虚拟的点光源来近似间接光照。每个点光源都要渲染一个reflective shadow map,然后将shadow map的光照信息注入到一个专门用球谐系数形式保存光照的volume 3D纹理里面,然后在纹理内部将最初的光照传递分散开来,渲染的时候直接从这个volume texture里读取要着色的点位置的颜色作为间接光照。这个方法可以达到不错的间接漫反射。缺点第一是volume texture太费显存,第二是基于体素化之后的光照信息也会有“格子”样的artifact,而且也是非常耗费计算的一个技术,因为每一个虚拟点光源都要渲染一个reflective shadow map。 这个功能是默认没有打开的(为啥没开不用多说了吧!),必须要修改配置文件,r.LightPropagation=1 加入consolevariables.ini 文件最后。 遇到问题 漏光问题,拥有体积的面片墙无法遮挡光线渗透。之前项目的脑残做法是用一个额外的box进行遮挡阳光。我服了。 可通过调整Light Injection Bias 来规避问题。别问为什么,我现在也不知道。 阴影平坦,调整Occlusion   结论 总之呢,目前来说,由于灯光全都是动态光,mesh也是动态的,不能进行bake的话,LPV这是比较好的解决方案,但是并无法产生最好的图像。