平时随笔写下的一些UE4和VR开发中的技术笔记,以及一些相关资料的收录,之前零零散散放在imzlp.com/notes中,今天整理了一下,后续的笔记都会放到这篇文章中。
Engine Documents
UE4 Online Documents
- Unreal Engine API Reference
- Coding Standard
- Unreal Architecture
- Gameplay Framework
- Compiling Game Projects
- Asynchronous Asset Loading
- Online Subsystem Overview
- Start Commands
- Command-Line Arguments
- UPARAM
- UPROPERTY
- UFUNCTION
UE GamePlay Framework Tutorial
- Unreal Engine Gameplay Framework Primer for C++
- Gameplay Classes
- Gameplay Programming
- Actor Lifecycle
- This post in Russian (Unofficial)
VR Devices
UE适配不同VR设备的高度问题
在UE适配Oculus Rift和HTC Vive时注意把TrackingOrigin
(EHMDTrackingOrigin::Type)改为Floor
,不然默认的追踪起源是在眼睛位置,导致头盔位置在游戏场景中高度不对。
还有一个问题是,使用PlayerStart
放置时,PlayerStart
是有高度的,所以高度可能是不对的(取决于你的Pawn是怎么写的),解决的办法是可以重写AGameModeBase
的SpawnDefaultPawnAtTransform
,来指定高度。
UE中游戏启动VR头显初始化
1 | Stereo On/Off |
重置VR头显旋转和位置
因为VR头显默认的朝向X轴是与房间设置的定位有关的,所以,当我们初始就与定位时的朝向偏离时,进入游戏就会偏离我们设定让玩家看到的东西,所以需要进行修正。
可以使用以下函数:
1 | /** |
蓝图中也是同名的节点。
在UE中使用Oculus Rift
在Oculus Rift设备安装完成之后需要在Oculus商店中启用Unknow Source
,不然无法在UE中使用Oculus Rift预览。
Unreal的文档中适配Oculus Rift的页面:Developing for Oculus Rift.
Oculus官方提供的按键操作介绍:
以及Oculus Rift在UE中的按键映射:
HTC Vive的按键映射
与上面的Oculus Rift作为对比,附一张HTC Vive的按键映射:
HTC VIVE设备设置
SteamVR 2.0定位基站
HTC Vive Pro支持的定位器是SteamVR 2.0,支持150°和7米的追踪范围,而且支持基站串联(最多16个)实现大空间定位方案。
注意:二代基站不支持一代HTC Vive头显。
使用Proxifier让Oculus走SS代理
昨天公司买了台Oculus Rift设备,在安装设备时需要全局代理,在Windows下我使用的是Proxifier来让Oculus相关软件走代理。
首先先添加Proxifier的代理:
测试连接成功之后即可执行下列操作。
上面连接成功后可以添加一个代理规则,而Oculus程序相关的进程如下,我们需要做的是让下列的进程走SS的代理:
1 | OculusSetup.exe;OculusClient.exe;OVRServiceLauncher.exe;OVRServer_x64.exe;OculusVR.exe;OculusCompatCheck.exe;CompatToolCommandLine.exe;OculusLogGatherer.exe;OVRLibrarian.exe;oculus-driver.exe;OVRLibraryService.exe;oculus-overlays.exe;OVRRedistributableInstaller.exe; |
将上面的内容填入应用程序
文本框内之后,选择走SS的本地代理端口就可以了。
其他的程序(如外服游戏、Steam等),如果需要强制走SS代理也是同样的方法。
VR画面模糊的问题
因为UE项目中默认的Screen Percentage值是很低的,所以会感觉很模糊,但直接调高之后会有严重的帧率下降问题。
一般设置为200以内画面质量就不错了,下面列有UE的建议值(理想值)。然后需要美术在此基础上对场景进行优化,保证接近满帧的帧率。
在4.19之前(不含4.19),VR HMD建议的理想值(r.ScreenPercentage)为:
DeviceType | r.ScreenPercentage |
---|---|
Oculus Rift | 133 |
HTC Vive | 140 |
PSVR | 140 |
GearVR | 120 |
GoogleVR | 120 |
在4.19之后UE增加了vr.PixelDensity
,在r.ScreenPercentage
保持为100时,就可以在不同平台的设备上使用标准化的值:
DeviceType | r.ScreenPercentage | vr.PixelDensity |
---|---|---|
Oculus Rift | 100 | 1 |
HTC Vive | 100 | 1 |
PSVR | 100 | 1 |
GearVR | 100 | 1 |
GoogleVR | 100 | 1 |
Lower values will perform faster but will be undersampled (more blurry) while values over 1 will perform slower and will supersample (extra sharp).
这样就可以通过控制vr.PixelDensity
这个标准化的值来控制显示质量。
具体介绍链接:Significant Changes Coming To VR Resolution Settings in 4.19
HTC VIVE定位器故障(03)的解决办法
如果定位器面板上闪红灯且SteamVR显示**定位器故障(03)**,请试着手动烧录定位器(基站)固件。步骤如下:
固件路径在Steam的安装路径下:Steam\steamapps\common\SteamVR\tools\lighthouse\firmware\lighthouse_tx\archive\htc_2.0
,找到以下两个文件:
1 | * lighthouse_tx_htc_2_0-calibration-rescue-244.bin |
- 在定位器(基站)未通电情况下,将其通过micro-B USB传输线连接到电脑。
- 按住定位器(基站)背后的模式键并插入电源线.
- 一旦电脑端确认为USB大容量存储设备(USB mass storage device),才可以释放模式键。
- 被连接的定位器(基站)储存设备名为“CRP_DISABLED”,打开后包含一个文件“firmware.bin”,删除它。
- 将“lighthouse_tx_htc_2_0-calibration-rescue-244.bin”文件复制到基站的储存空间上。
- 复制完成后,拔掉电源线。
- 等几秒,然后再次插上电源。在此过程中不要按模式键。几秒后定位器(基站)应该会快速的闪烁绿灯或者红灯。绿灯表示修复成功。
- 如果它闪烁红灯,这表示不能自动修复,请您送修。
- 再次拔下电源。
- 重复步骤1到7,但第5步复制文件改为“lighthouse_tx_htc_2_0-244-2016-03-12.bin”。
- 完整后定位器(基站)就恢复正常了,讲其频道设置为“A”并单独跟踪(另一个基站不通电)来确认运行情况。一旦确认工作正常,再打开另一个基站。
如果出现闪烁绿灯无法正常使用,重复步骤1到7,但在第五步清除”CRP_DISABLED”中所有文件,只复制 “lighthouse_tx_htc_2_0-244-2016-03-12.bin” 即可。
- 如果手动烧录定位器(基站)固件和校准文还是无效,请使用手机拍照确定下列两个雷射点是否正常(不能用iphone/ipad雷射点拍不出來),如果这两个雷射点任一个没有显示,代表雷射损坏,请送客服检查。
参考链接:定位器故障(03)
Engine Analysis
UE Game的启动
游戏的初始化是从UGameInstance::StartGameInstance
开始的。
通过FEngineLoop::Init()
中调用GEngine->Start()
多态调用到UGameEngine::Start()
中调用GameInstance->StartGameInstance();
:
UE中Actor初始化
AActor的PreInitializeComponents
/InitializeComponents
/PostInitializeComponents
以及DispatchBeginPlay
均在ULevel::RouteActorInitialize中调用。
1 | void ULevel::RouteActorInitialize() |
UE4:Engine Start Order
UE引擎的Tick调用栈(call stack)
1 | FEngineLoop_Tick=>start: void FEngineLoop::Tick() |
Game Flow on UE4
Actor LifeCycle
Actor Lifecycle on Unreal Engine
UE Log macro defined
UE源码中的一些Log定义:
EngineLogs.h中定义了这些Log:
1 | ENGINE_API DECLARE_LOG_CATEGORY_EXTERN(LogPath, Warning, All); |
CoreGlobals.h中定义了下面这些Log:
1 | CORE_API DECLARE_LOG_CATEGORY_EXTERN(LogHAL, Log, All); |
最近用到的一些Log定义地方一并贴出:
1 | // Module: Json |
UBT代码分析:检测是否为安装版引擎的方法
在EpicGameLauncher安装的引擎版本是不能通过UnrealBuildTool.exe -ProjectFiles "ProgramProjectName"
来创建TargetProgram
的项目的,会提示下列错误:
1 | ERROR: UnrealBuildTool Exception: A game project path was not specified, which is required when generating project files using an installed build or passing -game on the command line |
这个异常在UBT里的相关代码在ProjectFileGenreator.cs
:
1 | // ProjectFileGenreator.cs |
可以看到,if
这里如果传递给UBT-game
参数并且是引擎是安装版本(EpicGameLauncher)时会检测有没有传入project
参数,如果没有就会抛异常。
正常的UBT调用命令:
1 | UnrelBuildTool.exe -ProjectFiles -project="D:\UnrealProjects\UEProject.uproject" -game |
这种普通的Game参数在UBT里面是不会抛异常的。但是用生成Program的命令来调用UBT,安装版引擎就会抛异常:
1 | UnrelBuildTool.exe -ProjectFiles ProgramName |
根据上面ProjectFileGenreator.cs
的检测代码,我们要做到的是把UnrealBuildTool.IsEngineInstalled()
获取的结果变为false.
继续跟代码:UnrealBuildTool.IsEngineInstalled()
获得的是UnrealBuildTool
中的一个bool变量bIsEngineInstalled
:
1 | // UnrealBuildTool.cs |
查找引用发现在GuardedMain
里有设置bIsEngineInstalled
这个变量的地方:
1 | // UnrealBuildTool.cs |
从代码可以看到,UBT对是不是安装版引擎的检测有三种方法:
- 传入参数是否有
-installled
和-installedengine
- 传入参数是否有
-notinstallengine
- 判断引擎路径
Engine\Build
下是否具有InstalledBuild.txt
文件
(说是三种其实也就是两种,就算指定了-notinstallengine
也是要判断存不存在Engine\Build\InstalledBuild.txt
这个文件)
而且检测的顺序是这样的:
1 | -installled > -installedengine > -notinstalledengine > Engine\Build\InstalledBuild.txt |
所以,当我想要让UBT认为我的引擎版本不是安装版,有两种办法:
- 对UBT的调用传入
-notinstalledengine
参数,并且删掉Engine\Build
目录下的InstalledBuild.txt
文件 - 对UBT的调用不传入
-installled
和-installedengine
参数,并且删掉Engine\Build
目录下的InstalledBuild.txt
文件
注:UBT里还有下面两种检测:
1 | // UnrealBuildTools.cs |
UE:Get all registed Engine
可以使用IDesktopPlatform::EnumerateEngineInstallations
来获取当前系统中所有从启动器安装、以及用户使用UnrealVersionSelector
注册的引擎版本。
1 | TMap<FString,FString> Installations; |
UnrealVersionSelector注册引擎路径
使用UnrealVersionSelector注册引擎时,会将注册的引擎路径写入到注册表:
1 | HKEY_CURRENT_USER\SOFTWARE\Epic Games\Unreal Engine\Builds |
其注册表项的lpValueName
则是生成的一个GUID:
1 | // DesktopPlatfromWindows.cpp |
UE并没有直接在IDesktopPlatfrom
中单独提供获取用户通过使用UnrealVersionSelector注册的引擎列表。
但是在EnumerateEngineInstallations
中写了从注册表获取per-user installations
引擎:
1 | void FDesktopPlatformWindows::EnumerateEngineInstallations(TMap<FString, FString> &OutInstallations) |
EpicGameLauncher版引擎注册表路径
上面提到,如果非源码版引擎,使用UnrealVersionSelector注册时会写入到注册表:
1 | HKEY_CURRENT_USER\SOFTWARE\Epic Games\Unreal Engine\Builds |
从EpicGameLauncher安装的版本则会写入到另一个注册表路径下:
1 | HKEY_LOCAL_MACHINE\SOFTWARE\EpicGames\Unreal Engine |
其值为(从注册表导出的):
1 | Windows Registry Editor Version 5.00 |
UE提供了方法来得到从EpicGameLauncher安装的引擎(通过IDesktopPlatfrom
接口):
1 | TMap<FString,FString> Installations; |
UnrealVersionSelector的注册表文件关联
1 | Windows Registry Editor Version 5.00 |
注:如果想要为自己定义的文件加上启动方式,也可以使用这种方式。
UE注册编译版引擎的安装路径
UE提供了UnrealVersionSelector
工具用来选择引擎版本/生成sln等功能,其也可以用来注册本地的引擎(非Launcher安装的引擎,如自己编译的源码版引擎)到项目文件的右键Select Unreal Engine Version...
列表中。
简单分析了一下UnrealVersionSelector
的代码,它的注册流程如下:
1 | WinMain_Func=>start: WinMain |
向注册表写入的操作在FDesktopPlatformWindows::RegisterEngineInstallation
这个函数中。
操作为将注册的引擎目录写入到HKEY_CURRENT_USER\Software\Epic Games\Unreal Engine\Builds
中的字符串项中。
当右键Switch Unreal Engine Version...
的时候,会修改.uproject
文件中的EngineAssociation
值:
其调用流如下:
1 | WinMain_Func=>start: WinMain |
执行项目文件写入的操作在FDesktopPlatformBase::SetEngineIdentifierForProject
中:
1 | bool FDesktopPlatformBase::SetEngineIdentifierForProject(const FString &ProjectFileName, const FString &InIdentifier) |
所以如果你选择了一个项目使用编译版引擎,可以使用文本编辑器打开该项目的.uproject
文件,可以看到其中的EngineAssociation
项的值就是注册表中的引擎版本值。
注:UnrealVersionSelector所支持的命令行参数及其用途在UnrealVersionSelector.cpp#L224:
1 | int Main(const TArray<FString>& Arguments) |
解决.uproject右键生成失败
首先要查看右键菜单所使用的UnrealVersionSelector.exe
的路径,可以打开注册表:
1 | HKEY_CLASSES_ROOT\Unreal.ProjectFile |
然后找到shell\open\command
条目查看UnrealVersionSelector.exe
的位置(如果没有安装过源码版引擎则默认在EpicGamesLauncher的Binaries路径下),如:
1 | "C:\Program Files (x86)\Epic Games\Launcher\Engine\Binaries\Win64\UnrealVersionSelector.exe" /editor "%1" |
然后打开C:\Program Files (x86)\Epic Games\Launcher\Engine\Binaries\Win64
,将UnrealVersionSelector.exe
设置为以管理员权限启动即可(右键-属性-兼容性-以管理员身份运行此程序)。
GamePlay
UE宏库的问题
在UE蓝图中使用宏库,在编辑了宏库里面的宏之后,只保存宏库是没用的,必须在用到宏库的蓝图里编译一遍才会生效,相当于蓝图里面的编译才会直接展开宏,否则还是原来未修改之前的版本,这问题实在太操蛋了。
在UE4.18.3问题存在,其他版本没试。
UE使用Shipping模式打包的Saved目录
UE项目在工程和Develement
或DebugGame
打包出来的Saved
目录均包含在项目目录
或打包到的目标目录
下,其中包含Autosaves
/Backup
/Config
/Logs
/Crashs
/SaveGames
等等。
但是使用Shipping打包的不同,使用Shipping打包出来的游戏,Saved目录并不在打包到的目标目录下
,而是在C:/User/%username%/AppData/Local/ProjectName
下,ProjectName
替换为你的项目名。
更多关于UE打包的内容可以看UE的文档:
CharacterMovement开启RVO避障
CharacterMovementComponent
具有自动避障的功能,只需要启用UseRVOAvoidance
。
但是记得在角色死亡之后关闭RVO的壁障,不然会导致怪物在空地上避障的问题。
可以使用SetAvoidanceEnable
来关闭。
VR弓的模型标准
VR中需要用的弓为SkeleMesh,模型的root骨骼点要位于抓取的位置(最好是弓箭握持中心点),而且为了程序计算方便模型方向要求下图:
这是为了方便计算VR玩家抓取弓到手上时的旋转计算:
拉弓时抓弓的手提供Roll的旋转,Pitch与Yaw则由抓弓的手LookAt到拉弓的手所需要的旋转提供。
所有的弓使用相同的模型旋转标准,这点美术上很好实现,如果不同程序调整上很麻烦。
而且箭的模型原点要在箭羽尾部:
做一把体验好的弓是个挺麻烦的事,重要的就是细节优化。
UE换装的一个实现
在UE的USkinnedMeshComponent中有这样一个函数:
1 | class ENGINE_API USkinnedMeshComponent : public UMeshComponent |
大概意思就是让当前的SkinnedMeshComponent
随着NewMasterBoneComponent
的姿态运动。
我们可以使用一组使用相同骨骼的模型来实现换装的功能,比如说头部、胸部、腿、脚、双手,让一个角色具有这五个单独的USkinnedMeshComponent
模型组件来表示不同的部位。
让角色有一个带有动画的USkinnedMeshComponent
当作身体,然后将上面的五个USkinnedMeshComponent
的MasterPose
设置为它。
此时各个部位都会随着身体的动画运动的,实现换装就直接修改各个部位的模型就可以了。
从蓝图编译到C++代码
UE支持从蓝图编译到C++代码,需要在Project Setting
-Packaging
-Blueprints
里选择Exclusive
(只有选择的蓝图资源会生成C++)或者Inclusive
(为所有的蓝图资源生成C++)。
选择之后打包项目,打包成功后可以在项目的Intermediate\Plugins\NativizedAssets\Windows\Game\Source\NativizedAssets
路径下的public
/private
目录里找到以蓝图名字开头的.cpp
与.h
文件。
UE蓝图函数库无法在UObject对象中调用
在编辑器中创建一个蓝图函数库(Blueprint Function Library)并创建一个函数,该函数是不能在蓝图的Object
中调用的,会提示:
1 | Function Requires A World Context. |
写一个测试的蓝图函数库生成C++代码:
生成的C++代码如下(移除多余的部分,全部的代码可以在这里查看):
1 | // TestFuncLib_pf1448227310.h |
直接把上面的代码抄到一个C++的蓝图函数库里是可以在UObject的对象中调用的…这就有毒了。
UE中放置组件到骨骼插槽(socket)
在蓝图中直接可以在蓝图编辑器中设置parent socket
属性来将一个组件放置到骨骼插槽中。
在C++中也一样,不过略微麻烦一点,来看一下ShooterGame中的代码示例:
1 | // ShooterGame\Private\Weapons\ShooterWeapon.cpp |
同样是用的也是AttachToComponent,蓝图中也可以用相同名字的蓝图节点来attach到骨骼插槽上。
Unreal中获取OpenLevel的Options
在UE中加载关卡时,可以传一个FString
的Options过去:
在被加载的关卡中可以通过GetGameMode
来获取:
使用C++的代码是这样:
1 | AGameModeBase* OurGameMode=UGameplayStatics::GetGameMode(this); |
注意:在切换关卡后,原关卡中创建出来的对象都会被销毁,解决的办法是使用GameMode的GetSeamlessTravelActorList
来留存指定的Actor在切换关卡时不会被销毁。
转换游戏场景中的3D位置到屏幕位置
设置鼠标的光标在viewport内的相对位置
首先安装LowEntry-ExtendedStandardLibrary这个插件,可以使用其中的ULowEntryExtendedStandardLibrary::SetMousePosition
函数来设置鼠标的光标在viewport内的相对位置,viewport的大小可以通过UWidgetLayoutLibrary::GetViewportSize
来获取。
UE启动游戏后鼠标焦点不在窗口内
可以使用SetInputModeGameAndUI
来设置鼠标的焦点在窗口内,InMourseLockMode
设置为LockAlways
即可。
在启动游戏时使用这个操作就可以在开始游戏时鼠标的焦点就在游戏窗口内,从而避免想要点击窗口上的UI需要先点击一遍游戏窗口。
判断一个特效是否循环
从一个UParticleSystem
的Emitter
的Required
的Emitter Loops
为0则是循环特效:
UE提供了方法可以判断一个特效是不是循环特效:
1 | bool UParticleSystem::IsLooping()const{ /*...*/ } |
只要该特效里有一个循环的Emitter,则该特效就是循环的。
但是该方法没有暴露给蓝图,可以写个函数库封装给蓝图。
跨模块使用类注意是否导出符号
在继承/访问UE引擎内的类时,一定要注意类是否具有导出符号,没有导出符号的类是没办法链接到定义的。
如UEEngine
模块下的FParticleSpriteEmitterInstance
这个类就是没有导出符号的。
Blueprint创建异步节点
在工程中有一些异步操作的需求,比如下载文件的行为,一个下载命令等待下载完成之后回调,而且要尽量避免太多的事件绑定和解绑操作。
在蓝图的节点中有一些异步的操作,比如PlayMontage
/DownloadImage
等,都是异步操作中有多个输出节点的:
我们能不能自己写一个这样的异步操作的节点呢?那必然是可以的。
可以在Engine\Source\Runtime\UMG\Public\Blueprint\AsyncTaskDownloadImage.h
中查看DownloadImage节点的实现(C++API)。
可以自己仿照这自己写一个出来:
- 关键就是要继承
UBlueprintAsyncActionBase
,这个是必须的。 - 然后写一个
static
的函数,返回类的指针,并用UFUNCTION
的mate
标记为BlueprintInternalUseOnly="true"
- 声明并定义几个派发器成员,这些派发器成员就是异步的节点,也就是蓝图节点右侧的exec节点。
我们先来看一下DownloadImage
的声明:
1 | class UTexture2DDynamic; |
对比上面的DownloadImage的节点,可以看到:
0. 首先声明了一个动态多播代理FDownloadImageDelegate
,并且需要传入一个参数
UAsyncTaskDownloadImage
类中声明了两个事件派发器OnSuccess
和OnFail
,这也是蓝图节点右侧的Exec和参数Texture
,本质都是派发器(动态多播代理)UAsyncTaskDownloadImage
的static
函数DownloadImage
接收一个FString的参数,返回一个UAsyncTaskDownloadImage*
,这个返回就是把派发器的执行节点在蓝图中显示出来
即:声明的动态多播的成员和该多播的参数都会显示在蓝图节点的右侧。
我自己实现了一个异步行为的操作,先在蓝图中看操作:
行为就是,先创建一个AsyncActionObject
的对象作为后期触发异步操作的对象,然后执行CreateAsyncTask
里面对上一步创建的AsyncActionObject
进行事件绑定。
然后我们就可以在那个ActionObj调用OnActionStart
之类的操作就可以调用CreateAsyncTask
右侧的相关节点。
注意:我做的限制是,一个对象对应一个Task,如果当前传入的AsyncActionObject
正在被其他的task绑定,则创建task会失败。
然后就是代码:
1 | // AsyncTask.h |
然后是实现:
1 | // AsyncTask.cpp |
AsyncActionObject类的声明:
1 | // AsyncActionObject.h |
以及它的实现:
1 | // AsyncActionObject.cpp |
其实就是本质上裹了两层派发器而已…
举个例子的用途:可以在行为树里监听某个动画被终止或者结束了之后然后再执行其他的行为,可以解决不同模块之间之间的耦合。
UE引用windows头文件的警告/错误
如果你在UE中使用了windows.h
在VS可能会爆出4668这样的错误,在之前的UE版本中是警告,但是在UE4.18变成了错误,UE本身对windowsAPI的头文件做了封装,可以包含相应的:
1 |
|
或者不用这个办法,使用:
1 |
也是可以的.
而且,如果你在代码里用到了WindowsAPI,如windows.h
等.
可能会遇到下面类似这样的错误:
1 | 1>C:\Program Files\Epic Games\UE_4.15\Engine\Source\Runtime\Core\Public\Async/TaskGraphInterfaces.h(892): error C2039: '__faststorefence': is not a member of 'FWindowsPlatformMisc' |
解决这个问题的办法是把这些windowsAPI的头文件不要在UE的头文件中包含,移动到使用这些windowsAPI的.cpp中即可.
UE获取光标在窗口的相对比例
首先先要获取当前的窗口大小,可以通过UGameViewportClient
获得SWindow
,进而可以通过SWindow::GetSizeInScreen
得到窗口的大小:
1 | void GetWindowSize(bool& Success, int32& Width, int32& Height) |
然后得到光标在当前窗口的位置,可以通过APlayerController::GetMousePosition
来得到(其实他也是通过Viveport来得到的):
1 | bool APlayerController::GetMousePosition(float& LocationX, float& LocationY) const |
然后两者相除即可得到鼠标在当前窗口的相对位置。
UE SceneCapture2D捕获的gamma值
在使用USceneCapture2D
捕获画面到RenderTarget
使用Spectator Screen
再贴到屏幕上时发现颜色不对:
解决的办法是:
- 设置SceneCapture2D的
CaptureSouce
为Final Color (LDR) in RGB
- 设置RenderTarget资源的Gamma值为
2.2
就看起来和原图十分接近了
蓝图Event参数的一个骚操作
在一些插件中看到了类似这种的操作:
其实实际上,Unreal蓝图的事件节点(Event)的参数是类的成员变量(data member of class),所以可以在其他的地方直接使用他的参数。
类似的问题还有delay的操作:
UE使用UProjectileMovementComponent的碰撞检测问题
在UE中使用UProjectileMovementComponent弹射组件来做一些比如弓箭之类的功能,可能会因为速度太快的原因导致碰撞无法被触发。
记录一下这个问题留待后面研究。
Config and Editor
修改UE的编辑器模式下的Esc退出快捷键
打开Editor Preferences
-Keybord Shortcuts
修改Play World(PIE/SIE)
的按键即可。
UE在编辑器中显示插件的Content
修改UE编译时的parallel数量
修改下列文件:
1 | Engine/Saved/UnrealBuildTool/BuildConfiguration.xml |
如下:
1 |
|
MaxProcessorCount
即是修改本地执行的最大处理器数。
更多的confiuration参数可以看:UBT configuration
UE Android打包将数据存放在obb文件中
UE编辑器模式下焦点不在窗口内的卡顿
在Windows平台上运行UE时如果在编辑器内Play游戏,若当前的焦点不在编辑器/VR应用内,会减少对CPU的占用,从而出现卡顿的问题(打包出来不会出现这个问题)。
其实是因为UE在编辑器环境下做了不在焦点内的检测:
1 | // Runtime/ApplicationCore/Private/Windows/WindowsPlatformApplicationMisc.cpp |
只需要把FPlatformProcess::Sleep(0.005f);
这一行注释掉就可以了。
Win10下解决UE编辑器内编译日志的中文乱码
注意:可能会出现某些软件内的编码问题(如GBK编码出现烫烫烫/锟斤拷等)。
Package
ObservedKeyNames.Num()>0
解决详情具体看:UE Package Error:ObservedKeyNames.Num()>0
UE Package Error:RenderDocPlugin
RenderDocPlugin: Error: unable to initialize the plugin because no RenderDoc libray has been located.
解决办法:打包之前禁用掉RenderDocPlugin这个插件。
UE4打包32bit要求16byte对齐错误
在引擎中选择32bit平台打包的时候会出现下列错误:
1 | error C2719: 'SpawnTransform': formal parameter with requested alignment of 16 won't be aligned |
这是因为在代码里使用pass-by-value的方式传递了FTransform
:
1 | AProps* SpawnProps(FTransform SpawnTransform); |
因为FTransform要求使用16byte对齐:Math/TransformVectorized.h#L36
1 | MS_ALIGN(16) struct FTransform |
MS_ALIGN
这个宏是在Core/Public/Windows/WindowsPlatform.h#L131中定义的:
1 | // Alignment. |
所以FTransform
要求的是16byte对齐。
FTransform is implemented using vector intrinsics, and instances of it need to have 16-byte alignment. I think the stack is guaranteed to be aligned to 16-bytes on Win64 so the compiler can pass it on the stack correctly, but there’s no such guarantee on Win32 (which is what we use for shipping builds).
那么改为传递指针或引用就可以了(传引用和传指针均是sizeof(void*)
的大小):
1 | AProps* SpawnProps(const FTransform& SpawnTransform); |
相关问题:
- Shipping: formal parameter with declspec(align(‘16’)) won’t be aligned
- FVector4 error not usable with x32 game package
UE打包时提示文件占用导致打包失败
- 引擎版本:4.18.3
- 打包平台:Windows
- 运行模式:VR
- BuildConfiguration: Shipping
打包中的错误信息log:
1 | UATHelper: Packaging (Windows (64-bit)): Program.Main: ERROR: AutomationTool terminated with exception: System.IO.IOException: The process cannot access the file** ‘C:\YourProjectPath\Saved\StagedBuilds\WindowsNoEditor\Engine\Extras\Redist\en-us\UE4PrereqSetup_x64.exe’ **because it is being used by another process**. |
UE打包时的错误提示为is being used by another process的原因是进程里也启动了EpicGameLauncher,打包之前把它关掉就可以了。
Online
UE Actor Replication Config
Replication
OnlyRelecantToServer(default false)
if true,this actor is only relevant its owner,if this flag is changed during play,all non-owner channels would need to be explicitly close.
Always Relevant(default false)
Always relevant for network(overrides bOnlyRelevantToOwner)
ReplicateMovement(default true)
if true,replicate movement/location related properties.
Actor must also be set to replicate.
- see SetReplicates()
- see https://doc.unrealengine.com/latest/INT/Gameplay/Networking/Replication/
NetLoadOnClient(default true)
This actor will be loaded on network clients during map load.
NetUseOwnerReplovancy(default false)
If actor has valid Owner, call Owner’s IsNetRelevantFor and GetNetPriovity
Replicates(default true)
if true,this actor will replicate to remote machines
see SetReplicates()
NetDormancy(default DORM_Awake)
Dormancy setting for actor ro take itself off the replication list without being destory on clients.
1 | // This actor can go dormant,but is not currently dormant,Game code will tell it when it go dormant. |
NeuCullDistanceSquared(default 225000000.0)
Suqare of the max distance from the client’s viewpoint that this actor is relevant and will be replicated.
NetUpdateFrequency(default 100.0)
how often(per second) this actor will be considered for replication,used to determine NetUpdateTime.
MinNetUpdateFrequency(default 2.0)
Used to determine what rate to throttle down to when replicated properties are changing infrequently.
NetPriority: (default 3.0)
Priority for this actor when checking for replication in a low bandwidth or saturated siuation,higher priority means it is more likely to replicate.
Replicated Movement
LocationQuantization Level: (default EVectorQuantization::RoundTwoDecimals)
1 | enum EVectorQuantization |
VelocityQuantization Level: (default ERotatorQuantization::RoundWholeNumber)
1 | enum ERotatorQuantization |
RotationQuantization Level(default ByteComponents)
Allow turing the compression level for replicated rotation.You should only need to change this from the default if you see visual artfacts.
1 | enum ERotatorQuantization |
UE编辑器内测试多人时禁用自动连接
使用UE联网的部分问题
UE里提供了AController::IsLocalControlled
来判断当前控制器控制的是否是本地实体:
1 | bool AController::IsLocalController() const |
注意:千万谨慎不要在Pawn里使用
AutoPossessPlayer
选项。这会使加入进来的玩家的Controller自动作为Player0,造成奇葩的bug.
还有UKismetSystemLibrary::IsServer
/UKismetSystemLibrary::IsDedicatedServer
,他们获取的都是当前World
的GetNetMode
来判断的:
1 | bool UKismetSystemLibrary::IsServer(UObject* WorldContextObject) |
enum ENetMode
的成员及其含义如下:
Name | Descript |
---|---|
NM_Standalone | Standalone: a game without networking, with one or more local players. |
NM_DedicatedServer | Dedicated server: server with no local players. |
NM_ListenServer | Listen server: a server that also has a local player who is hosting the game, available to other players on the network. |
NM_Client | Network client: client connected to a remote server. |
NM_MAX |
使用UE的OnlineSubsystem联网
UE的联网可以通过CreateSession
/FindSeccsion
/JoinSession
来实现,但要先进行一些简单配置。
编辑Config\DefaultEngine.ini
,加入以下内容:
1 | +NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="/Script/OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="/Script/OnlineSubsystemUtils.IpNetDriver") |
注意和对接Steam的不同,要把DefaultPlatformService
改为Null
,不然无法加入Session.
UE联网客户端没有寻路
需要在Project Settings
-NavigationSystem
里设置Allow Client Side Navigation
为true
:
UE的Session在LAN中搜索不到
使用UE的CreateSession
创建,然后在LAN的另一台机器上使用FindSession
无法找到Session列表。
出现这个问题的原因是电脑上装了VM或者VirtualBox之类的虚拟机,需要把VMware Network Adapter
或者VirtualBox NetWork Adapter
禁用掉就可以了。
在控制面板的具体位置为控制面板/网络和Internet/网络和共享中心/更改适配器设置
:
Other Script
UE莫名其妙的编译和链接错误
修改代码后最好把下面的文件删了:
1 | Binaries |
bat脚本如下:
1 | del *.VC.db |
还有搜索所有插件目录的Binaries和Intermediate:
1 | $ find . -name "Binaries"|xargs rm -rf |
Profiling Commands
显示FPS
1 | stat FPS |
显示统计单元(每帧的总时间,逻辑线程/渲染线程和GPU的时间消耗):
1 | stat Unit |
显示渲染线程中的各种参数值
1 | Stat SceneRendering |
显示渲染线程命令的消耗
1 | stat RenderThreadCommands |
显示游戏线程上的参数(AI/物理/动画/蓝图/内存分配等)
1 | stat game |
显示剔除所需的时间和效率数据
1 | Stat InitViews |
显示照明和着色所需的渲染时间
1 | Stat LightRendering |
抓取当前帧的GPU信息
1 | ProfileGPU |
会弹出GPU Data Bisualizer
的GPU Visualizer
显示抓取帧的数据。
抓取Profiling信息(CPU/GPU)
1 | stat StartFile |
会在项目的Saved/Profiling/UnrealStats
下产生*.ue4stats
文件,可以使用UnrealFornted打开。
UE网络分析
1 | # 打开和关闭录制 |
捕获的数据保存在Saved/Profiling
下,后缀名为*.nprof
。
UE网络分析(Network Profiler)工具的文档Network Profiler.
链接: