UE4官方藍圖優(yōu)化總結
FestEurope 2019 藍圖深入探討|Blueprint In-depth 官方視頻
UE4官方藍圖優(yōu)化總結
?

----------------------------------------------------------

????藍圖的消耗主要是在節(jié)點之間,藍圖連線觸發(fā)的消耗是一致的,但節(jié)點運行的消耗是通過C++ ,節(jié)點不同就有所不同. (意思應該是簡化節(jié)點連接的數(shù)量可以降低藍圖消耗)
----------------------------------------------------------

????與循環(huán)邏輯有關的節(jié)點,性能開銷都很大. 因為在循環(huán)節(jié)點中,會有很多連線. 根據(jù)實際需要來使用.
?----------------------------------------------------------

????遍歷Actor的節(jié)點同樣性能開銷很大 , 建議使用時把遍歷結果保存下來.
?----------------------------------------------------------

????大量使用每幀更新節(jié)點,同樣開銷很大. ?后面會有一些方法來優(yōu)化他.
?----------------------------------------------------------

????藍圖是單線程執(zhí)行, 循環(huán)次數(shù)上限是100萬 , 所有藍圖每幀指令執(zhí)行次數(shù)上限是25萬.
?----------------------------------------------------------

????藍圖本身作為預制體不會產(chǎn)生性能開銷. 只有預制體特別復雜的時候才會. 總的來說影響不大.
?----------------------------------------------------------

????藍圖開銷對比. ?編輯器模式(紅色)運行下效率不高. 但打包(藍色)和開發(fā)模式(黃色)要低很多, 比C++高10倍左右.
?----------------------------------------------------------


????這些類似的節(jié)點都是每幀來更新的 , 包括輸入,時間軸,更新動畫,UMG的綁定.
優(yōu)化建議:
1.?避免過多使用每幀更新, 最直接有效
2.?當使用每幀更新時,盡量思考是否必要. 80%-90%的情況是用不到的
3.?

????????可以禁用藍圖每幀更新,如果不需要.
4.?

????????定時器可以處理幾乎所有的節(jié)點更新

????如果場景里有很多實例,不希望在同一時間內(nèi)循環(huán),導致開銷驟增,可以使用隨機時間來分攤開銷.
5.?

?????盡可能使用基于事件的更新, 上圖中UMG綁定會每幀更新.
?6.?

?????可以禁用藍圖每幀更新,或者修改更新間隔. ?如果沒有每幀更新的事件,禁不禁用沒有區(qū)別.
7.?

?????可以通過設置一些條件來啟用每幀更新. 方法很簡單,但效果明顯.

????同上 可以通過設置一些條件來修改更新頻率.??

????有個節(jié)點Was Recently Rendered,能提供最近是否渲染.如果是false可以考慮關掉或者降低更新頻率.
8.?視覺效果不一定要像邏輯處理一樣每幀更新.
???????根據(jù)情況在適當?shù)臅r候拆分邏輯


????每幀更新部分,邏輯沒有變,但降低了開銷.
9.?

????簡單的動畫可以使用材質來實現(xiàn),不必用藍圖來寫. 用材質是使用GPU, 藍圖會消耗CPU. 并且比藍圖更快.?

?????任何簡單動畫和淡入淡出效果或其他效果.都可以使用材質來處理.材質總是比藍圖快.
-------------------------------------------------------------
性能分析和調試
1.??


????Window--->Developer Tools--->Blueprint Debugger 方便查看所有監(jiān)測值
2.?可視化日志

????場景中可視化查看變量變化位置和記錄軌跡,需要創(chuàng)建或者在現(xiàn)有藍圖里添加

????設置復雜 ?下面是設置在Tick事件的Heath后面,記錄Heath變化和場景中發(fā)生變化的位置

????? 然后打開Window--->Developer Tools--->Visual Logger窗口
3.?分析工具
????統(tǒng)計數(shù)據(jù)窗口

????控制臺輸入 Stat Game

????Dumpticks 命令 輸出場景中所有每幀更新的Actors.

????Profiler 常規(guī)分析工具.

????自動測試 ?設置復雜

????藍圖要先設置測試事件和測試內(nèi)容, 然后是開始測試事件和返回值.
????關卡名前綴必須FTEST_
????打開Window--->Developer Tools--->Session Frontend窗口
?

????測試完成會返回參數(shù)窗口.
?
-------------------------------------------------------------
內(nèi)存和加載
????藍圖和C++ 內(nèi)存加載上完全不同 , 藍圖屬于資源內(nèi)容 C++就是C++
????如果使用C++ 所有的C++代碼都會在初始化時加載,當你啟動項目時,項目會加載所有C++類,
????藍圖只有在需要時才會加載.
?
????如果C++ 引用了內(nèi)容. 那么一開始就會加載這些內(nèi)容.
?

