你的浏览器不支持canvas

让我们携手共创奇迹!

杂记

Date: Author: LBD

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。转载请注明来自WindCrazy

这是随手记得,很杂,在做的过程中一直改,还未整理,仅供参考

命名规范

模版类以T作为前缀,比如TArray,TMap,TSet UObject派生类都以U前缀

AActor派生类都以A前缀

SWidget派生类都以S前缀

抽象接口以I前缀

枚举以E开头

bool变量以b前缀,如bPendingDestruction

其他的大部分以F开头,如FString,FName

typedef的以原型名前缀为准,如typedef TArray FArrayOfMyTypes;

在编辑器里和C#里,类型名是去掉前缀过的

UHT在工作的时候需要你提供正确的前缀,所以虽然说是约定,但你也得必须遵守。

UE官方推荐的资产命名规范:

https://docs.unrealengine.com/5.0/zh-CN/recommended-asset-naming-conventions-in-unreal-engine-projects/

VR

Set tracking origin站立式和半坐式

Attachment actor to component中attachmentRule:

Keep Relative保持原来的相对于父级的变换

Keep World保持自己的世界变换

Snap To Target将变换附加到目标的变换

在 VR 应用程序中,摄像机位置设置通常是通过改变摄像机的相对位移来实现的。当应用程序开始运行后,摄像机的位置通常会根据应用程序的需求进行调整,例如在游戏中,摄像机的相对位移可以根据角色的位置和移动来动态调整。

在 Unreal Engine 中,可以通过将摄像机组件放置在 VR 视口中,并设置其相对位置和旋转来控制摄像机的位置。摄像机的位置通常是相对于 VR 世界的原点(Origin)来定义的,因此摄像机的位置和旋转可以随着应用程序的运行而改变,以响应用户的交互、移动和其他操作。

需要注意的是,VR 应用程序中摄像机位置的设置和控制可能会受到许多因素的影响,例如用户的头部位置和姿态、VR 手柄的输入、场景中其他对象的位置和动态效果等等。因此,在设计和实现 VR 应用程序时,需要仔细考虑和测试摄像机位置的设置和控制,以确保良好的用户体验和交互效果。

剖析虚幻渲染体系-XR专题:https://www.cnblogs.com/timlly/p/16357850.html

Go to the outliner and select your SkyAtmosphere. In the details, choose “SkyAtmosphere (Instance)”, click “Add”, and add a Static Mesh. Click your new mesh, go to the Static Mesh property, and change it for SM_SkySphere. Click your new mesh, go to the Materials property, and where it says Element_0, change in the dropdown for SkySphereMaterial. In your content browser, go to All/Engine/Content/EditorMaterials/Thumbnails and open SkySphere Material.

In SkySphereMaterial, follow the comment

  1. In Details->Material->Blend Mode, Opaque不用改

  2. In Details->Material->Shading Model, default Lit -> Unlit

  3. In Details->Material (Advanced)->Is Sky, tick the box to mark as True

其实直接用BP_Sky_Sphere就行

物理

物理原理浅析

https://zhuanlan.zhihu.com/p/35686607

Swing1Motion Yaw

Swing2Motion Pitch

TwistMotion Roll

注意关节的默认轴向和关节的旋转范围是两个东西,关节可以前后旋转范围直接在swing1/2/twist里面调整数值即可,关节的默认轴向需要按住Alt键拖动轴向旋转后才可以生效,单独旋转不能修改默认轴向。

Set Simulate Physics和Set All Bodies Below Simulate Physics的区别

都是用于控制物体是否启用物理模拟的函数,并且会被视为动态物体被物理引擎影响并计算,但它们的应用场景不同。Set Simulate Physics适用于单个物体,而Set All Bodies Below Simulate Physics适用于包含多个子物体的物体,例如骨骼网格体。

Set Simulate Physics应用到骨骼网格体上时,效果和Set All Bodies Below(pelvis) Simulate Physics相似即:骨骼网格体不会与根组件脱离(root仍然跟随capsule但是因为root和pelvis约束是free的所以视觉感觉脱离了)

所以使用Set All Bodies Below(root,include self)Simulate Physics时才会与根组件脱离,因此在停止模拟后要重新将Skeletal Mesh Component attach到root component上

这三个效果一样mesh不会与root component脱离但是视觉效果是mesh不跟随capsule移动(body name是root)

这个pelvis不模拟物理所以挂在capsule上然后在约束下整个mesh跟随移动但是是物理模拟的

