/images/avatar.png

Papalqi

[译]Low-level Thinking in High-level Shading Languages

很多聪明人写的代码,本可以以更好的方式编写。 偶尔我会听到“这是未优化的”(this is unoptimized)或者这只是个“例子”(educational example)作为借口,但大多数时候这个借口都不成立。因为他们其实不知道如何做到正确。 此外,供应商的SDK示例中的代码也不总是正确的。当最优秀的牛人都做得不好时,这是一个行业的问题。 1 (x – 0.3) * 2.5 = x * 2.5 + (-0.75) 很久之前,我们需要写汇编,从2003年之后的一切都是HLSL或者GLSL。这当然是一种进步,我们使用更高层次的抽象语言进行shading。这没毛病,但是,随着硬件与我们正在使用的抽象内容之间的差距的扩大,人们与硬件失去联系的风险就越来越大了。如果我们只看到HLSL代码,而从来没有不知道GPU运行的是什么,这将是个严重的问题。本文要传达的信息是,在使用高级着色语言时保持低级别(Low-Level)心态对于编写高性能着色器至关重要。 这表现的很清楚,为什么我们应该使用低级别的思考。我们只移动一些东西,加一些括号,就能实现一个更快的着色器。这是通过理解底层硬件并将HLSL构造映射到它从而来实现的。 本文使用的硬件是Radeon HD4870((用于生成最易读的反汇编代码)),但本文中的大部分都是通用的,除非另有说明否则适用于任何GPU。硬件之间具有诸多的不同。 即使您没有观察到特定GPU的性能提高,也有可能对其他的GPU有所提升。GPU有大量的ALU。如果我们将ALU的利用率从50%降低到25%,这却并不一定能够提高性能。因为同时其会受到其他因素的限制(贴图和内存带宽等)因此可能不会提高性能,但可以让你降低功耗,并且为新feature留出更多空间。最后如果你解决了TEX/BW,会给你带来相对于的收益。 “编译器将优化它” 编译器不懂你的思想。编译器只理解着色器中的操作的语义。他们不知道你在努力完成什么。许多可能的优化都“不安全”,因此必须由人来完成。 他们没有整张贴图数据 他们只有有限数据 他们不能打破常规 这可能认为的最简单的代码示例,您可能认为它可以自动优化为使用MAD指令,而不是ADD+MUL,因为这两个常量都是立即数。 然而编译器并不是这么想的。 驱动程序仅限于传递的D3D字节码的语义。最终在GPU上执行的代码就是你写在着色器上的内容!大多数情况下你可以在PS3看到一样的结果。但是上面这种情况例外,可能是因为那里的常数为1.0f。其他的情况都不会变为MAD。 Xbox360着色器编译器很有趣。 它什么都不在乎。 即使你明显破坏了数字,你也会一直做这个优化。 即使它导致常量溢出或下溢为零,也无关紧要。 如果上述式子中1的位置是一个常数,GOGOGO。上车,直接优化 如果上述式子中1的位置是0,这样的话MUL不就好了吗? 太棒了! 所以当然会产生很多小误差。 如果在此转换中丢失了许多浮点数精度,则不会立即注意到为什么会发生这种情况。 我们在这里处理IEEE的浮点数。更改操作顺序并不安全。如果你运气好,你会得到同样的结果。 改变顺序更可能会提高精确度。但是,根据数值的不同,并不总是行得通。 在最坏的情况下,它可能会被上溢或下溢破坏,或者如果不进行优化,它可能会在正确运行的部分返回NaN。一般来说,编译器擅长于:移除死代码,消除未使用的资源,折叠常数,寄存器分配,代码调度;但通常不会:更改代码的含义、中断依赖关系、违反规则。 例如我们的x = 0.2f sqrt(0.1f * (0.2f - x)) ,returns 0 sqrt(0.02f - 0.1f * x) ,returns NaN 这种差异是因为第二个表达式将非常小的负值传递给sqrt。 请记住,0.1f、0.2f和0.02f都不能用IEEE浮点数正确表示。这个偏差来自于有适当的四舍五入的常数。 编译器不可能预测未知输入的这些失败。因此我们需要让硬件知道我们要干什么。相信着色器编译器会很好地修复事情,真是太天真了。虽然D3D编译器允许自己在编译时忽略INF和NaN的可能性(这通常对于游戏开发是可取的),但这并不意味着驱动程序在运行时被允许这样做。如果D3D字节码说“乘以零”,那么这正是GPU最终要做的事情。虽然D3D编译器可以在编译期忽略INF和NaN的可能性(这通常有利于游戏开发),但驱动程序并不可以在运行时做同样的事情。 如果D3D字节码说“乘以0”,GPU将正确地执行它。 1 x* 0 = 0,但是NaN * 0=NaN 因此,我们关于硬件的通用事实是