?


????藍圖之間的互相引用都會導致加載所有相關的內(nèi)容 , ?如果不加以控制,就會失控.
?

????Size Map會顯示加載內(nèi)容
?

????計劃并組織引用的管理方式. 務必考慮這點.
????避免藍圖引用和巨量的大型資源, 試著把藍圖拆分成父類藍圖和子類藍圖
?
引用建議:
????創(chuàng)建層級清晰的結構,明確有關資源引用位置的規(guī)定
1.?所有關鍵類都定義在C++中
2.?確保有一個藍圖繼承自C++
3.?另一個藍圖以合理的方式繼承自父類藍圖
4.?內(nèi)容最好在第三步中引用

?????看起來像這樣
?
-------------------------------------------------------------
?
庫 (函數(shù)庫,宏庫,任何類型的藍圖庫)
????如果使用庫中的任何一個,整個庫都會被加載,請注意這一點
????如果庫中的函數(shù),用到了引用, 這個引用也會被加載
????(下圖 ?不要在函數(shù)中引用外部資源, 應該作為傳入.)



????游戲模式也能幫助區(qū)分引用
?

????動態(tài)資源加載 , 異步加載資源(Async Load Asset) 然后引用網(wǎng)格體
?

????如果你有很多需要軟引用的部分,可以使用Maps來存儲,通過關鍵字查找,方便配置和管理.
這是一種資源映射.
?

?????在編輯器和最終打包出來的加載時間是完全不一樣的.
????Engine.ini 可以禁用”加載時重新編譯”?(如果藍圖損壞,編輯器可能在加載時因為重新編譯崩潰.)
?
-------------------------------------------------------------
?
垃圾回收/GC
????在游戲中銷毀某個對象時,他不會被立即移除,而是被隱藏, 只是被簡單標記為不應該存在,實際上并沒有從游戲中刪除,為了刪除他,我們要遍歷場景中所有對象,然后明確這個對象應該消失,但我們不能總這樣做, 因為開銷很大. 這時候就要用到垃圾回收.每隔一段時間,引擎就遍歷場景中所有對象,然后刪除. 這個就是垃圾回收.

????由于要遍歷對象, 所以開銷有點大 ,通常沒有必要特別關注他. ?只需要了解垃圾回收有一個統(tǒng)計信息.
?

?????可以修改垃圾回收的間隔時間, 默認61秒 ,游戲不建議修改. 如果是電影,根據(jù)內(nèi)存情況可以修改成1小時.
?

????集群,所有藍圖中都有這個設置
????(然而,集群和GC通常是復雜的,啟用集群并不是一個好主意.
????最好的辦法是,如果你要處理大量生成和摧毀的話,最好找C++程序員來處理.)
?
-------------------------------------------------------------
?
編譯
1.?編譯時間對于運行時執(zhí)行沒有任何影響
2.?通常編譯時間長就預示著涉及很多轉換和引用,內(nèi)容不夠優(yōu)化,內(nèi)存占用很有可能超過應有的限度
3.?
?????編譯時間通常受三個方面的影響
????(1)??節(jié)點數(shù)量
????(2)??轉換和引用, 導致引用的其他藍圖也編譯
????(3)??循環(huán)引用
?4.?

????藍圖編譯有上限 64KB , 編譯會提示失敗信息. 正常情況是不會達到上限的, 除非犯了某些錯誤.
5.?
????使用宏不會對編譯產(chǎn)生幫助
????但是函數(shù)會帶來巨大的變化
????可以依賴函數(shù)來降低編譯時間 ,有助于降低編譯壓力,還能減少編譯大小. 相對于宏更好
6.?
????(1)?將功能拆分成不同的藍圖Actor. 例如 子類,子actor ,組件
????(2)?將邏輯移到C++
????(3)?實際情況很復雜, 什么時候該遷移, 遷移多少等等.
?
-------------------------------------------------------------
?
轉換|Cast To

????轉換會同時影響編譯,內(nèi)存和引用
?
????當你將某個Actor(藍圖) 轉換成第二個Actor(藍圖)時, 當編譯第一個時,除非轉換前后沒有變化,否則會一同編譯第二個Actor(藍圖), 可以緩存結果,但如果你改變了兩者,編譯這個或者那個, 就會出現(xiàn)連鎖反應.
????例如:

?

????看起來簡單的藍圖, 但轉換目標是一個十分復雜的藍圖. 空變量轉換失敗, 打印一段字符串,但卻需要編譯30s . 僅僅因為cast to的目標復雜. 所以轉換成功與否并不重要,只要參轉換與就會有影響
????轉換是指藍圖之間的轉換, 廣義上引用也屬于這種轉換.

????任何引用都會產(chǎn)生類似的效果, 舉例,你想獲取他的類型(Get Class)是否是特定的類, 這個轉換會耗時30s
?
轉換建議:
1.?

