UE4數(shù)字孿生 WebUI前端控制功能淺析
在UE4數(shù)字孿生的實際開發(fā)過程中我們經(jīng)常會遇到前端和客戶端的通信問題,為實現(xiàn)相關(guān)功能,我在此分享開發(fā)者Tracer Interactive的開發(fā)經(jīng)驗,并做一定程度上的技術(shù)分析。
DOWNLOAD
01
—
注意事項
您必須將GitHub帳戶鏈接到您的EpicGames帳戶!
- 設置說明:https: //www.unrealengine.com/ue4-on-github
否則,如果您未使用關(guān)聯(lián)帳戶登錄,則將收到先前的404錯誤。02
—
安裝
若要安裝Webul插件,請將下載的文件解壓縮到以下引擎文件夾中:
另外,請注意屏幕截圖中的UE_4.19目錄。您需要將此文件夾更改為與已下載的插件版本相對應的版本。如果您沒有將引擎安裝到默認目錄,請轉(zhuǎn)至您的自定義安裝文件夾。
然后打開您的項目并轉(zhuǎn)到編輯下拉菜單中的"插件''選項,單擊'‘小部件''類別,然后啟用 Webul插件(如果尚未啟用)
您現(xiàn)在已經(jīng)成功安裝了Webul插件。重新啟動編輯器以繼續(xù)。03
—
設置
安裝并啟用WebuI插件后,首先創(chuàng)建一個自定義用戶窗口小部件。在此示例中,我們將創(chuàng)建一個稱為 Webinterface 的 Web Interface 。
現(xiàn)在打開Webinterfaceface藍圖并開始編輯。將WebInterface組件拖放到畫布面板中。
在畫布面板中選擇Web UI組件,然后設置一個變量名。在此示例中,我們將為該組件使用名 稱"瀏覽器"。
接下來,單擊“錨點”下拉列表,然后選擇右下?的“snap to all edeges ”選項,然后將所有偏移 設置為零。
Web UI組件現(xiàn)在應該是全屏的。單擊"編譯''和"保存''按鈕,然后關(guān)閉此藍圖。
創(chuàng)建一個新的藍圖類并選擇父類。在此示例中,我們將選擇HUD類,因為它是最合適的,并 為此資產(chǎn)使用名稱MyHUD。請注意,可以從任何藍圖將小部件添加到視口,因此您可以改 用現(xiàn)有的藍圖。
現(xiàn)在打開MyHUD藍圖開始編輯,然后單擊'EventGraph"選項卡。從BeginPlay事件中拖動一 條執(zhí)行行,然后選擇"CreateWidget"節(jié)點。然后單擊"Select Class"下拉列表,然后選擇“ Webinterface"窗口小部件。
接下來,從“ Owning Player”引腳上拖動?個連接,然后選擇“ Get Owning Player Controller” 節(jié)點。
然后從“ Return Value”引腳上拖動另?個連接,并在下拉菜單中選擇“ Promote to variable”選 項。
現(xiàn)在,通過從MyWidget引腳拖動連接來讀取瀏覽器變量的值。
接下來,從瀏覽器變量中拖動?個連接,然后選擇“Bind Event to OnInterface Event”節(jié)點。
另外,還要確保將執(zhí)?銷釘從MyWidget節(jié)點連接到此節(jié)點。
現(xiàn)在,從“Event”圖釘中拖動?個委托連接,然后從下拉列表中選擇“Add Custom Even..”。在此示例中,我們將為此事件使?名稱“ OnBroadcas”。
然后從“我的窗??部件”變量中拖動另?個連接,然后在下拉列表中選擇“Add to Viewport”節(jié)點。
將此節(jié)點移到右側(cè),然后將其連接到“將事件綁定到OnInterfaceEvent”節(jié)點?,F(xiàn)在,從 瀏覽器變量中拖動?個連接,然后選擇“Set Input Mode UI Only”節(jié)點。
將此節(jié)點也向右移動,然后將其連接到“添加到視?”節(jié)點。然后,將“Target”引腳連接 到先前創(chuàng)建的“獲取擁有者播放器控制器”節(jié)點。
現(xiàn)在,從瀏覽器變量中拖動另?個連接,然后選擇“Load File”節(jié)點。
將此節(jié)點移到右側(cè),然后將其連接到“僅設置輸?模式UI”節(jié)點。然后從/ UI?錄輸??件 名。嘗試使?示例項?中的Sample.html?件:
您現(xiàn)在應該擁有?個類似于以下屏幕截圖的藍圖:
這是WebInterface窗??部件所需的基線功能。單擊“edit”和“save”按鈕,然后關(guān)閉此藍 圖。
若要在游戲中使?該類,請創(chuàng)建另?個藍圖類,然后選擇“ Game Mode Base”類作為?類。在此示例中,我們將為該藍圖使?名稱My GameMode。然后在詳細信息部分中選擇您的 HUD。
單擊“edit”和“save”按鈕,然后關(guān)閉此藍圖。如果您已有?個要在其中加載界?的級別, 請?zhí)^以下部分并改?您??的?定義級別。您還可以在項?設置中將此游戲模式設置 為默認游戲模式,如下所示:
現(xiàn)在創(chuàng)建?個關(guān)卡資產(chǎn)來加載您的界?。在此示例中, 我們將為此級別使?名稱“MyMap”。創(chuàng)建完成后,雙擊級別在編輯器中將其打開。
在“World Settings”選項卡中,從“游戲模式替代”下的下拉列表中選擇MyGameMode。然后 點擊左上?的“Save Current”以保存您的地圖。現(xiàn)在您的Webul已準備好進?測試,只需單 擊“Play”按鈕即可開始!04
—
數(shù)據(jù)
瀏覽器可以使??定義藍圖事件將數(shù)據(jù)作為JSON發(fā)送到游戲。?先從先前創(chuàng)建的 OnBroadcast事件的“Name”針腳拖動連接,然后選擇“Switch on Name”節(jié)點。
單擊“Add pin +”按鈕,并選擇節(jié)點,然后取消選中右側(cè)詳細信息?板中的“Has Default Pin”選 項。根據(jù)所需的功能鍵?引腳的名稱,并根據(jù)需要添加更多名稱。在此示例中,將使?打印 來調(diào)試“Data”引腳。從該引腳上拖動連接以遍歷和訪問從JavaScript發(fā)送的對象,數(shù)組和原始 數(shù)據(jù)類型。
選擇“ Stringify”節(jié)點并打印“ Return Value”引腳后,您的?播事件應類似于以下屏幕截圖:
通過調(diào)?JavaScript中的ue.interface.broadcast函數(shù)來觸發(fā)此事件。第?個參數(shù)是事件的 “Name”,并且必須是字符串。第?個參數(shù)是通過“ Data”引腳提供的,并且必須是有效的 JSON字符串。全局ue4()輔助函數(shù)已定義為?動JSON.stringify ...)第?個參數(shù)。
此腳本應?于在??加載時定義全局ue4()幫助器函數(shù),并且是移動?持所必需的。下頁提供了- "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()幫助程序函數(shù)是?個包裝器,該包裝器使?有效的JSON字符串調(diào)? ue.interface.broadcast??蛇x的第?個參數(shù)允許在不提供數(shù)據(jù)的情況下觸發(fā)命令。此功 能還回退到通過移動平臺上的URL更改傳輸JSON。
- if (typeof ue != "object" || typeof ue.interface != "object")
- {
- if (typeof ue != "object")
- ue = {};
- // mobile
- ue.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)
- {
- // desktop
- ue.interface = {};
- ue.interface.broadcast = function(name, data)
- {
- if (typeof name != "string")
- return;
- if (typeof data != "undefined")
- obj.broadcast(name, JSON.stringify(data));
- else
- obj.broadcast(name, "");
- };
- })(ue.interface);
- // create the global ue4(...) helper function
- ue4 = ue.interface.broadcast;
游戲還可以通過函數(shù)調(diào)?以JSON格式將數(shù)據(jù)發(fā)送到瀏覽器。?先從瀏覽器變量中拖動 ?個連接,然后選擇“Call”節(jié)點。
輸?將在JavaScript中執(zhí)?的函數(shù)的名稱。在此示例中,將調(diào)?setFPS(...)函數(shù)?,F(xiàn)在將JSON值連接到“Data”引腳,可以是浮點數(shù)、整數(shù)、字符串、布爾值,甚?是復雜類型,例如數(shù)組或映射。
這些函數(shù)必須在JavaScript中的全局ue.interface對象上定義。提供給“Data”引腳的 JSON作為該函數(shù)的唯 ?參數(shù)傳遞,它將?動反序列化為適當?shù)臄?shù)據(jù)類型。
使用這些功能,開發(fā)人員可以通過JSON快速輕松地在游戲和瀏覽器之間發(fā)送數(shù)據(jù)。05
—
加載
從瀏覽器變量中拖動連接并選擇“Load”功能之?時,瀏覽器可以加載?件或內(nèi)容
“Load URL”和“Load HTML”節(jié)點?常簡單。您可以提供原始HTML字符串,也可以提供將在 瀏覽器中加載的任何URL:
對于?多數(shù)游戲,“Load”功能是加載界?的主要?式。它采?/ Content?錄中?件的路徑。該路徑將使??定義的pak://?案重組為URL,該?案使?Unreal Engine?件系統(tǒng)加載內(nèi)容:
這意味著使??定義 pak://scheme訪問的任何?件都可以直接位于/ Content?錄中的 磁盤上,以供編輯器構(gòu)建或打包在內(nèi)部。運輸版本中的pak?件。引擎?件系統(tǒng)將像其他.uasset文件一樣自動管理此文件
為了確保/ Content?錄中的任何?件夾都包含在.pak?件中,請在項?設置中設置 “Additional Non-Asset Directories to Package”選項:
還有“Load File”和“Load Content”節(jié)點,它們稍微復雜?些:
“Load File”功能等效于使?file:/// 并直接在瀏覽器中加載HTML?件。默認情況下, 它將從項?根?錄中的IUI?錄加載?件:
這也允許使?HTML中的相對路徑(例如 )訪問圖像,腳本和 樣式表。在運輸或包裝時, /Ul ?錄應復制到與游戲?件夾中的/Binaries和 /Content ?件夾相同的級別:
如果您希望將HTML?件放在/Content ?錄中,那么在?級顯示下也可以選擇使? 此選項。然后,可以使?項?設置中的“Additional Non-Asset Directories To Copy” 選項來?動復制/Content?錄中的特定?件夾,?不必?動復制UI文件夾:
但是,“Load File”功能?法訪問.pak?件中的HTML?件(即使它們位于 /Content ?錄 中)。因此,使?“添加到軟件包的其他?資產(chǎn)?錄”選項添加了“加載內(nèi)容”功能以訪問?件:
此選項將/Content ?錄中的?件夾打包到您提供的游戲的pak?件中。但是,由于未使? file:///加載此內(nèi)容,因此HTML?法訪問本地?件,例如圖像,腳本和樣式表。但是, “Load Content”功能的確在?級顯示下提供了?個選項,該選項允許/Content ?錄中的 JavaScript?件在瀏覽器的上下文中執(zhí)行:06
—
回調(diào)
從4.23版開始,ue.interface.broadcast函數(shù)包含?個可選的第三個參數(shù),該參數(shù)必須是字符串。它在UE上指定函數(shù)名稱。引擎可以選擇使?可選參數(shù)回調(diào)的接?對象。這是?個從藍圖調(diào)?回調(diào)的示例(如果提供的話):
可以通過全局ue4()幫助函數(shù)從JavaScript觸發(fā)此事件,并將回調(diào)函數(shù)作為第?個或第三 個參數(shù):
該功能后可以提供?個可選的超時時間。如果未提供超時,則在輔助函數(shù)中定義的默認值為1秒。超時后,臨時回調(diào)函數(shù)將被?動刪除。以下是輸?數(shù)據(jù)和3秒鐘的回調(diào)超時的示例:
該腳本可?于定義全局ue4()幫助函數(shù),該函數(shù)注冊具有可選超時期限的臨時回調(diào)函數(shù)。示 例項?中提供了此腳本的源代碼。- "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"!=typeof
- ue.interface.broadcast?(ue.interface={},function(t,e,n,o){var u,i;"string"==typ
- t&&("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"==typeof
- history&&"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"==typeof
- e&&(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"";var
- n=uuidv4();return ue.interface[n]=t,setTimeout(function(){delete ue.interface[n]},
- 1e3*Math.max(1,parseInt(e)||0)),n});
uuidv4函數(shù)?成?個加密強度?的UUID,?作ue上的臨時函數(shù)名稱。接?對象。此屬性將 在設計的超時時間(默認為1秒)后?動刪除。
06
—
聚焦
有“聚焦”和“未聚焦”功能可?于更改鍵盤和?標的聚焦:
“聚焦”節(jié)點直接將焦點集中到瀏覽器的視?中。此?法?引擎提供的默認功能更?級,因為 它們要求?戶在瀏覽器獲得鍵盤焦點之前單擊界?。但是,插件提供的此功能 允許 JavaScript集中輸?和?本框元素。這意味著當與JavaScript焦點事件結(jié)合使?時,您可以將游戲的焦點直接設置為HTML元素(例如:聊天?部件),如下所示:
該節(jié)點還將?動顯示?標光標,并使界?完全可交互。然后,“ 未聚焦”節(jié)點將?動隱藏? 標光標,并將焦點從瀏覽器移回到游戲上,這兩個節(jié)點通常?于在游戲和任何游戲內(nèi)設置 之間進?切換(通常在?多數(shù)游戲中通過退出鍵) 。提供了另?個名為“Reset Mouse Positio”的節(jié)點,以將?標(在可?時)移動到屏幕中?。通常在“聚焦”節(jié)點之后調(diào)?此?法,如果在將焦點設置到界?時最初不可??標,則建議使 ?此?法:07
—
透明度
可以將?部件配置為?持在界?的透明部分后?單擊,以進?需要始終顯示?標光標的游戲。此設置在“Behavior”部分下的?部件藍圖中可?:
這將指導基礎板?部件在每個游戲刻度上的?標位置下對像素采樣,并在“點擊測 試不可?”和“可?”模式之間動態(tài)切換?部件。由于使?ActorOnClicked和ActorBeginCursor Over或ActorEndCursorOver事件是?動內(nèi) 置到actor藍圖中的,因此,建議您在使?此功能時在游戲中啟??標單擊/?標移過事 件。
這些事件已經(jīng)包含在引擎中,并且在任何參與者藍圖的事件圖上單擊?標右鍵時,可在 “Add Event”下的“Mouse Input”部分中找到它們:
請注意,必須在播放器控制器的“Mouse Interface”部分中啟?“Click Events”或“Mouse Over Events”,這些事件才能在引擎中觸發(fā):08
—
光標
由于引擎中的錯誤,此插件不支持自定義鼠標光標。但是,如果您從源代碼手動編譯,則可以實現(xiàn)以下更改。若要使用自定義鼠標光標解決此問題,請在引擎源文件的/ Engine / Source / Runtime / WebBrowser / Private / CEF目錄中找到CEFWebBrowserWindow.cpp文件。搜索以下 所示的方法 FCEFWebBrowserWindow::OnCursorChange(...):注意第1708行的#if PLATFORM_WINDOWS II PLATFORM_MAC。它實質(zhì)上是通過手動設置操作系統(tǒng)的光標來繞過引擎的本機光標管理的,除非它是默認的指針或文本編輯器光束。
因此,您應將此行更改為#if,以防止編譯此塊(絕對沒有全局設置可切換它)。以 示例說明了對引擎源所做的更改:
請注意,第1709和1720?之間的塊現(xiàn)在顯示為灰?,并且Web瀏覽器進程的光標將 被適當?shù)赜成涞揭婀鈽祟愋汀,F(xiàn)在,您可以構(gòu)建UE4項?,以將?定義?標光標與Webul插件?起使?:
09—
紋理
可以使?“Read Texture Pixel”節(jié)點或“Read Texture Pixels”節(jié)點訪問瀏覽器的紋理數(shù)據(jù), 如以下示例所示:
這些節(jié)點將分別返回單?或顏?數(shù)組。請注意,沒有創(chuàng)建任何渲染?標來訪問此紋理數(shù) 據(jù)。相反,這些函數(shù)使?瀏覽器的基礎紋理引?直接在渲染線程上執(zhí)?命令。還請記住,瀏覽器紋理的??可能并不總是與視?中的?部件的??匹配。因此,提供 了“Get Texture Width”和“Get Texture Height”節(jié)點以訪問基礎瀏覽器紋理的??:10
—
工具
聚集對準時,可以使?CTRL + SHIFT + I調(diào)試瀏覽器。此組合鍵可打開ChromeDevTools,并且僅在開發(fā)和調(diào)試版本中可?。
您可以在以下地址的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 (...)方法,如以下示例所示:
請注意,附加到瀏覽器子進程命令行的兩個開關(guān)enable-gpu和enable-gpu-compositing。您將需要將這兩個開關(guān)更改為disable-gpu和disable-gpu-compositing,如下所示:
現(xiàn)在,您可以構(gòu)建 UE4項?, 并在啟?WebGL的情況下使?WebUI插件:
性能表現(xiàn)
版本4.24到4.26的引擎安裝默認情況下啟用了 WebGL,這會大大降低性能(尤其是對于全屏界面)。但是,如果您從源代碼手動編譯,則可以實現(xiàn)以下更改。打開/ Engine / Source / Runtime / WebBrowser / Private / CEF 目錄中的CEFBrowserApp.cpp文件。搜索FCEFBrowserApp :: OnBeforeCommandLineProcessing(...)方法,如以下示例所示:請注意,附加到瀏覽器?進程命令?的兩個開關(guān)enable-gpu和enable-gpu-compositing。您將需要將這兩個開關(guān)更改為disable-gpu和disable-gpu-compositing,如下所示:
現(xiàn)在,您可以構(gòu)建UE4項?,以在禁?WebGL的情況下使?WebUl插件:
12
—
編譯
可以為其他平臺或引擎版本手動編譯此插件。首先打開命令提示符(通過在開始菜單中 搜索"cmd”)并鍵入以下命令:
cd "C:\Program Files'Epic Games \UE_4.21"您可以通過右鍵單擊命令提示符來復制并粘貼此命令。還要注意UE_4.21目錄。您需要將 此文件夾更改為與您所使用的引擎版本相對應的版本。如果未將引擎安裝到默認目錄,請鍵入自定義安裝文件夾的路徑。按輸入運行命令。現(xiàn)在,您應該看到類似于以下內(nèi)容的輸出:
然后鍵入以下命令來構(gòu)建插件:Engine\Build\BatchFiles\RunUAT.bat.BuildPlugin-Rocket-Plugin="..." -Package="..."將第一個替換為WebUI.uplugin的路徑,將最后一個替換為臨時"package"文件夾 的路徑。您也可以將.uplugin文件或您的臨時文件夾直接拖放到命令提示符下,它將自動鍵入路徑:
確保這些路徑不在引擎目錄中,否則構(gòu)建將失敗。輸入完整的命令后,其外觀應類似于以下內(nèi)容:
如果您的計算機不支持Mac或Linux構(gòu)建,則您很可能必須從WebUI中刪除"Mac"和" IOS”或"Linux"平臺。編譯前添加:
現(xiàn)在按輸入鍵運行命令。如果一切設置正確,您將看到正在為各種平臺編譯的插件的許多不同版本。構(gòu)建完成后,您應該會看到"BUILD SUCCESSFUL"信息:
檢查您的臨時"package"文件夾,以確保其外觀類似于以下內(nèi)容:
然后,將該臨時文件夾中的文件復制到您的引擎安裝目錄中。如果要編譯需要 Webul插件的任何其他插件,則必須事先執(zhí)行此操作。
您現(xiàn)在已經(jīng)成功為您的引擎版本編譯了Webul插。制心一處 無事不辦
加入我們:
UE4美術(shù)×1
UE4產(chǎn)品經(jīng)理×1
UE4客戶端開發(fā)(藍圖)×1
數(shù)字可視化平面設計師×1