这个直接散开

问题:使用Set All Bodies Below Physics Blend Weight函数时,Blend Wight重置,mesh位置(transform)也会重置

即:将物理混合权重重置为1时,骨骼网格体回到了原来的物理模拟的位置重新进行模拟(混合状态重置,从新开始)。这是因为在物理混合权重为0时,骨骼网格体处于运动学控制,不存在物理模拟。如果物理混合权重正在1~0之间平滑变化,这时如果我们突然重置混合权重,比如从0.5突变为1,各骨骼的位置会瞬间从当前位置(物理模拟和运动学控制混合的位置)切回纯物理模拟计算的位置。(以上为猜测,但是可以这么理解,直接的解决办法是在设置物理混合权重之前保存每个骨骼网格体的当前位置。这样,当您重新启用物理模拟时,骨骼网格体将从当前位置重新开始模拟。暂时使用插值使Blend Wight平滑)

重新计算物理模拟可能会导致骨骼网格体出现抖动或者不稳定的情况。以下是一些可能有助于解决这些问题的技巧:(ChatGPT)

  1. 提高物理模拟的精度和步长。

在 Unreal Engine 4 中,您可以通过调整物理资产的精度和步长来提高物理模拟的精度。在骨骼网格体的物理资产中,您可以找到“Solver Iteration Count”和“Max Physics Delta Time”的设置。通过增加“Solver Iteration Count”或减小“Max Physics Delta Time”,您可以提高物理模拟的精度,从而减少抖动和不稳定性。

  1. 减少物理模拟实例的数量。

如果您的场景中有大量的物理模拟实例,可能会导致性能问题和不稳定性。您可以尝试减少物理模拟实例的数量,例如通过合并多个物理模拟实例或者使用关节连接多个物理模拟实例。

  1. 使用更高级的物理引擎。

Unreal Engine 4中的默认物理引擎是 PhysX,但是您也可以使用其他物理引擎,例如 Chaos(UE5默认)。这些物理引擎可能具有更高的精度和性能,从而减少抖动和不稳定性。

  1. 使用插值和平滑技术。

您可以使用插值和平滑技术来减少抖动和不稳定性。例如,使用“Interp To Movement”节点来平滑骨骼网格体的运动,或者使用“Smooth Interp”节点来平滑骨骼网格体的旋转。

  1. 碰撞体积和形状的设置。

如果碰撞体积和形状设置不当,可能会导致物理模拟出现抖动和不稳定性。您可以尝试调整碰撞体积和形状的设置,例如增加碰撞体积的分辨率或者使用更准确的碰撞形状。

在Apply Physical Animation Profile Below函数中切换物理的资产的Profile时需要调用Set Skeletal Mesh Component主要是清除已经存在的数据,否则即使切换Profile在游戏中依然使用之前设置的Profile

Set Strength Multiplier

设置Physical Animation Profile的乘数,设置的数字越大往动画矫正的力越大(参数不是很好调,使用Set All Bodies Below Physics Blend Weight函数感觉更灵活些但是这个函数和Physical Animation Profile无关)

动画

Save Pose Snapshot

等待一帧是为了确保在保存快照之前,所有的动画和姿势都已经被更新到最新状态。在游戏引擎中,动画和姿势通常是在每一帧的渲染循环中进行更新的。如果不等待一帧,就有可能会出现在保存快照时某些动画或姿势还没有被更新到最新状态,导致保存的快照不准确。假设在保存快照之前,某个角色正在执行一个动作,而该动作的更新是在下一帧进行的。如果不等待一帧,就有可能会在保存快照时捕捉到该角色的旧动作,而不是最新的动作。

重定向

创建IKRig,在里面添加链条(链条是一条没有分支的从起始骨骼到末端骨骼的链,要注意twist骨骼此骨骼的分支看不出来不添加此骨骼即可),两个对应的链条即使骨骼的数量不相等但只要链条对应的上就可以,动画复制过去不会出错,注意选择重定向根为pelvis

创建IKRetargeter, 选择原始骨骼,进入后可以选择目标资产,注意Tpose还是Apose

CurrentNetSpeed

当前的网络速度是一开始就初始化的,如果是局域网就读取配置中的局域网速度 ConfiguredLanSpeed,否则读取互联网速度 ConfiguredInternetSpeed。客户端连接过程中接收到消息 NMT_Welcome,会以初始化的网速发送 NMT_NetSpeed ,服务器接收 NMT_NetSpeed,并适当调整当前连接的网速。