蓝图的一些细节

一些基本的Ctrl和Alt类似的基本操作就不说了。 快捷键T可以防止我们选中透明物体,当有大量的雾气或烟雾并且干扰对象选择时,可以使用此功能。 蓝图书签功能 当您按下☆图标时,将显示[新书签]注册框,输入书签名称即可。 这将帮助你快速阅读蓝图和进行跳转。 具有快速跳转功能的蓝图迭代 在[编辑器首选项]-> [常规]-> [键盘快捷键]的“图形编辑器”中指定。 您可以使用Ctrl + N(N:数字键)进行保存,并使用Shift + N(N:数字键)进行移动。 使用快速跳转移动如果已经使用Ctrl + 1,Ctrl + 2,Ctrl + 3保存了蓝图视图,则可以输入Ctrl + 1,Shift + 2,Shift + 3到达你保存时的地方Ctrl +N。。 蓝图宏的开销 宏以与C ++宏相同的方式替换节点。其特征是宏的节点在宏节点所在的位置扩展。与函数不同,除非放置了节点,否则不会对其进行编译。放置的节点像内联函数一样展开,因此调用它的成本应比调用函数的成本低。 仅添加矢量的函数和宏就是这样。 宏为321毫秒,函数结果为392毫秒。宏仍然更快,但是它可能没有您所关心的那么大。由于包括了逻辑的复杂性,函数和宏之间的速度差异变得更加明显。当然,这种加法会产生这样的差异,因此,如果它成为复杂的逻辑,则可能会出现明显的速度差异。 在UE4中,当您双击BP节点时,Visual Studio(或Xcode)将自动启动并打开实现该BP节点的代码。 当您想详细了解如何使用节点和处理内容时,这很方便,但是说实话,有时在不使用BP的情况下意外双击就可能导致Visual Studio在未经许可的情况下启动. 在这种情况下Navigate to Native Functions from Blueprint Call Nodes,让我们禁用编辑器设置!即使双击该节点,Visual Studio也不会在未经许可的情况下启动! 拉直连接和左对齐快捷方式 如果像我一样,希望将蓝图组织得井井有条,您可能已经知道“拉直连接”工具,该工具可让您在选定节点之间建立直连。 不幸的是,默认情况下,此选项没有快捷方式,但是经过深思熟虑的UE4允许您定义一个。我将说明如何进行这些简单的步骤,并在以后节省大量时间。 首先,我们需要进入Editor Preferences,然后进入Keyboard Shortcuts部分。在此处,我们将在搜索栏中输入“straig”以查找与“拉直连接”命令。可以设置两个绑定,个人而言,我只在H键上设置了一个(它既快速又易于使用,并且尚未绑定到其他东西)。 然后,我们可以使用我经常使用的“向左对齐”选项进行相同的操作。就个人而言,我将其绑定到V键。 现在,一切就绪。我们可以在图形编辑器中对其进行测试。只需选择要排列的节点,然后按H(如果要水平对齐节点)或按V(如果要垂直对齐节点)。 编辑器蓝图组件 Asher在他的Inside中就是用这个功能做了自己的高度雾的生成工具。 创建一个小部件。首先,我们需要创建一个类型为Editor Widget的新资产。对于此示例,我们将仅制作一个小的“ Hello World”按钮。编辑器小部件窗口应如下所示: 在小部件的事件图中,我们添加以下简单行为: 运行小部件。这个小部件非常简单,但是它显示了为编辑器创建UMG小部件的主要原理。现在,我们要对其进行测试。 当我们单击按钮Hello World时:在视口中将看到日志行“ Hello World”。假设我们处于编辑器上下文中,则可以调用任何编辑器函数。 父节点和子节点 Actor Palete UE4 .