????玩家可能已經(jīng)加載到內(nèi)存,不會對內(nèi)存造成壓力.但會稍微降低編譯時間.
2.?

????如果轉換的對象很簡單,也不會有什么問題
3. 如果有個藍圖只包含變量, 不包含其他內(nèi)容.轉換和引用他不會有太大問題
4.?

?????如果將核心類轉換到特定類, 例如將玩家類轉換到交通生成類,通常就會產(chǎn)生問題,因為只要玩家類出現(xiàn),這個交通生成類就需要編譯. 所以不要這樣做. 除非你的游戲始終有一個交通生成類. 但這里假設沒有.
5.?

?????如果你在核心類之間來回引用,從內(nèi)存角度來看,可能沒有區(qū)別,但會增加編譯時間, 問題不大,但仍然要小心,有可能會變成這樣. (下圖)

?

????一般可以這樣簡化理解, 讓偶爾出現(xiàn)的依賴性功能 ,引用始終存在的核心功能, 但反過來不行, 這是普遍做法.
6.?

????不斷將內(nèi)容轉移到C++中或者采用其他技巧最小化引用的影響.
????使用C++來橋接類. 經(jīng)常這樣做 ,方法很簡單. 很多示例都這樣做, 即使不是程序員也可以操作. 有助于你使用藍圖. ( 用C++代碼獲取一個藍圖里的變量信息,直接在另一個藍圖里像節(jié)點一樣直接創(chuàng)建使用, 而不必要Cast To 來轉換獲得.)
?

????函數(shù)也可以這樣操作.?
7.?

????當你進行轉換時,請試著先轉換成父類. 藍圖始終能轉換成父類. 你可以用一種方法讓他觸發(fā)子類中的特定功能,但你只引用父類.(子類繼承事件)
?
????例如 父類中只有變量和事件,子類中事件后實現(xiàn)功能, 其他藍圖只用轉換或引用父類事件即可直接觸發(fā)子類功能.


?
-------------------------------------------------------------
?
接口/ Interface

????最早用于藍圖通信的方法,比Cast To轉換還要早.
????從不引用特定的類,只獲取你查看的Actor,具體是什么Actor要視情況而定, 可以是任何東西.
????即使Actor 沒有實現(xiàn)接口, 他也會忽略這點, 所以你甚至不需要檢查這樣做是否正確.
?


????你也可以檢查一下, 是否實現(xiàn)了接口 ,相比使用”獲取類”方法,你可以檢查是否實現(xiàn)了接口,如果實現(xiàn)了, 就接著完成其他操作 .避免了硬引用.
?
?-------------------------------------------------------------
?
?
標簽系統(tǒng)

????使用標簽系統(tǒng)或者使用”游戲技能系統(tǒng)”插件提供的標簽系統(tǒng), 為場景中的對象綁定了很多標簽,以便確認當前我們在處理什么內(nèi)容. 而不必直接引用這些內(nèi)容.
????例如, 這是玩家可以拾取的物品,為他綁定標簽, 這樣我們可以隨時判斷出是否是玩家可以拾取的物品.無需獲取類才能得出結論,只需檢查標簽.你只需指定好標簽, 然后在藍圖中查找檢查Actor的標簽,獲取標簽數(shù)組,遍歷他.
?
????最佳實踐往往是混用這些方法,所以沒有絕對的完美方案. 不是說有些方法完全不要用, 而是權衡各種之間的利弊, 取長補短,深思熟慮,選擇合適的方法.
?
-------------------------------------------------------------
?
競態(tài)條件

????競態(tài)條件是指兩個或多個類相互依賴, 但他們可能會暫時失效. 因為你不知道哪個會先運行
?

?????請經(jīng)常使用 ”IsValid”?確保對象存在.
?
-------------------------------------------------------------
?
C++

????C++和藍圖是緊密聯(lián)系在一起的. 藍圖所做的一切都依賴于C++
????每個節(jié)點基本上都是C++ , 用C++擴展藍圖很容易.
?
????通常 大型游戲項目中的比重大約80%C++ vs 20%BP , 非游戲項目可能不一樣. 根據(jù)實際情況來.
?
?????建議團隊中所有人都學習藍圖的使用.??
????即使是程序員也花點時間學習了解一下藍圖. 這將提供很大幫助, 有助于縮小團隊之間的鴻溝,有助于讓程序理解美術師和設計師在什么樣的環(huán)境中工作,他們?nèi)绾喂ぷ?藍圖如何工作. 以及虛幻引擎的工作方式,引擎有哪些類,常見流程是怎么樣的. 理解美術師和設計師需要什么.哪些對他們會很有幫助.
????另一方面建議美術師和設計師學習C++ ,以便能使用簡單的C++技巧. 有助于理解程序員的工作.
????拉近彼此的距離,這是促進團隊成長的最佳方式.
?
????C++更效率,更適合管理大型復雜系統(tǒng),執(zhí)行數(shù)學運算,無法用藍圖實現(xiàn),或者無法用藍圖實現(xiàn)最優(yōu)效率,藍圖是有局限性的. 你可以用藍圖做很多事情, 但有些功能實現(xiàn)起來可能很困難.
?
????藍圖優(yōu)勢:原型更快,可視化能讓團隊成員參與進來加快速度,激發(fā)創(chuàng)意,編譯更快,迭代更快,調整功能也更容易.
????簡單來說,他有助于理解邏輯流,更靈活,更容易被團隊成員接受.
????內(nèi)存方面也更有優(yōu)勢, 因為他屬于內(nèi)容
?