通过阅读源码发现,当前网速是固定的,只在连接过程中同步客户端配置的网速,此后不再改变。

引擎默认配置的网速为每秒的字节数,比如默认配置中的网络速度10000,转换成通俗一点的网速是(10000 / 1024 = )9.76 kb/s ,局域网的会快一点。通常每个项目会根据需要修改合适的网速。需要特别说明的是,如果是重播相关的 UDemoNetDriver,初始化连接的时候会传入固定的网速1000000,相当于976 kb/s。

DefaultEngine.ini

[/Script/Engine.Player]

ConfiguredInternetSpeed=10000

ConfiguredLanSpeed=20000

杂项

Get Attach Parent Actor获取直系父组件

Get Owner获取拥有调用该函数组件的AActor

FlipFlop MultiGate蓝图执行流控制MultiGate可以做简单随机效果

模拟物理会脱离root component,要注意这个细节,如VR中拾取模拟物理的物体如果使用Attachment actor to component函数需要关闭物理模拟

UE小白人的pelvis在小白人仰视时x<0,z约等于180,俯视时x>0,z约等于0(即使其他资产pelvis的相对旋转不同,也是这样的)

Ue基础移动(deadzone变量)

https://zhuanlan.zhihu.com/p/628510656

当一个玩家更早地看到另一个玩家的身影或者通过较高的分辨率获得更快的响应时间时,该玩家可能有一种优势。尽管使用提供的可扩展设置不是欺骗,但是某些可扩展功能却可能被乱用于欺骗行为.一个游戏机变量提供的值的范围可能比该可扩展功能所需的值更广,者游戏机平台变量设置的组合都可能会导致问题。某些多玩家游戏,通过让服务器管理员来覆盖有问题的设置来为所有玩家来提供平等的机会,来解决这些问题。

示例:隐藏在深深的草丛中可能是很好的游戏策略。但是,如果视图距离较远就不渲染这些草丛了,那么对于那些尝试隐藏的玩家这可能是非常不公平的。

理想情况下,可扩展功能将不会影响游戏性。(游戏中的图形设置)

https://docs.unrealengine.com/5.2/zh-CN/scalability-and-the-developer-for-unreal-engine/

GameUserSetting的使用(设置分辨率,全屏模式,帧率,垂直同步等)

https://blog.csdn.net/u010385624/article/details/89926061

https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/GameFramework/UGameUserSettings/

经试验ApplyNonResolutionSettings也会保存

变换

Inverse Transform Direction

将给定的direction乘以transform从局部空间到世界空间转换的矩阵的逆矩阵,这个操作会将方向从世界空间转换到局部空间

Atan/Atan2函数

  • x– 代表 x 轴坐标的浮点值。
  • y– 代表 y 轴坐标的浮点值

atan2函数返回的是原点至点(x,y)的方位角,即与 x 轴的夹角。也可以理解为复数 x+yi 的辐角。如果返回值的单位为弧度,则取值范围为(-Π,Π]。

在数学坐标系中,结果为正表示从 X 轴逆时针旋转的角度,结果为负表示从 X 轴顺时针旋转的角度。

ATAN2(a, b) 与 ATAN(a/b)稍有不同,ATAN2(a,b)的取值范围介于 -pi 到 pi 之间(不包括 -pi),

而ATAN(a/b)的取值范围介于-pi/2到pi/2之间(不包括±pi/2)。

若要用度表示反正切值,请将结果再乘以 180/pi。

另外要注意的是,函数atan2(y,x)中参数的顺序是倒置的,atan2(y,x)计算的值相当于点(x,y)的角度值。

atan函数:

功能:求x(弧度表示)的反正切值。

说明:值域为(-π/2,+π/2)。

atan2 函数

功能:求y/x(弧度表示)的反正切值

Make Rot From…函数

https://www.cnblogs.com/weixiaodezhoubian/p/12844425.html (不懂的话里面有图)

Make Rot from X与Rotaion From X Vector(类似Find Look at Rotation)

使目标物体(将输出的rotation所赋予的物体)的x轴方向始终朝向我们给定的X向量(其实引擎会指定一个隐式的Z轴(0,0,1),用来保证XYZ三个轴向的平面正交)

Make Rot from XY