关闭双击蓝图跳转VistualStudio

在UE4中,当您双击BP节点时,Visual Studio(或Xcode)将自动启动并打开实现该BP节点的代码。 当您想详细了解如何使用节点和处理内容时,这很方便,但是说实话,有时在不使用BP的情况下意外双击就可能导致Visual Studio在未经许可的情况下启动. 在这种情况下Navigate to Native Functions from Blueprint Call Nodes,让我们禁用编辑器设置!即使双击该节点,Visual Studio也不会在未经许可的情况下启动!

UE4 VirtualTexture 源码解析

一.基础、原理和使用 Unreal最早从2017年就开始进行VirtualTexture功能的研发工作。4.17版本初次的提交,4.23 版本正式放出SVT和RVT,4.26 版本推出Adaptive VT。 按照使用上的不同,在引擎中一共有四种不同的VT类型 UVirtualTexture2D直接是继承于UTexture2D的,是最普遍上的的VT类型。 ULightMapVirtualTexture2D跟 UVirtualTexture2D没有什么太大的区别,主要是使用在LightMap中使用。 URuntimeVirtualTexture,RVT,后面会讲到其最终的用法。 如果RVT勾选了Adaptive,那么RVT则会变成AdaptiveRVT。 大致上我们按照生成的时机不同,主要分为两种VT的格式。UVirtualTexture2D和ULightMapVirtualTexture2D叫做SVT(Streaming Virtual texture)。而URuntimeVirtualTexture和他的衍生类别AdaptiveRVT称之为RVT((Runtime Virtual texture))。 1.1Streaming Virtual Texture VT功能并不是UE4引擎默认开启的,如果我们想要使用Virtual texture ,需要在项目设置中设置Enable Virtual Texture Support。而勾选Enable Virtual texture lightmaps,则会将我们的Lightmap变为VT形式。 1.1.1 普通贴图转换为Virtual Texture 当我们重启编辑器后,我们可以把之前普通的贴图右键点击转换为VirtualTexture。使用这种方式编辑器将检索与之相关的材质使用。会将会改变使用到这张贴图的材质的采样方式。 多选批量转换当然也是支持的。 我们也可以在贴图的设置中去设置这张贴图是否是VirtualTexture。 不过,这样我们就必须手动的去调整材质里对于VT的采样方案。不然材质会报编译错误 1.1.2 导入为VirtualTexture 之前的操作是把项目中已知的贴图进行转换,当我们想要新增贴图时,由于贴图的大小限制,我们可以把一张超大的贴图切割开,然后同时导入多张texture ,如果他的命名规则如下图所示那么他就会按照UDIM多象限UV进行排列并且识别为VirtualTexture。 当然,如果我们只是导入一张贴图的话,会根据项目中的配置来进行判断,分辨率如果大于这个设置,将会转换为VirtualTexture。如果比这个小的话,将视为普通的贴图处理。 1.2 Virtual Texture的目的 在这里我们希望去讨论VT的实现目的。假设我们的游戏画面是静止不动的,并且如果我们能够实时创建这么一张贴图来显示我们的场景,我们假设屏幕分辨率是1920x1080 ,用RGB8来进行存储。 920x1080x3 =6075KB≈5.93MB,(显存利用率) 也就是说,我们显卡的显存只需要用 6MB 就完全够了。这种极端的情况用现有的硬件实现起来恐怕不太现实。这种情况很难在一个动态的场景中实时的去做到,但是即使是有一些cache的冗余数据,就算到了100倍的冗余,其空间使用也小于我们目前的Texture Pool的大小设置。 因此,Virtual Texture的基本思路就是:把能看到的贴图才加载进来,没看到的不加载;进的精度高,远处的精度低。如下图所示,如果我们只把看到的部分(高亮的部分加载进来)那么内存占用上将大大减少。 从中我们可以看出Virtual Texture实则是解决我们空间存储的问题。世间所有的炼金术都遵循等价交换,你既然节省了空间,那么你的时间消耗则会增加,这是一个以时间换空间的技术:在每个Tile动态加载卸载的过程中和VT采样时都将产生额外的性能开销。因此我们是否需要开启,将哪些贴图进行开启,都是一个值得权衡的问题。而不是无脑的去使用。 既然解决的是贴图的内存管理问题,其跟传统的基于Mipmap的贴图和可见性的Texture Streaming管理是不同的。传统的StreamMgr只会根据可见性和对应的Mipmap来进行流送的处理,也就是说我们并不能对单张贴图的某一部分进行更为精确的控制,也就是有了过多的冗余信息。例如我只看到了一个贴图的一个角落,却要把他整个都加载进来。 而VirtualTexture 这种将整个Texture分为Tile 的方案,则考虑了这一冗余数据的处理。VT的劣势也很明显,在镜头剧烈变化的时候,其会不停的进行加载卸载的操作,如果配置不当会导致明显的帧率问题。 1.3 Runtime Virtual Texture 首先我们将解释一下RVT(Runtime Virtual Texure) 和普通的SVT(streaming Virtual Texture)的区别。RVT是一张动态在场景中获取的VT,因此所有的数据并不需要存储在硬盘中,而是在我们需要某一块时(相机看到的时候)直接渲染出来。

ActorPalete

UE4 .26或悄悄添加了曾经是“演员面板(Actor Palete)”插件的东西。顾名思义,这个actor调色板是一个插件,它可以让您加载其他level的角色从它们拖动到当前level。 一旦激活了Actor Palette插件,请从顶部菜单的“窗口”->“ Actor Palette”中打开一个Actor Palette。 当打开一个新窗口时,它将如下所示。 您可以在Actor Palette中打开一个关卡,方法是从Actor Palette窗口中选择“打开关卡”,然后选择您实际要打开的关卡。

Niagara 源码架构解析

从git上的信息其实可以看到,Niagara其实在引擎中存在的时间非常久,在4.0版本就已经存在。但是直到2018年的4.17中公开出来。4.17~4.24 为实验版本,4.25 之后正式版本。但是从目前官方的对于Niagara fix的代码提交上看,还是有相当多的编辑器问题修复。 17年才将Niagara从Engine内部移植到插件中。 随着长久的历史变迁,Niagara已经进行了多次的文件位置上的转移,目前的位置是在引擎的插件中。 Niagara在UE4开始就已经在构思做了,目的就是重构继承于UE3的Cascade。Niagara当时的设计目的就是data driven并且扩展性更高的粒子系统,解锁模拟和渲染,所以有图形化的节点能不需要程序来实现模拟的逻辑功能。所以2014年时引擎实现了向量化(指令并行)的虚拟机。 后续为了进一步提高了并行性,加入了compute shader的GPU支持。 本文主要设计Niagara 的主要代码框架结构,对其内部可能的其他一些知识体系。本接下来文章介绍Niagara 的编译和反射系统。因此本文就不在提及过多关于这方面的内容。 我们照例观察一下整个代码的文件组织。 Niagara:所有的运⾏和逻辑构成 。 NiagaraAnimNotifies:可以在动画的过程中进行事件通知播放Niagara。 NiagaraCore:⼀些通⽤的类 NiagaraEditor:编辑器内的可视化编辑节点。 NiagaraEditorWidgets:Niagara 的UI 。 NiagaraShader:Niagara 的shader 。 NiagaraVertexFactories:组成MeshBatch的顶点⼯⼚。 一.基本概念 1.1system 和Emitter 我们通常在编辑器中使用的是Niagara资源主要有两种,一种是我们的Niagara发射器Emitter,一种是我们的Niagara系统System。并且我们发射器是由我们的Module共同组成,从而完整的形成我们的整个Niagara系统。其设计理念相比与Cascade,拆分的更加的细致,从而能偶比较细致的组合和复用。 我们本次并不关心Module所能代表的发射和编译模块,我们重点关注的是Emitter和System所对应的运行时数据。 所有使用Niagara 的地方都需要我们的UNiagaraComponent来进行,其主要是进行控制和Niagara系统的交互。 我们在编辑器中资源对应的是UNiagaraSystem和UniagaraEmitter。一个UNiagaraComponent会拥有指定的一个UNiagaraSystem对应。但是UNiagaraSystem并不是我们运行时直接使用的数据。我们会在UNiagaraComponent初始化时构建对应UNiagaraSystem的FNiagaraSystemInstance,同样System里面的UNiagaraEmitter会生成对应的FNiagaraEmitterInstance。这如同类和实例的关系一般。 对于每个FSystemInstance,会有⼀个相对应这个System类型的的Simulation,它和Instance并不是⼀对⼀的 关系。如果场景中存在同⼀个UNiagaraSystem的多个实例,其只对应⼀个 FNiagaraSystemSimulation。也就是说,对于数据结构⼀致的实例,会使⽤同⼀个Simulation进⾏模拟。因为相同的System的Spawn和Update与数据存储的大小和类型是相同的。提高缓存一致性和数据的存储效率。 所有的FNiagaraSystemSimulation都由FNiagaraWorldManager统一进行管理。 1.2 运转流程 Niagara将有Initial和Update两个重要阶段。其中Initial只在一开始运行一次,Update则每帧运行。 而根据发生的位置不同分为SystemUpdate,EmitterUpdate和ParticleUpdate,分别代表每个System,每个Emitter,和每个粒子的更新。 例如我们spawn一个NiagaraActor,对应的NiagaraSystem中有两个Emitter,每个Emitter发射1000个粒子。 我们排除一些粒子间事件这种情况。那么当我们在初始化时,会调用一次SystemSpawn,调用各自的Emitter的EmitterSpawn,调用各自粒子的共两千次的ParticleSpawn。之后除非有新的Particle生成会调用particleSpawn,否则不会再调用任何Spawn。 之后,我们每帧都会调用我们的各种Update去更新数据。 1.3 渲染策略 这里忽略Light和component对应的Renderer。我们拥有多种渲染器可供选择。 我们其他MeshDraw一样会拥有⼀个渲染的代理Proxy帮助我们来完成最终的渲染,对于Component来说我们持有的该System 的所有Emiter带有的Renderer都会我们会赋值给Proxy。因此其实我们的最小MeshBatch单位是与Emitter数量相关,其数据被Proxy持有,最终交付渲染,这⾥的渲染和UE4普通的渲染架构并没有什么不同,都是统⼀的框架。 由于Niagara的可编程性,其实现功能的潜力是巨大的。它可以非常复杂,但是我们剖析其本质上是一种空间位置模拟的系统之后,我们就能够抓住其关键就是更新它需要的关键数据。更新FNiagaraDataSet。 二.模拟数据 不论Niagara Emitter有多少的Module,Module里有多少的脚本,脚本中写了多少东西。我们当然要抓住本质数据,其都是更新某个渲染器所需要的必要参数,也就是如下图所示的信息。 也就是说,只有这些信息是每个渲染器所需要的,其会传递给渲染线程并最终提交渲染。任何其他参数仅仅为中间变量。因此我们首先关心的是这个数据是存储在什么地方的。由于一个Emitter可以拥有多个不同的Renderer。因此其本身存储在Emitter级别,而不是在Renderer级别。 因此我们最终传递给渲染线程的数据存储在每个Emitter实例FNiagaraEmitterInstance的FNiagaraDataSet身上。不论是GPU粒子还是CPU粒子。 我们将FNiagaraDataSet的数据作为每帧更新的数据继续传递。FNiagaraDataSet最主要的数据是两个buffer。 其中一个是当前使用的buffer,一个是我们将要写入的buffer。FNiagaraDataBuffer拥有提供CPU粒子或者GPU粒子的数据。如果是CPU粒子,我们将在CPU做计算写入操作,如果是GPU粒子,我们在CPU端只需要把对应的buffer指定就可以了。 从传递的数据来看,如果我们是CPU粒子,将直接把最终的模拟结果对应的buffer传递给renderer。而GPU粒子则没有最终的数据,所以需要传递给渲染线程的数据则更完整一些。 其封装成FNiagaraComputeExecutionContext。 2.1 CPU粒子模拟数据更新 最开始我们有一个全局的管理器FNiagaraWorldManager。每一个System类型对应的唯一FNiagaraSystemSimulation都将在这里进行注册并且收到它的支配和管理。 我们的FNiagaraSystemSimulation的数据更新分成两个部分。 Tick_GameThread。这里主要是更新一下系统时间等参数,然后调用FNiagaraSystemInstance的Tick_GameThread。在FNiagaraSystemInstance主要是更新System的Parameters和DataInterface。 Tick_Concurrent,这个阶段可以不在Game线程完成。 对于那些新生成的SystemInstance调用它的spawn script。 是调用system update script进行System的更新。 将system模拟的结果注入到emitter的绑定数据中。 调用FNiagaraSystemInstance的Tick_Concurrent。 在FNiagaraEmitterInstance::PreTick中,最主要的是执行Emitter的Spawn和Update脚本。