????C++類使用時甚至可能是空的,你可以創(chuàng)建它以防萬一 ?(核心功能,重要變量)
????C++類可以一直是空的
????藍圖類包含簡單功能或畫面效果,可以包含聲音和畫面有關的效果.
????考慮到上面提到過的內(nèi)存管理技巧,任何內(nèi)容引用都最好在藍圖中實現(xiàn).
?
?????通常會在一個以上地方用到的功能最好由C++實現(xiàn),最好是超過兩個地方用到.
????例如有個背包系統(tǒng), 馬和玩家都用到了它.
????如果某個功能每幀都要使用,特別是關聯(lián)了很多Actor,使用C++更合適
????如果功能很復雜且容易出錯.C++更合適.
????保存游戲, 網(wǎng)絡, 關鍵變量和枚舉. C++更好.
?
?????大多數(shù)內(nèi)容引用都應該放在藍圖中, 同樣要看具體情況
????任何簡單明了,直觀可見的內(nèi)容. 藍圖
????一次性功能. 藍圖
????處于原型并需要快速迭代的內(nèi)容. 最好還是留在藍圖中
?

????上面使用C++橋接藍圖的部分代碼實現(xiàn)
?

????使用C++實現(xiàn)藍圖函數(shù)庫
?

????建議程序員把一些方法暴露給藍圖供所有人使用, 讓設計師可以使用,有助于產(chǎn)生新的想法和讓所有人參與進來. 即使最終沒有使用到.
?
-------------------------------------------------------------
?
其他內(nèi)容

????推廣“DOP”標注 表示有意斷開的鏈接.
?


????純函數(shù) 沒有執(zhí)行引腳
?

????生成時公開,生成Actor時,會得到那個屬性. 位于SpawnActor節(jié)點內(nèi)會出現(xiàn)這個變量的屬性.
?

????啟用在”編輯器中調用”?在藍圖事件中勾選Call in Editor ,非運行狀態(tài)下,可以調用事件測試.
?

????將一個變量公開到動畫 Sequencer ?
????創(chuàng)建一個事件 SetNameOfVariable, Set開頭+變量名稱, 在Sequencer時間軸運行, 事件運行, Sequencer就會運行 . 這樣可以在Sequencer中的變量發(fā)生變化時,將變量值打印出來.
?

????刪除未使用的變量
?

?

?????顯示3D控件
????勾選后Actor藍圖就會在視口中顯示變量的3D控件(菱形標志),可以通過拖動來改變變量,不用輸入就能改變變量的值,更直觀.
?

?????如果你想廢棄某些過時和不需要的藍圖內(nèi)容,又不想刪除他,因為其他內(nèi)容還需要依賴他,你可以標記他,讓人們不會繼續(xù)使用他.
????Class Settings--->Deprecate
?

?????書簽

????創(chuàng)建和顯示窗口, 還能顯示注釋框 ,方便查找功能位置
?
?

????字符串表
????類似一張表格, 必須輸入”key”和”source string”?,”key”負責增加條目,他會和一個字符串綁定,與之前的”Maps”映射類似,一邊是字符串,一邊是資源. 只是字符串換到了另一邊.他對本地化這類工作很有用.
????例如創(chuàng)建一個”key”標識符,把他標記為”主菜單1”的文本, “key”是你內(nèi)部使用的信息,然后將他與實際文本綁定,如”開始”,然后你可以本地化了.
?

????Maps類似 ,映射表示兩個對象的關聯(lián)關系, 你可以讓某個資源始終與另一個資源關聯(lián),可以是任何類型的資源. 網(wǎng)格,特效,變量 等等 .能減少邏輯復雜度和管理難度.
?

????集合Sets也類似 ,有點像一個數(shù)組, 他有一些內(nèi)部邏輯, 一個對象只能添加一次 .具有唯一性.
????如果是普通數(shù)組,我們要自己編寫邏輯來判斷是否有重復. 集合避免了這一點. 他能自動檢查是否有重復的元素.
?

????IsValid 上面提到過了
?

完