通过给定的X向量使物体的X轴指向某一个目标,Y轴也通过你输入的向量指向某个地方,再通过X,Y来确定Z轴(但是Y轴可能会有偏差,因为X轴朝向是固定的)

Make Rot from YX

通过给定的Y向量使物体的Y轴指向某一个目标,此函数是保证Y轴朝向不变的情况下,计算Z轴,修正X轴,以达到使Y朝向指定方向的目的。

Make Rot from XZ

保证X轴朝向不变的情况下,计算Y轴,修正Z轴,以达到使X朝向指定方向的目的。所以Y轴是由X和Z轴来确定

Make Rotation from Axes

等同于Make Rot from X

控制台指令

stat fps 查看当前帧率(ctrl+shift+h)

stat unit 查看cpu、gpu哪个慢了

Profile GPU 打开GPU查看器(ctrl+shift+,)

gc.CollectGarbageEveryFrame 1内存检测channel,垃圾回收器

trace.send localhost cpu,gpu,…启用Unreal Insights追踪

trace.stopped 停止跟踪

UE

UE智能指针

委托

https://zhuanlan.zhihu.com/p/460092901

Inside UE

game instance:在游戏生成时创建,并且在游戏关闭前不会销毁,在关卡之间持续存在

game mode:游戏的规则包括什么时候将玩家转移到新关卡中,怎么选择出生位置,gamemode有几个继承的函数可用于tracking player什么时候进入或离开游戏PostLogin和Logout

game state:保存关于游戏的状态信息而不是特定的信息,其中包含player state数组他们更旨在保存特定信息如得分,客户端可以访问游戏状态并获取此信息

game mode可以访问game state因此可以获得这个玩家状态数组并查看有多少玩家在游戏中

C++

inline, __forceinline

https://www.cnblogs.com/SoaringLee/p/10532267.html

__forceinline关键字则是不基于编译器的性能和优化分析而依赖于程序员的判断进行内联,但它也不保证一定内敛,有些情况函数是肯定不能内敛的。要慎用__forceinline,不加考虑的使用它将会造成代码量的膨胀而只得到很小的性能回报,甚至造成性能下降。

文章中介绍了一些情况,编译器不进行函数内联,即使是使用__forceinline

关键字noexcept

该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。

如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。

文章还有一些该关键字使用情况和一些语法如noexcept(noexcept(x.swap(y)))

https://www.cnblogs.com/sword03/p/10020344.html

打包问题

  1. 工程路径和命名问题

  2. 检查并修复关卡错误

打开每个关卡并运行,检查并修复错误(包括材质丢失、贴图丢失等)。

  1. 修复重定向资源

右键单击内容浏览器中的Contents文件夹,然后选择“Fix Up Redirectors In Folder”。

  1. 清理临时文件

从项目文件夹中删除Intermediate和Saved文件夹。

重新保存项目。

  1. 资源保存问题

如果无法保存资源,查看链接如何解决。

UE4 无法保存资产:https://blog.csdn.net/Deveuper/article/details/115389535

确保没有同时打开两个虚幻编辑器。

如果开了多个编辑器但桌面无显示,关闭后台偷跑的UE4服务。

https://blog.csdn.net/qq_21153225/article/details/84139186

  1. 安装并配置Visual Studio

无论是蓝图还是C++项目,都需要安装Visual Studio 2015/17/19/22。

在VS中安装所需的运行库,然后重启。如果重启后仍无法打包,尝试新建一个C++项目。

UE4打包 No required compiler toolchain解决:

https://blog.csdn.net/Deveuper/article/details/117309373

  1. 打包日志分析

在打包失败后,仔细阅读打包日志,找出导致失败的具体原因。

根据日志中的错误信息,进行相应的修复。

在打包前,确保项目中没有编译错误或警告。

仔细阅读错误日志,了解问题的根本原因并解决。

  1. 编译问题

确保在项目设置中选择正确的编译目标平台。

检查编译器设置和工具链(插件等),确保它们与虚幻引擎版本兼容。

  1. 选择正确的打包设置

输出打包时,建议使用ship版本,包体较小。(官方文档建议)

  1. Cook项目

如果不着急,先对项目进行cook操作,然后再进行打包。

  1. 打包注意事项

打包过程中,不要再操作UE4/5软件,也尽量避免在后台运行内存占用较高的软件。最好离开电脑。

  1. 插件或扩展包问题

检查并更新插件和扩展包至最新版本。

尝试禁用或删除不再需要的插件或扩展包。

  1. 硬件和性能问题

  2. 第三方库和依赖项问题

Delay函数(C++)

https://zhuanlan.zhihu.com/p/450322292 ( C++实现异步操作Delay,FLatentActionInfo)

(1).meta=(Latent):

该修饰符声明被修饰的函数是一个潜在的函数(异步函数)

(2).LatentInfo=”LatentInfo”:

(2_1).该修饰符配合Latent使用,为了声明哪一个参数是异步操作需要用到的参数.

其效果相当于将参数列表中LatentInfo的数值赋给了修饰符LatentInfo.

(2_2)这个修饰符与WorldContext修饰符非常像,WorldContext=”WorldContextObject” 同样是把参数WorldContextObject的值赋给了修饰符WorldContext.我们暂时将这种方式称之为”指定式赋值”

(2_3)它们都有一个特点,被”指定式赋值”的参数不会在蓝图中显示,此类参数会默认将调用该函数的对象自动传入到C++中.

void UKismetSystemLibrary::Delay(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo )
{
    //获得当前所在的world
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
        /*
        1. 通过World获取异步操作管理器FLatentActionManager,异步管理器管理异步操作列表,当进行异步操作时,先将异步操作加入到列表,然后将列表中的异步任务逐个执行
        2. 通过传入的LatentInfo相关信息,判斯当前请求的异步任务是否已存在,已经存在就不进行重复操作(Retriggerablebelay不同就是这,它是重置延迟时间)
        */
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
        //判断当前请求的异步任务是否已经存在
		if (LatentActionManager.FindExistingAction<FDelayAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL)
		{
            //若是新的异步操作,管理器通过AddNewAction将异步操作相关信息(保存在LatentInfo中),加入到执行列表
            //一旦加入进去,剩下的操作(如调回调函数等)引擎会自动完成。
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FDelayAction(Duration, LatentInfo));
		}
	}
}


// Delay execution by Duration seconds; Calling again before the delay has expired will reset the countdown to Duration.
void UKismetSystemLibrary::RetriggerableDelay(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo)
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
		FDelayAction* Action = LatentActionManager.FindExistingAction<FDelayAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
		if (Action == NULL)
		{
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FDelayAction(Duration, LatentInfo));
		}
		else
		{
			// Reset the existing delay to the new duration
			Action->TimeRemaining = Duration;
		}
	}
}

所以蓝图会有提示:倒计时再次调用并无效果

然后这个就会可能会有一些细节上的要点

比如:

可能会这么认为

但当Delay节点完成其延迟时间并继续执行后面的节点时,ForeachLoop节点如果还没有完成所有迭代,它将继续在同一个线程中执行。但是,Delay函数通过LatentInfo判断当前请求任务是否已经存在,如果已经存在,则不会再创建新的延迟任务,并且Delay节点后面的节点只会执行一次,而不是继续遍历数组中的剩余元素。

具体而言,当ForeachLoop节点执行到Delay节点时,它会将当前元素传递给Delay节点。在此期间,Delay节点会阻塞当前线程的执行,并等待指定的延迟时间结束后才会继续执行后面的节点。如果延迟时间非常短,并且ForeachLoop节点的迭代非常大,那么Delay节点的阻塞可能会导致其他线程在等待其完成时浪费时间。

当Delay节点完成其延迟时间并继续执行后面的节点时,它将在同一个线程中继续执行。但是,Delay函数通过LatentInfo判断当前请求任务是否已经存在,如果已经存在,则不会再创建新的延迟任务。因此,Delay节点后面的节点只会执行一次,而不是继续遍历数组中的剩余元素。如果ForeachLoop节点还没有完成所有迭代,它将继续在同一个线程中执行,但是Delay节点的延迟只会影响到当前元素,而不会影响到后续元素的处理。

然后,如果你想要在每个迭代中添加延迟,可以考虑将Delay函数放置在ForeachLoop节点内部。

或者下面的两种方法

异步操作封装为蓝图节点

UBlueprintAsyncActionBase

https://neil3d.github.io/unreal/bp-async.html#blueprint-async-action

https://xusjtuer.github.io/post/ue4-post8_async_bp_node_set_timer/

Get Component Velocity vs Get Physics Linear Velocity

Get Component Velocity如果他的父组件和他以相同速度移动则返回0

软引用

https://www.bilibili.com/video/BV1ZP4y1y7Pn?t=1243.5


对于本文内容有问题或建议的小伙伴,欢迎提出问题