给UE4项目改名

很多时候我们对一个工程随意地起了一个随意的名字,这很常见,如果我们想要后面修改整个项目的名字,似乎应该是一件简单的事情,但是这个过程充满了陷阱。如果做错了,您可能会无意间破坏您的项目。手动的做当然是一件非常困难的事情,尤其是对于C++的项目,其模块的命名其实并不容易进行修改,在这里介绍一个工具帮助我们自动的修改抿成。在进行这样的大更改之前,最好备份您的项目。当然,请确保重命名时未在编辑器中打开您的项目。 使用流程 我们打开二进制文件。 输入对应的目录:E:\UE4\1 需要注意的是,现在他没办法支持中文名称的更改 然后需要我们输入新的名称: 输入完成后就可以了。 其可处理蓝图和C++工程。 工程地址:https://github.com/UnrealisticDev/Renom 直接下载

100TipForUnreal

1.Paste Here(复制到这个位置) 我们打开编辑器的设置,然后可以设置这个快捷键,例如我们可以设置为左括号 之后我们在场景中复制的时候,就可以直接使用这个快捷键,将之前你Ctrl C的东西复制到你鼠标的位置。 2. 快速对齐——按住V键拖动物体顶点对齐 我们在拖动一个物体的时候,按住V键,可以显示它周围的物体的顶点并且在移动的时候吸附上去。场景摆放的时候利器!。 3. 鼠标中键移动物体中心 我们知道所有的物体中心是制作模型的时候决定的,但是我们在编辑器摆放物体的时候,希望能够边缘点对齐,我们就可以临时移动中心点。当然这个移动后中心点是临时的,不会保存。 4. 自定义项目类别 我们可以通过修改.uproject file的category来实现 5. 使用高级的文件检索方式 例如我们所有定点数小于1000的模型 6. 输入计算 7.选择log类型 8. 修改文件夹颜色 可以自定义颜色,明显的标记出自己常用的文件夹 9.修改缩略图 我们可以转动编辑器里面的缩略图,进行更改 10.Ctrl +鼠标中间+ 拖动 =快速切换视图 我们使用Ctrl +鼠标中间+ 拖动可以快速切换视图,拖动的方向决定你的视图模式。 11.测量距离 在平行投影的视图中使用鼠标中键可以测试距离,单位是厘米。 12.你可以打开4个Content 这样你就不用每次翻阅资源都跳转了,你需要提前锁住。 13.你可以打开4个Detail面板 14.你可以复制任意属性 15.你在编辑器复制的所有东西,其实都文本 所以我们是可以直接使用文本传递的。 推荐的网站https://blueprintue.com/,可以共享蓝图。 16. 你能够在color picker保存颜色 17.你能够任意拖动数组改变里面的位置 18.蓝图全搜索 使用CTRL + SHIFT + F 在蓝图编辑器中 19. 使用Ctrl 移动节点 20. 修改网络样式 1 2 3 r.Editor.NewLevelGrid 0 r.Editor.NewLevelGrid 1 r.Editor.NewLevelGrid 2 21.修改网格材质 /Engine/EditorMaterials/LevelGridMaterial2 22. r.

