UE4数字孪生WebUI前端控制功能浅析

光影年年 2023-09-11 10:30:49

在UE4数字孪生的实际开发过程中我们经常会遇到前端和客户端的通信问题,为实现相关功能,我在此分享开发者Tracer Interactive的开发经验,并做一定程度上的技术分析。

此Webul插件支持Windows, Mac, Linux,Android (4.19)和iOS (4.21)。同样 从版本4.19幵始,您必须下载并安装Json Library插件。

DOWNLOAD

可以从GitHub的以下地址下载此插件(*公众号联系:“光影年年”客服获取)

01

注意事项

每个版本还与所有次要引擎更新兼容,这意味着该插件的4.19.0版本也可以与任何对应的 修补程序(如4.19.1或4.19.2)一起使用。

您必须将GitHub帐户链接到您的EpicGames帐户!

设置说明:https: //www.unrealengine.com/ue4-on-github

否则,如果您未使用关联帐户登录,则将收到先前的404错误。

02

安装

若要安装Webul插件,请将下载的文件解压缩到以下引擎文件夹中:

另外,请注意屏幕截图中的UE_4.19目录。您需要将此文件夹更改为与已下载的插件版本相对应的版本。如果您没有将引擎安装到默认目录,请转至您的自定义安装文件夹。

然后打开您的项目并转到编辑下拉菜单中的"插件''选项,单击'‘小部件''类别,然后启用 Webul插件(如果尚未启用)

您现在已经成功安装了Webul插件。重新启动编辑器以继续。

03

设置

安装并启用WebuI插件后,首先创建一个自定义用户窗口小部件。在此示例中,我们将创建一个称为 Webinterface 的 Web Interface 。

现在打开Webinterfaceface蓝图并开始编辑。将WebInterface组件拖放到画布面板中。

在画布面板中选择Web UI组件,然后设置一个变量名。在此示例中,我们将为该组件使用名 称"浏览器"。

接下来,单击“锚点”下拉列表,然后选择右下⻆的“snap to all edeges ”选项,然后将所有偏移 设置为零。

Web UI组件现在应该是全屏的。单击"编译''和"保存''按钮,然后关闭此蓝图。

创建一个新的蓝图类并选择父类。在此示例中,我们将选择HUD类,因为它是最合适的,并 为此资产使用名称MyHUD。请注意,可以从任何蓝图将小部件添加到视口,因此您可以改 用现有的蓝图。

现在打开MyHUD蓝图开始编辑,然后单击'EventGraph"选项卡。从BeginPlay事件中拖动一 条执行行,然后选择"CreateWidget"节点。然后单击"Select Class"下拉列表,然后选择“ Webinterface"窗口小部件。

接下来,从“ Owning Player”引脚上拖动⼀个连接,然后选择“ Get Owning Player Controller” 节点。

然后从“ Return Value”引脚上拖动另⼀个连接,并在下拉菜单中选择“ Promote to variable”选 项。

现在,通过从MyWidget引脚拖动连接来读取浏览器变量的值。

接下来,从浏览器变量中拖动⼀个连接,然后选择“Bind Event to OnInterface Event”节点。

另外,还要确保将执⾏销钉从MyWidget节点连接到此节点。

现在,从“Event”图钉中拖动⼀个委托连接,然后从下拉列表中选择“Add Custom Even..”。在此示例中,我们将为此事件使⽤名称“ OnBroadcas”。

然后从“我的窗⼝⼩部件”变量中拖动另⼀个连接,然后在下拉列表中选择“Add to Viewport”节点。

将此节点移到右侧,然后将其连接到“将事件绑定到OnInterfaceEvent”节点。现在,从 浏览器变量中拖动⼀个连接,然后选择“Set Input Mode UI Only”节点。

将此节点也向右移动,然后将其连接到“添加到视⼝”节点。然后,将“Target”引脚连接 到先前创建的“获取拥有者播放器控制器”节点。

现在,从浏览器变量中拖动另⼀个连接,然后选择“Load File”节点。

将此节点移到右侧,然后将其连接到“仅设置输⼊模式UI”节点。然后从/ UI⽬录输⼊⽂件 名。尝试使⽤示例项⽬中的Sample.html⽂件:

您现在应该拥有⼀个类似于以下屏幕截图的蓝图:

这是WebInterface窗⼝⼩部件所需的基线功能。单击“edit”和“save”按钮,然后关闭此蓝 图。

若要在游戏中使⽤该类,请创建另⼀个蓝图类,然后选择“ Game Mode Base”类作为⽗类。在此示例中,我们将为该蓝图使⽤名称My GameMode。然后在详细信息部分中选择您的 HUD。

单击“edit”和“save”按钮,然后关闭此蓝图。如果您已有⼀个要在其中加载界⾯的级别, 请跳过以下部分并改⽤您⾃⼰的⾃定义级别。您还可以在项⽬设置中将此游戏模式设置 为默认游戏模式,如下所示:

现在创建⼀个关卡资产来加载您的界⾯。在此示例中, 我们将为此级别使⽤名称“MyMap”。创建完成后,双击级别在编辑器中将其打开。

在“World Settings”选项卡中,从“游戏模式替代”下的下拉列表中选择MyGameMode。然后 点击左上⻆的“Save Current”以保存您的地图。现在您的Webul已准备好进⾏测试,只需单 击“Play”按钮即可开始!

04

数据

浏览器可以使⽤⾃定义蓝图事件将数据作为JSON发送到游戏。⾸先从先前创建的 OnBroadcast事件的“Name”针脚拖动连接,然后选择“Switch on Name”节点。

单击“Add pin +”按钮,并选择节点,然后取消选中右侧详细信息⾯板中的“Has Default Pin”选 项。根据所需的功能键⼊引脚的名称,并根据需要添加更多名称。在此示例中,将使⽤打印 来调试“Data”引脚。从该引脚上拖动连接以遍历和访问从JavaScript发送的对象,数组和原始 数据类型。

选择“ Stringify”节点并打印“ Return Value”引脚后,您的⼴播事件应类似于以下屏幕截图:

通过调⽤JavaScript中的ue.interface.broadcast函数来触发此事件。第⼀个参数是事件的 “Name”,并且必须是字符串。第⼆个参数是通过“ Data”引脚提供的,并且必须是有效的 JSON字符串。全局ue4()辅助函数已定义为⾃动JSON.stringify ...)第⼆个参数。

此脚本应⽤于在⻚⾯加载时定义全局ue4()帮助器函数,并且是移动⽀持所必需的。下页提供了

"object"!=typeof ue||"object"!=typeof ue.interface?("object"!=typeof ue&&(ue={}),ue.interface={},ue.interface.broadcast=function(e,t){if("string"==typeof e){var o=[e,""];void 0!==t&&(o[1]=t);var n=encodeURIComponent(JSON.stringify(o));"object"==typeof history&&"function"==typeof history.pushState?(history.pushState({},"","#"+n),history.pushState({},"","#"+encodeURIComponent("[]"))):(document.location.hash=n,document.location.hash=encodeURIComponent("[]"))>):function(e){ue.interface={},ue.interface.broadcast=function(t,o){"string"==typeof t&&(void 0!==o?e.broadcast(t,JSON.stringify(o)):e.broadcast(t,""))>(ue.interface),ue4=ue.interface.broadcast;

ue4()帮助程序函数是⼀个包装器,该包装器使⽤有效的JSON字符串调⽤ ue.interface.broadcast。可选的第⼆个参数允许在不提供数据的情况下触发命令。此功 能还回退到通过移动平台上的URL更改传输JSON。

if (typeof ue != "object" || typeof ue.interface != "object"){if (typeof ue != "object")ue = {};// mobileue.interface = {};ue.interface.broadcast = function(name, data){if (typeof name != "string")return;var args = [name, ""];if (typeof data != "undefined")args[1] = data;var hash = encodeURIComponent(JSON.stringify(args));if (typeof history == "object" && typeof history.pushState == "function"){history.pushState({}, "", "#" + hash);history.pushState({}, "", "#" + encodeURIComponent("[]"));}else{document.location.hash = hash;document.location.hash = encodeURIComponent("[]");}};}else(function(obj){// desktopue.interface = {};ue.interface.broadcast = function(name, data){if (typeof name != "string")return;if (typeof data != "undefined")obj.broadcast(name, JSON.stringify(data));elseobj.broadcast(name, "");};})(ue.interface);// create the global ue4(...) helper functionue4 = ue.interface.broadcast;

游戏还可以通过函数调⽤以JSON格式将数据发送到浏览器。⾸先从浏览器变量中拖动 ⼀个连接,然后选择“Call”节点。

输⼊将在JavaScript中执⾏的函数的名称。在此示例中,将调⽤setFPS(...)函数。现在将JSON值连接到“Data”引脚,可以是浮点数、整数、字符串、布尔值,甚⾄是复杂类型,例如数组或映射。

这些函数必须在JavaScript中的全局ue.interface对象上定义。提供给“Data”引脚的 JSON作为该函数的唯 ⼀参数传递,它将⾃动反序列化为适当的数据类型。

使用这些功能,开发人员可以通过JSON快速轻松地在游戏和浏览器之间发送数据。

05

加载

从浏览器变量中拖动连接并选择“Load”功能之⼀时,浏览器可以加载⽂件或内容

“Load URL”和“Load HTML”节点⾮常简单。您可以提供原始HTML字符串,也可以提供将在 浏览器中加载的任何URL:

对于⼤多数游戏,“Load”功能是加载界⾯的主要⽅式。它采⽤/ Content⽬录中⽂件的路径。该路径将使⽤⾃定义的pak://⽅案重组为URL,该⽅案使⽤Unreal Engine⽂件系统加载内容:

这意味着使⽤⾃定义 pak://scheme访问的任何⽂件都可以直接位于/ Content⽬录中的 磁盘上,以供编辑器构建或打包在内部。运输版本中的pak⽂件。引擎⽂件系统将像其他.uasset文件一样自动管理此文件

为了确保/ Content⽬录中的任何⽂件夹都包含在.pak⽂件中,请在项⽬设置中设置 “Additional Non-Asset Directories to Package”选项:

还有“Load File”和“Load Content”节点,它们稍微复杂⼀些:

“Load File”功能等效于使⽤file:/// 并直接在浏览器中加载HTML⽂件。默认情况下, 它将从项⽬根⽬录中的IUI⽬录加载⽂件:

这也允许使⽤HTML中的相对路径(例如 )访问图像,脚本和 样式表。在运输或包装时, /Ul ⽬录应复制到与游戏⽂件夹中的/Binaries和 /Content ⽂件夹相同的级别:

如果您希望将HTML⽂件放在/Content ⽬录中,那么在⾼级显示下也可以选择使⽤ 此选项。然后,可以使⽤项⽬设置中的“Additional Non-Asset Directories To Copy” 选项来⾃动复制/Content⽬录中的特定⽂件夹,⽽不必⼿动复制UI文件夹:

但是,“Load File”功能⽆法访问.pak⽂件中的HTML⽂件(即使它们位于 /Content ⽬录 中)。因此,使⽤“添加到软件包的其他⾮资产⽬录”选项添加了“加载内容”功能以访问⽂件:

此选项将/Content ⽬录中的⽂件夹打包到您提供的游戏的pak⽂件中。但是,由于未使⽤ file:///加载此内容,因此HTML⽆法访问本地⽂件,例如图像,脚本和样式表。但是, “Load Content”功能的确在⾼级显示下提供了⼀个选项,该选项允许/Content ⽬录中的 JavaScript⽂件在浏览器的上下文中执行:

06

回调

从4.23版开始,ue.interface.broadcast函数包含⼀个可选的第三个参数,该参数必须是字符串。它在UE上指定函数名称。引擎可以选择使⽤可选参数回调的接⼝对象。这是⼀个从蓝图调⽤回调的示例(如果提供的话):

可以通过全局ue4()帮助函数从JavaScript触发此事件,并将回调函数作为第⼆个或第三 个参数:

该功能后可以提供⼀个可选的超时时间。如果未提供超时,则在辅助函数中定义的默认值为1秒。超时后,临时回调函数将被⾃动删除。以下是输⼊数据和3秒钟的回调超时的示例:

该脚本可⽤于定义全局ue4()帮助函数,该函数注册具有可选超时期限的临时回调函数。示 例项⽬中提供了此脚本的源代码。

"object"!=typeof ue&&(ue={}),uuidv4=function(){return"10000000-1000-4000-8000-100000000000".replace(/[018]/g,function(t){return(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)})}ue4=function(r){return"object"!=typeof ue.interface||"function"!=typeofue.interface.broadcast?(ue.interface={},function(t,e,n,o){var u,i;"string"==typt&&("function"==typeof e&&(o=n,n=e,e=null),u=[t,"",r(n,o)],void 0!==e&&(u[1]=e),i=encodeURIComponent(JSON.stringify(u)),"object"==typeofhistory&&"function"==typeof history.pushState?(history.pushState({},"","#"+i),history.pushState({},"","#"+encodeURIComponent("[]"))):(document.location.hash=i,document.location.hash=encodeURIComponent("[]")))}):(i=ue.interface,ue.interface={},function(t,e,n,o){var u;"string"==typeof t&&("function"==typeofe&&(o=n,n=e,e=null),u=r(n,o),void 0!==e?i.broadcast(t,JSON.stringify(e),u):i.broadcast(t,"",u))});var i}(function(t,e){if("function"!=typeof t)return"";varn=uuidv4();return ue.interface[n]=t,setTimeout(function(){delete ue.interface[n]},1e3*Math.max(1,parseInt(e)||0)),n});

uuidv4函数⽣成⼀个加密强度⾼的UUID,⽤作ue上的临时函数名称。接⼝对象。此属性将 在设计的超时时间(默认为1秒)后⾃动删除。

06

聚焦

有“聚焦”和“未聚焦”功能可⽤于更改键盘和⿏标的聚焦:

“聚焦”节点直接将焦点集中到浏览器的视⼝中。此⽅法⽐引擎提供的默认功能更⾼级,因为 它们要求⽤户在浏览器获得键盘焦点之前单击界⾯。但是,插件提供的此功能 允许 JavaScript集中输⼊和⽂本框元素。这意味着当与JavaScript焦点事件结合使⽤时,您可以将游戏的焦点直接设置为HTML元素(例如:聊天⼩部件),如下所示:

该节点还将⾃动显示⿏标光标,并使界⾯完全可交互。然后,“ 未聚焦”节点将⾃动隐藏⿏ 标光标,并将焦点从浏览器移回到游戏上,这两个节点通常⽤于在游戏和任何游戏内设置 之间进⾏切换(通常在⼤多数游戏中通过退出键) 。提供了另⼀个名为“Reset Mouse Positio”的节点,以将⿏标(在可⻅时)移动到屏幕中⼼。通常在“聚焦”节点之后调⽤此⽅法,如果在将焦点设置到界⾯时最初不可⻅⿏标,则建议使 ⽤此⽅法:

07

透明度

可以将⼩部件配置为⽀持在界⾯的透明部分后⾯单击,以进⾏需要始终显示⿏标光标的游戏。此设置在“Behavior”部分下的⼩部件蓝图中可⽤:

这将指导基础板⼩部件在每个游戏刻度上的⿏标位置下对像素采样,并在“点击测 试不可⻅”和“可⻅”模式之间动态切换⼩部件。由于使⽤ActorOnClicked和ActorBeginCursor Over或ActorEndCursorOver事件是⾃动内 置到actor蓝图中的,因此,建议您在使⽤此功能时在游戏中启⽤⿏标单击/⿏标移过事 件。

这些事件已经包含在引擎中,并且在任何参与者蓝图的事件图上单击⿏标右键时,可在 “Add Event”下的“Mouse Input”部分中找到它们:

请注意,必须在播放器控制器的“Mouse Interface”部分中启⽤“Click Events”或“Mouse Over Events”,这些事件才能在引擎中触发:

08

光标

由于引擎中的错误,此插件不支持自定义鼠标光标。但是,如果您从源代码手动编译,则可以实现以下更改。若要使用自定义鼠标光标解决此问题,请在引擎源文件的/ Engine / Source / Runtime / WebBrowser / Private / CEF目录中找到CEFWebBrowserWindow.cpp文件。搜索以下 所示的方法 FCEFWebBrowserWindow::OnCursorChange(...):

注意第1708行的#if PLATFORM_WINDOWS II PLATFORM_MAC。它实质上是通过手动设置操作系统的光标来绕过引擎的本机光标管理的,除非它是默认的指针或文本编辑器光束。

因此,您应将此行更改为#if,以防止编译此块(绝对没有全局设置可切换它)。以 示例说明了对引擎源所做的更改:

请注意,第1709和1720⾏之间的块现在显示为灰⾊,并且Web浏览器进程的光标将 被适当地映射到引擎光标类型。现在,您可以构建UE4项⽬,以将⾃定义⿏标光标与Webul插件⼀起使⽤:

09

纹理

可以使⽤“Read Texture Pixel”节点或“Read Texture Pixels”节点访问浏览器的纹理数据, 如以下示例所示:

这些节点将分别返回单⾊或颜⾊数组。请注意,没有创建任何渲染⽬标来访问此纹理数 据。相反,这些函数使⽤浏览器的基础纹理引⽤直接在渲染线程上执⾏命令。还请记住,浏览器纹理的⼤⼩可能并不总是与视⼝中的⼩部件的⼤⼩匹配。因此,提供 了“Get Texture Width”和“Get Texture Height”节点以访问基础浏览器纹理的⼤⼩:

10

工具

聚集对准时,可以使⽤CTRL + SHIFT + I调试浏览器。此组合键可打开ChromeDevTools,并且仅在开发和调试版本中可⽤。

您可以在以下地址的Chrome DevTools上找到⽂档:https://developers.google.com/web/tools/chrome-devtools/

11

WEBGL

由于引擎的配置,此插件在4.24及更低版本的桌面平台上不支持WebGL。但是,如果您 从源代码手动进行编译,则可以以性能为代价进行以下更改(尤其是对于全屏界面)。打幵 / Engine / Source / Runtime / WebBrowser / Private / CEF 目录中的CEFBrowserApp.cpp文件。搜索FCEFBrowserApp :: OnBeforeCommandLineProcessing (...)方法,如以下示例所示:

请注意,附加到浏览器子进程命令行的两个开关enable-gpu和enable-gpu-compositing。您将需要将这两个开关更改为disable-gpu和disable-gpu-compositing,如下所示:

现在,您可以构建 UE4项⽬, 并在启⽤WebGL的情况下使⽤WebUI插件:

性能表现版本4.24到4.26的引擎安装默认情况下启用了 WebGL,这会大大降低性能(尤其是对于全屏界面)。但是,如果您从源代码手动编译,则可以实现以下更改。打开/ Engine / Source / Runtime / WebBrowser / Private / CEF 目录中的CEFBrowserApp.cpp文件。搜索FCEFBrowserApp :: OnBeforeCommandLineProcessing(...)方法,如以下示例所示:

请注意,附加到浏览器⼦进程命令⾏的两个开关enable-gpu和enable-gpu-compositing。您将需要将这两个开关更改为disable-gpu和disable-gpu-compositing,如下所示:

现在,您可以构建UE4项⽬,以在禁⽤WebGL的情况下使⽤WebUl插件:

12

编译

可以为其他平台或引擎版本手动编译此插件。首先打开命令提示符(通过在开始菜单中 搜索"cmd”)并键入以下命令:

cd "C:\Program Files'Epic Games \UE_4.21"您可以通过右键单击命令提示符来复制并粘贴此命令。还要注意UE_4.21目录。您需要将 此文件夹更改为与您所使用的引擎版本相对应的版本。如果未将引擎安装到默认目录,请键入自定义安装文件夹的路径。按输入运行命令。现在,您应该看到类似于以下内容的输出:

然后键入以下命令来构建插件:Engine\Build\BatchFiles\RunUAT.bat.BuildPlugin-Rocket-Plugin="..." -Package="..."将第一个替换为WebUI.uplugin的路径,将最后一个替换为临时"package"文件夹 的路径。您也可以将.uplugin文件或您的临时文件夹直接拖放到命令提示符下,它将自动键入路径:

确保这些路径不在引擎目录中,否则构建将失败。输入完整的命令后,其外观应类似于以下内容:

如果您的计算机不支持Mac或Linux构建,则您很可能必须从WebUI中删除"Mac"和" IOS”或"Linux"平台。编译前添加:

现在按输入键运行命令。如果一切设置正确,您将看到正在为各种平台编译的插件的许多不同版本。构建完成后,您应该会看到"BUILD SUCCESSFUL"信息:

检查您的临时"package"文件夹,以确保其外观类似于以下内容:

然后,将该临时文件夹中的文件复制到您的引擎安装目录中。如果要编译需要 Webul插件的任何其他插件,则必须事先执行此操作。

您现在已经成功为您的引擎版本编译了Webul插。

制心一处 无事不办

加入我们:

UE4美术×1

UE4产品经理×1

UE4客户端开发(蓝图)×1

数字可视化平面设计师×1

0 阅读:16

光影年年

简介:分享数据可视化设计|数字孪生开发