功能介绍
从Unreal Engine 4.23版本开始,新增了WebRemoteControl模块,在引擎中开启一个网络服务,通过类REST API发送http请求将指令发送到引擎中,从而实现远程控制。
这一模块可以用来制作第三方平台,比如GM工具,实时展示游戏参数和调试运行中的游戏;或者虚拟制片,如官方演示视频中展示的界面一样,将常用功能集成到网页或者APP面板中方便调用。
主要有两种调用方式:
- 获取/设置object的公开到蓝图和python的属性
- 调用公开到蓝图和python的函数
后面的功能演示使用了Unreal Engine 4.24版本,其他版本可能有差异。
功能开启
首先点击菜单Edit>Plugins打开插件窗口,启用Remote Control API插件。
启用后如果提示需要重启则重启引擎。
第二步,打开测试项目后,点击菜单Window>Developer Tool>Output Log打开输出日志窗口,确认左下角为CMD模式(还有一个python模式可以用来执行python命令),输入控制台命令WebControl.StartServer
,执行成功结果如下。
然后即可发送请求命令进行远程控制了。
需要注意的是网络服务器监听本地8080端口,需确保此端口不被防火墙拦截,控制端可以访问该端口。
另外要注意的一点是在4.24版本中,默认开启本地回环地址(127.0.0.1)和网络地址(本地连接ip)的8080端口,而在4.25版本中,默认只开启本地回环地址(127.0.0.1)的8080端口,会导致只能在本地调用而从其他电脑上无法远程调用网络服务。
解决的办法是修改一个配置文件,路径是Engine\Config\BaseEngine.ini
,在这个文件中加上下面的配置信息,IP改为本地连接的IP就可以在其他电脑上远程调用了。
[HTTPServer.Listeners] DefaultBindAddress=IP
不过这样写会导致本地回环地址反而不能使用该服务了,emmm。
除了开启网络服务的WebControl.StartServer
控制台命令,还有其他两条相关命令,分别是关闭网络服务WebControl.StopServer
和网络服务自动启动WebControl.EnableServerOnStartup
(保存到项目配置中,每次打开该项目时自动打开网络服务)。
API调用方式
使用专门用于测试API请求和响应的工具,例如Postman 或Insomnia ,我比较习惯使用Postman,这里就不详细说Postman的用法了,自行搜索即可。
获取Object的属性
上图所示为获取当前关卡中环境球(世界大纲视图中名为SkySphere的Actor)上的旋转(RelativeRotation)属性值。
需要注意的是,请求方式必须为PUT
,正文格式必须为JSON
(默认为Text),目标地址为http://ip:8080/remote/object/property
,发送结果为200 OK
并且得到返回的结果说明执行成功。
参数解释
请求正文中的三个参数分别是objectPath
(关卡中的物体)、access
(读写权限)、propertyName
(属性名)。
其中objectPath为虚幻引擎对加载到内存中的每个资源和Actor的唯一标识路径,遵循以下格式:
/path/PackageName.ObjectName:SubObjectName.SubObject
资产(uasset)的ObjectPath可以通过在内容浏览器窗口(Content Browser
)中右键该资产菜单中Copy Referrence
,即可获得。
对于关卡中的物体(Uobject),可以通过以下两种方法获取。
第一种是通过修改该物体,然后查看撤销历史窗口(Edit>Undo History)获得该路径,需要打开右下角的显示事务细节(Show transactions details)。
鼠标悬停在已修改对象和属性(Modified objects and propertyies)列的条目上,提示文本即为对应的ObjectPath。
这种方法既可以获取到关卡中的物体(Uobject)路径,也可以获取到资产(uasset)路径。
第二种方法是通过调用蓝图函数获得当前关卡中所有Actor的路径,后面再详细介绍。
第二个参数access有三种类型,READ_ACCESS
为读取物体上的属性,WRITE_ACCESS
和WRITE_TRANSACTION_ACCESS
为修改物体上的属性,两者的区别是WRITE_TRANSACTION_ACCESS
会在项目的事物历史中记录属性值的修改。
可以理解为WRITE_ACCESS
方法虽然修改了参数,但在不会立即影响当前关卡,而WRITE_TRANSACTION_ACCESS
可以立即看到参数修改的结果,与在细节面板(Details)中修改参数相同,会调用更多链接到该属性的更改前和更改后相关代码。
因此在实际使用中,更多使用WRITE_TRANSACTION_ACCESS
类型。
第三个参数为propertyName
(属性名),即想要读取或修改的属性名,当第二个参数access为READ_ACCESS
时,可以省略属性名参数,这样返回的结果是当前物体的所有属性列表。
当不知道要读取的属性的代码时,可以使用此方法列出全部属性查看。
当第二个参数access为WRITE_TRANSACTION_ACCESS
时,除了写上第三个参数propertyName
(属性名),还要加上第四个参数propertyValue
(属性值)。
如下图示为修改环境球旋转值的参数。
可以看到propertyValue
(属性值)的写法需要与读取到的格式相同。
调用蓝图函数
上面说过通过调用蓝图函数列出当前场景中的所有Actor,下面就是具体使用方法。
可以看到,最大的区别是访问目标地址变成了http://ip:8080/remote/object/call
,其次参数也有不同。
第一个参数依然是objectPath
,只不过这里写的不是物体的路径,而是要调用的蓝图脚本的路径。
第二个参数为functionName
,为要调用的蓝图函数的名称。
该脚本路径如下:
可以看到脚本是C++的库文件,但右侧函数代码中有BlueprintCallable
,表明可以在蓝图中调用。
除了这两个参数外,还有第三个参数parameters
向函数中传入的参数以及第四个参数generateTransaction
生成事务。
生成事务参数类似于WRITE_TRANSACTION_ACCESS
,默认为false,当调用函数修改关卡中物体时,必须设置为true时才能实时看到修改效果。
例如以下代码,可以实时修改灯光物体的旋转属性。
{ "objectPath" :"/Game/ThirdPersonBP/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap:PersistentLevel.LightSource_0.LightComponent0", "functionName":"SetRelativeRotation", "parameters":{ "NewRotation":{ "Pitch":90, "Yaw":0, "Roll":0 } }, "generateTransaction":true }
同样可以在组件的库文件中可以找到该函数。
注意parameters
里面传入的参数名。
上面说过,该方法是基于向蓝图公开的函数的,因此当不知道想调用的函数的名称和参数时,可以先找到对应的物体的库文件,在库文件中搜索BlueprintCallable进行排查,就可以找到可用的函数以及传入的参数。
编辑状态与运行状态
在UE中,编辑状态与运行状态是不同的,上面的GetAllLevelActors函数,只能获取到编辑状态下所有的物体,如果在运行状态执行则返回结果为空。
同理在修改物体属性时,也要根据当前UE状态获取目标物体的相应ObjectPath。
例如同样一个HDRIBackdrop物体,在两种状态下的ObjectPath如下:
#编辑状态 /Game/VprodProject/Maps/Main.Main:PersistentLevel.HDRIBackdrop #运行状态 /Game/VprodProject/Maps/UEDPIE_0_Main.Main:PersistentLevel.HDRIBackdrop
那么在运行状态下如何获取到需要的Actor呢?
可以通过GetActorOfClass函数,获取到不同状态下的所选class的物体,而class种类可以通过GetObjectClass函数查看。
#查看物体的class { "objectPath" :"/Script/engine.Default__GameplayStatics", "functionName":"GetObjectClass", "parameters":{ "Object":"/Game/VprodProject/Maps/Main.Main:PersistentLevel.HDRIBackdrop" } } #根据物体class查找物体 { "objectPath" :"/Script/engine.Default__GameplayStatics", "functionName":"GetActorOfClass", "parameters":{ "WorldContextObject":"/Game/VprodProject/Maps/UEDPIE_0_Main.Main", "ActorClass":"/HDRIBackdrop/Blueprints/HDRIBackdrop.HDRIBackdrop_C" } }
常用API函数
下面是我整理的一些常用函数,对其进行封装并制作UI界面即可完成一个远程控制工具。
第一行为property(读取属性)或call(调用函数),后面为正文具体参数。
获取当前关卡编辑路径
库文件为Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorLevelLibrary.h
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorLevelLibrary", "functionName":"GetEditorWorld" }
获取当前关卡运行路径
库文件同上
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorLevelLibrary", "functionName":"GetGameWorld" }
获取所有Actor
库文件同上
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorLevelLibrary", "functionName":"GetAllLevelActors" }
获取当前Actor的component
库文件为Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
call { "objectPath" :"/Game/SpringLandscape/Maps/Overview/Overview.Overview:PersistentLevel.SkySphere_3", "functionName":"K2_GetRootComponent" }
Actor操作
这部分也可以在Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
中查找具体使用方法,略写如下。
call { #获取移动 "functionName""GetActorLocation" #设置移动 "functionName":"SetActorLocation","parameters" :{"NewPosition": {"X": 0,"Y": 0,"Z": 0}},"generateTransaction":true #获取旋转 "functionName":"GetActorRotation" #设置旋转 "functionName":"SetActorRotation","parameters" :{"NewRotation": {"Roll": 0,"Pitch": 0,"Yaw": 0}},"generateTransaction":true #获取缩放 "functionName":"GetActorScale3D" #设置缩放 "functionName":"SetActorScale3D","parameters" :{"NewScale3D": {"X": 1,"Y": 1,"Z": 1}},"generateTransaction":true #同时设置移动和旋转 "functionName":"SetActorLocationAndRotation" #获取和设置相对移动旋转缩放 "functionName":"SetActorRelativeLocation" "functionName":"SetActorRelativeRotation" "functionName":"SetActorRelativeScale3D" "functionName":"GetActorRelativeLocation" "functionName":"GetActorRelativeRotation" "functionName":"GetActorRelativeScale3D" #获取到某位置的距离 "functionName":"GetDistanceTo" #获取速度 "functionName":"GetVelocity" #隐藏 SetActorHiddenInGame "bNewHidden": false #碰撞 GetActorEnableCollision SetActorEnableCollision "bNewActorEnableCollision": false #销毁 DestroyActor }
获取组件材质
库文件为Engine/Source/Runtime/Engine/Classes/Components/StaticMeshComponent.h
call { "objectPath" :"/Game/SpringLandscape/Maps/Overview/Overview.Overview:PersistentLevel.SkySphere_3.StaticMeshComponent0", "functionName":"GetMaterial" }
设置组件材质
库文件同上
call { "objectPath" :"/Game/SpringLandscape/Maps/Overview/Overview2.Overview2:PersistentLevel.Sky_Sphere.StaticMeshComponent0", "functionName":"SetMaterial", "parameters":{ "ElementIndex":0, "Material":"/Game/SpringLandscape/Meshes/Background/Materials/MI_Background.MI_Background" }, "generateTransaction":true }
更改贴图
通过 :
可以访问到材质内部的贴图等节点
property { "objectPath" :"/Game/SpringLandscape/Meshes/Sky/Materials/test.test:MaterialExpressionTextureSample_0", "access":"WRITE_TRANSACTION_ACCESS", "propertyName":"Texture", "propertyValue": { "Texture":"/Game/StarterContent/Textures/T_Wood_Oak_D.T_Wood_Oak_D" } }
获取基础材质
库文件为Engine/Source/Runtime/Engine/Classes/Materials/MaterialInterface.h
call { "objectPath" :"/Game/SpringLandscape/Meshes/Sky/Materials/MI_Sky.MI_Sky", "functionName":"GetBaseMaterial" }
获取当前视角
库文件为Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorLevelLibrary.h
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorLevelLibrary", "functionName":"GetLevelViewportCameraInfo" }
设置当前视角
库文件同上
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorLevelLibrary", "functionName":"SetLevelViewportCameraInfo", "parameters":{ "CameraLocation": { "X": -186347, "Y": -338253, "Z": -18670 }, "CameraRotation": { "Pitch": -6.59973, "Yaw": 113.599, "Roll": 0 } }, "generateTransaction":true }
列出路径下的资产(uasset)
库文件为Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorAssetLibrary.h
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorAssetLibrary", "functionName":"ListAssets", "parameters":{ "DirectoryPath":"/Game/SpringLandscape/Meshes/Sky", "bRecursive":true, "bIncludeFolder":false } }
查询某个资产的详细信息
库文件同上
call { "objectPath" :"/Script/EditorScriptingUtilities.Default__EditorAssetLibrary", "functionName":"FindAssetData", "parameters":{ "AssetPath":"/Game/SpringLandscape/Meshes/Sky/SM_Sphere" } }
灯光组件操作
库文件为Engine/Source/Runtime/Engine/Classes/Components/LightComponent.h
call { #设置亮度 SetIntensity(float NewIntensity) #设置间接照明亮度 SetIndirectLightingIntensity(float NewIntensity) #设置灯光颜色 SetLightColor(FLinearColor NewLightColor, bool bSRGB = true) #设置色温 SetTemperature(float NewTemperature) #设置辉光 SetTransmission(bool bNewValue) #设置IES光域 SetIESTexture(UTextureLightProfile* NewValue); }
将texture资产导出为hdr
库文件为Engine/Source/Runtime/Engine/Classes/Kismet/KismetRenderingLibrary.h
call { "objectPath" :"/Script/engine.Default__KismetRenderingLibrary", "functionName":"ExportTexture2D", "parameters":{ "WorldContextObject":"/Game/SpringLandscape/Maps/Overview/Overview.Overview", "Texture":"/Game/SpringLandscape/Meshes/Sky/Textures/T_Sky_01_A.T_Sky_01_A", "FilePath":"C:/", "FileName":"test.hdr" } }
其他常用的库文件及包含功能如下,未完全测试:
#load、deleteLoaded、doesExist、rename、save、checkout、duplicate、delete、metadata Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorAssetLibrary.h #EditorPlaySimulate、select、spawnActor、NewLevel、loadLevel、saveLevel、replaceMeshComponentsMaterials Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorLevelLibrary.h #CurrentLanguage、CurrentLocale Engine/Source/Runtime/Engine/Classes/Kismet/KismetInternationalizationLibrary.h #ImportFileAsTexture2D Engine/Source/Runtime/Engine/Classes/Kismet/KismetRenderingLibrary.h #spawnObject、openLevel、SetGamePaused、isGamePaused、playSound2D、savegame、GetPlatformName、SetWorldOriginLocation Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h #ExecuteConsoleCommand、GetConsoleVariableBoolValue、QuitGame、QuitEditor、SetIntPropertyByName、LaunchURL、SnapshotObject Engine/Source/Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h
总结
上面只列举了比较常用的部分函数,可以看出WebRemoteControl模块的功能确实是极为强大的,经过开发者封装成带图形界面的工具后,能广泛应用在游戏调试和虚拟制片等领域。
绝对不要为你的一辈子做好计划,
因为人的变化在两三年内都是巨大的,
而且时刻会产生新的想法,
你真正可以做到的是,
想好现在要做什么。
《优秀的绵羊》
——威廉·德雷谢维奇
评论
612669 215742 An intriguing discussion is worth comment. I believe that you need to write a lot more on this topic, it may not be a taboo subject but usually folks are not enough to speak on such topics. To the next. Cheers 225342
You really make it seem so easy with your presentation but I find this matter to be really something that I think I would never understand. It seems too complicated and very broad for me. I’m looking forward for your next post, I’ll try to get the hang of it!
https://www.javelincloud.com/
71882 608219when i was a kid, i enjoy to receive an assortment of birthday presents like teddy bears and mechanical toys, 935460
Some truly fantastic articles on this web site, thankyou for contribution.
https://youtu.be/BanYFY6l55c
Some truly nice and useful info on this internet site, likewise I conceive the design and style has got good features.
https://youtu.be/GkE37b86KF0
406982 306420Register a domain, search for available domains, renew and transfer domains, and pick from a wide variety of domain extensions. 885249
48090 459467you could have a great weblog here! would you wish to make some invite posts on my weblog? 297953
I?¦m not sure where you’re getting your info, however great topic. I needs to spend a while learning much more or working out more. Thank you for wonderful information I used to be in search of this information for my mission.
https://youtu.be/L8_q3tFIOqg
I’ve read several good stuff here. Definitely worth bookmarking for revisiting. I wonder how much effort you put to make such a excellent informative site.
https://youtu.be/Xj8xoq9AWt8
140981 158568Spot lets start work on this write-up, I really believe this incredible web site requirements significantly far more consideration. Ill apt to be once once more to read a great deal far more, several thanks for that information. 539813