UE4网络教程1-网络架构总揽

一.网络总览 Unreal Engine4使用标准的Server-Client体系结构。 这意味着服务器是权威的,所有数据必须首先从客户端发送到服务器。 然后服务器依赖你写的代码验证数据并且给予反馈。 1.1一个简单的例子 在多人匹配中,作为一个客户端,当你移动你的角色时,你并不是自己移动你的角色,而是告诉服务器你想移动它。 然后服务器为其他人(包括你)更新你的位置,。 注意:为了防止对本地客户端产生“滞后”的感觉,程序员经常让这个玩家直接在本地控制他们的角色,虽然服务器仍然可能在客户端开始作弊的时候覆盖角色的位置!这意味着,客户端将(几乎)永远不会直接与其他客户端“交谈”。 1.2其他的例子 当向另一个客户端发送聊天消息时,您实际上是将其发送到服务器,然后服务器将其传递给您想要到达的客户端。 也许你消息的结构方并不是一个人,也就是不只是一次私聊,对方有可能是是一个team,guild,group等。 永远不要相信客户! 信任客户端意味着在执行客户端操作之前不测试客户端操作。 这将允许作弊!不过有些情况下我们可能会允许一些纯粹表现的效果只在客户端进行而不在客户端验证。一个简单的例子是射击:在服务器上应当确保对某个客户端的测试,如果在服务器的记录中显示该客户端实际上有弹药,才应当允许该客户端射击,而不是直接在客户端处理射击! 二.UE4 的网络框架 我们如果拥有一个对象,使用前面关于UE4的Server-Client体系结构的信息,我们可以将框架分成4个部分: Server Only – 只在服务器上 Server & Clients – 同时存在客户端和服务器 Server & Owning Client – 只在服务器和拥有他的客户端上 Owning Client Only – 这些对象只存在于客户端上 “Owning Client”是一个所有权的问题,也就是这个对象的所有权是否是在你这一台客户端上,例如你控制的角色,这个对象对于你来说,归属权就是Owning Client。 所有权在以后的“RPC”中变得很重要。下图展示了一些常见的类以及它们存在的部分。这就是一些最重要的类是如何在网络框架中布局的。 下图显示了另一个例子(具有两个客户端的专用服务器),说明这些类的对象如何通过网络框架分发: 之后将展示一些最常见的类。 还将提供如何使用这些类的小示例。 如果不理解,请忽略,直到您阅读系列后面有关复制等章节的内容。 一些游戏类型可能会使用不同方式使用这些类。 下面的例子和解释不是唯一的方法 2.1 GameMode 4.14开始GameMode类被分成 GameModeBase和GameMode。 GameModeBase的功能较少,因为有些游戏可能不需要GameModeBase类的完整功能。 GameMode用于定义游戏的规则。 这包括如Apawn、Player Controller、APlayer State等。 它只在服务器上可用。 客户端没有这个对象,并且在试图检索它时只会得到一个nullptr。 GameMode例如死亡匹配,团队死亡匹配或捕获旗帜等模式。这意味着游戏模式可以定义如下内容: 我们是团队比赛还是个人竞赛 获胜条件是什么?一个人/一个团队需要多少次杀戮? 如何取得胜利? 杀了人? 夺旗? 将使用哪些角色? 允许使用哪些武器? 只有手枪? 在多人游戏中,GameMode也有一些有趣的功能,帮助我们管理玩家和/或一般的比赛流程。 2.2.1GameMode Blueprint 我们要做的第一步是蓝图版本的“覆盖函数”部分: 您可以为这些函数实现您自己的逻辑,以适应您的游戏的特定规则。 这包括改变Gamemode产生DefaultPawn的方式或者你想决定游戏是否准备开始: 例如,检查是否所有玩家都已加入并且已经准备好了:

UE4物理动画参数

首先我们打开物理资产: 影响物理动画的是两个,一个是Profile里面物理动画的配置,还有一个是本身Body 上面的配置 一. Body的设置 Mass ,默认是根据你Body上的体积自动计算的,我们可以更改。最终影响的是惯性 LinearDamping:线性阻尼。控制Body的线性速度减缓强度。值越大,速度减小越快。 AngularDamping:角速度阻尼。控制Body的角速度减缓强度。值越大,速度减小越快。 (以上两个数值,若启用PhysicalAnimationProfile,一般不再设置这两个数值,Profile的值也影响该效果) Enable Gravity:是否启用重力。关闭后不受重力影响,只受Body的惯性影响。 CollisionReponse:是否和外部物体碰撞。需要和外部物体碰撞时打开,如在人群中穿行和碰墙壁 二. Limit的设置 原则上是根据人体骨骼活动范围设置limit,并且所有动作都应在limit中运动。为了方便,可把所有limit设为free,通过Physical Animation Profile来约束,Profile无法满足的,再去设置个别骨骼的limit,如Spine。 三. Physical Animation Profile 打开Profile 选择一个已经有的prfile,这个名字对应的配置是可以在蓝图里指定的。 选择完成后,就可以看不同的刚体对应的物理参数 Is Local Simulation:是在世界空间还是在局部空间,判断移动Kinematic时是全局还是相对父Body的。目前从代码来看我们用世界空间的比较好。 Orientation Strength:用于更正方向误差的力。值越大,越靠近动画的角度 Angular Velocity Strength:用于更正角速度误差的力。值越大,速度稳定(向动画靠近)的越快。 Position Strength:用于更正线性位置误差的力。仅可用于非局部模拟。值越大,越靠近动画的位置。 Velocaty Strength:用于更正线性速度的力。仅可用于非局部模拟。值越大,速度稳定(向动画靠近)的越快。 Max Linear Force:用于更正线性误差的最大力。(设为0) Max Angular Force:用于更正角度误差的最大力。(设为0) 四.Constraint Profile 功能:局部控制。关节驱动身体靠近动画,靠近动画的姿势,而不影响Body的属性。如果靠PhysicalAnimationProfile驱动,会导致Body过于僵硬无法移动,ConstraintProfile解决了这一个问题,但运动时需要PhysicalAnimationProfile去稳定Body的位置(全局的)。 原理:设置Constraint的Motor,setDrive驱动关联的两个Body到达动画的相对Rotation。 SkeletalMeshComponent需要设置Update Joints From Animation为true. Angular Drive Mode需要设置为Twist and Swing,Motor才会生效。 Target Orientation: 不必设置,Update Joints From Animation会取动画来设置该Orientation。 Strength:向动画靠近的强度。值越大越靠近,10000的值基本和动画一致。 Target Velocity: 设为0即可。可理解为停下的快慢。 待做:添加Update Velocity From Animation,从动画中取得目标速度。