在做游戲的過程中,性能 是個無所不在的話題。為了創建夢幻般的畫面,我們需要至少游戲幀數至少達到每秒 15 幀。根據不同的平台和游戲類型,這個幀數可能是 30 或者 60,甚至在某些情況下要求更高。
虛幻引擎提供了很多功能,它們也有不同的性能特性。為了達到性能的要求會需要對游戲素材和代碼進行優化。因此需要能夠知道性能花費在何處。這一點可以通過使用引擎的性能分析工具。 每個性能問題都可能是不同的,需要對當前的硬件、軟件都有一定的了解。這里我們整理了一些細節應該能在這方面有所幫助。
這篇指南主要涵蓋的是渲染的話題,因為通常渲染是性能花費最多的地方。更多的物件,更高的分辨率,更多的燈光,漂亮的材質,所有這些都會在性能上有所影響。 還好是在渲染上,這里要重新獲取性能也相對容易,很多渲染的特性都可以直接在控制台中調整。
編輯器的輸出日志,或者游戲的控制台中內,可以:
-
設置控制台變量(cvarname value)
-
獲取當前的狀態(cvarname)
-
查看某個變量的幫助(cvarname ?)
如果需要的話,可以將設置保存到 ConsoleVariables.ini 文件中,語法是:cvarname=value。要使用正確的控制台變量,可以使用DumpConsoleVars,或者利用系統的自動補完功能。大部分渲染變量都是以 r. 開頭。
-
需要了解更多控制台變量以及引擎優化的開關選項的話,請查看 調整引擎功能的級別 頁面。
通用提示
理想情況下,應該盡可能的貼近想要關心的目標來做性能分析。舉個例子來說,一個好的分析案例是,在目標平台上,對帶有已完成 Lightmap 構建的獨立游戲版本進行測試。
要做到好的分析,最好是能夠設置可重現的過程,這樣能隔離開那些可能對結果產生干擾的因素。即便是編輯器也會增加干擾(比如,一次打開 內容瀏覽器 的窗口就會增加渲染的開銷)因此最好是直接分析游戲程序。 在有些情況下,通過修改一些代碼也將會非常有幫助(比如,禁止隨機數的生成)。另外,在希望游戲狀態更穩定的情形下,Pause 命令和 Slomo 0.001 命令也是非常有用的。
多測試幾次可以來獲得分析工具的精確度。Stat 命令,比如 stat unit 和 stat fps 能夠提供一些數據結果。分析的精確度應該做到毫秒級別(ms),而不是用每秒幀數(fps)來衡量。 毫秒的度量方式能夠很容易的來做比較,而幀數的結果要很橫向比較就很困難。在面向一個具體的單獨功能討論時,我們應該只討論它的毫秒數量的性能,而非測量幀數。
如果發現幀數限制在了 30 fps(約 33.3ms)或者 60 fps(約 16.6ms)時,很可能啟用了垂直同步(VSync)。為了更准確的測量性能花費的時間,最好是在分析時去掉垂直同步。
對於一個簡單的場景也不要期望有極高的幀數。為了優化復雜場景的性能,很多設計上的抉擇(比如延遲渲染)會具有一個較高的最低開銷。因此可能會遇到一個整體環境的最高幀數的限制。 需要的話,這個限制可以被手動設置(比如 t.MaxFPS,r.VSync)(譯者注:無論怎么設置,都不可能突破軟硬件環境的下的最高值)
-
關於游戲內容和場景的性能設置上的提示和教程,請參考 性能指南 頁面。
-
關於 stat 命令的信息,請參考 Stat Commands 頁面。
定位到性能局限的原因
現代的硬件有很多單元在並行工作(比如,GPU 上有內存單元,三角面/頂點序列/像素處理等,而 CPU 上是多個 CPU 並行,內存單元等)。通常各個單元都會互相等待其他單元的工作。 首先要做的是找到哪個部分導致了性能的局限。針對這部分的優化都能夠帶來性能表現的改善。如果對錯誤的地方進行優化,則是一個浪費時間的事情,並且有可能會引入新的 BUG,甚至在其他地方引起問題。 一旦對當前局限的部分做了優化后,通常應該重新再做一次分析,一般來說都會找到又一個性能瓶頸處,而這新的瓶頸是由於剛剛的優化改善而暴露出來的,通常在改善前都處於不容易發現的狀態。
首先,要先檢查幀數是被 CPU 所限還是 GPU 所限。任何時候都可以改變程序的負載(比如調整分辨率)來看一下會有什么結果。這里可以通過 stat unit 功能來檢查引擎。
![]() |
---|
命令:stat unit |
游戲的實際單幀時間由這三者之一限制:Game(CPU 游戲線程),Draw(CPU 渲染線程)或者 GPU(GPU)。 圖中我們可以看到 GPU是限制主因(三者最大的一個)。為了取得更少的 單幀 時間,在這個情形下必須先優化 GPU 的負載。
Show Flags
引擎的 Show Flag 可以用來對諸多渲染特性進行開關。編輯器在一個 2D 的界面中已經列出了所有的 Show Flag。可以打開該菜單后對一個或者多個勾選框進行點擊選擇。
在游戲中,可以使用 show 命令。通過 show 可以獲得所有 Show Flag 的列表以及它們各自的狀態。使用 show showflagname 可以開關某個具體的特性。請注意這個方式只在游戲窗口中起效,如果是編輯器窗口, 應該使用編輯器的菜單。還可以通過命令行變量(比如showflag.Bloom)來覆蓋游戲或者編輯器中的 show flag 數值,這也會使得界面功能失效。
一個不錯的分析的起點是從較高層的功能着手,比如 show StaticMeshes,或者 show tessellation。
所有的 Show Flag 都暴露給了命令行變量。比如命令行中 show Bloom,可以通過 showflag.Bloom 0 或者在配置文件相應位置添加 showflag.Bloom = 0。 命令行變量需要打幾個字,但它們能夠覆蓋編輯器界面上的控制,並且可以寫在配置文件中。
分析的時候比較有用的 Show Flag 如下:
Show Flag | 描述 |
---|---|
ScreenSpaceReflections | 切換屏幕空間的反射效果,可能會非常影響性能,對那些達到一定粗造度的像素有效(由 r.SSR.MaxRoughness 調節,或者在后處理的設置中設定)。 |
AmbientOcclusion | 屏幕空間環境遮罩(對有些場景獲益非常有限,比如那些在 Lightmass 中已經對靜態物體做了環境遮罩烘培的狀況)。 |
AntiAliasing | 切換各種抗鋸齒(TemporalAA 和 FXAA),用 TemporalAA 切換到 FXAA(更快,但效果較差)。 |
Bloom | 影響那些受到 lens flares 和 bloom 功能的畫面。 |
DeferredLighting | 切換所有延遲光照通道。 |
DirectionalLights PointLightsSpotLights | 切換不同的光照類型(這在檢查哪種光照類型影響性能時較有用)。 |
DynamicShadows | 切換所有的動態陰影(陰影貼圖的渲染,以及陰影的過濾和投影)。 |
GlobalIllumination | 切換預烘培和動態間接光照(LPV)。 |
LightFunctions | 切換光照函數渲染。 |
PostProcessing | 切換所有后處理效果。 |
ReflectionEnvironment | 切換環境反射效果。 |
Refraction | 切換折射效果。 |
Rendering | 切換整體渲染。 |
Decals | 切換貼花渲染。 |
Landscape Brushes StaticMeshesSkeletalMeshes Landscape | 輪詢切換幾種不同的幾何體的渲染 |
Translucency | 切換透明度渲染。 |
Tessellation | 切換曲面細分(仍將運行曲面細分 shader,但生成更多三角面)。 |
IndirectLightingCache | 切換是否動態物體或者靜態物體具有使用間接光照 Cache 時無效的光照貼圖。 |
Bounds | 顯示編輯器中當前選中物體的邊界框。 |
Visualize SSR | 將所有收到屏幕空間反射的像素顯示為亮橙色(較慢),請看下圖。 |
![]() |
---|
命令行:r.SSR.MaxRoughness 0.9 = 最佳質量(左),r.SSR.MaxRoughness 0.1 = 運行較快(右) |
Unlit(上),show VisualizeSSR(下) |
視圖模式
視圖模式就是一系列的 Show Flag 的預設組合。編輯器界面中,和 Show Flag 單獨分開,也可以直接使用 ViewMode 的命令行來切換。 對於性能比較有用的是:Wireframe,LightComplexity,ShaderComplexity 和 Lit。(分別是線框模式,光照復雜度模式,Shader 復雜度模式 和 正常的光照模式)
幾個不同的視圖模式(按閱讀順序):光照模式,光照復雜度(越暗越好),線框模式,Shader 復雜度(綠色代表性能優良)
如何處理大范圍的不同硬件
虛幻引擎在諸多圖形功能中都預設了 可擴展性。不同的游戲對此有不同的要求,因此建議使用訂制系統。
可以在命令行中輸入 SynthBenchmark 來使用該工具。
FSynthBenchmark(V0.92):===============MainProcessor:...0.025383 s/Run'RayIntersect'...0.027685 s/Run'Fractal'CompiledTarget_x_Bits:64 UE_BUILD_SHIPPING:0 UE_BUILD_TEST:0 UE_BUILD_DEBUG:0TotalPhysicalGBRam:32NumberOfCores(physical):16NumberOfCores(logical):32 CPU PerfIndex0:100.9 CPU PerfIndex1:103.3Graphics:AdapterName:'NVIDIA GeForce GTX 670'(OnOptimus the name might be wrong, memory should be ok)VendorId:0x10de GPU Memory:1991/0/2049 MB ...4.450GigaPix/s,Confidence=100%'ALUHeavyNoise'...7.549GigaPix/s,Confidence=100%'TexHeavy'...3.702GigaPix/s,Confidence=100%'DepTexHeavy'...23.595GigaPix/s,Confidence=89%'FillOnly'...1.070GigaPix/s,Confidence=100%'Bandwidth' GPU PerfIndex0:96.7 GPU PerfIndex1:101.4 GPU PerfIndex2:96.2 GPU PerfIndex3:92.7 GPU PerfIndex4:99.8CPUIndex:100.9GPUIndex:96.7
基於一段時間來生成圖表
基於一段時間來獲取狀態數據並生成圖表也是很有用的方法(比如用游戲內的過場,或者設置一段攝像機路徑作為測試案例)。
下面的圖表就是來自一段安卓設備的過場畫面。在這個過場的開始處和結束處,輸入了命令行命令 StartFPSChart 和 StopFPSChart。 然后用微軟的 Excel 打開結果文件 .csv (保存在 [ProjectFolder]\Saved\Cooked\Android_ES31\SubwayPatrol\Saved\Profiling\FPSChartStats 處)。 在這里例子中,我們刪掉了頭四行,選擇全部,並插入了一個線狀圖的散列表。
![]() |
---|
命令行:StartFPSChart, StopFPSChart |
更多關於性能和分析的話題
在做游戲的過程中,性能 是個無所不在的話題。為了創建夢幻般的畫面,我們需要至少游戲幀數至少達到每秒 15 幀。根據不同的平台和游戲類型,這個幀數可能是 30 或者 60,甚至在某些情況下要求更高。
虛幻引擎提供了很多功能,它們也有不同的性能特性。為了達到性能的要求會需要對游戲素材和代碼進行優化。因此需要能夠知道性能花費在何處。這一點可以通過使用引擎的性能分析工具。 每個性能問題都可能是不同的,需要對當前的硬件、軟件都有一定的了解。這里我們整理了一些細節應該能在這方面有所幫助。
這篇指南主要涵蓋的是渲染的話題,因為通常渲染是性能花費最多的地方。更多的物件,更高的分辨率,更多的燈光,漂亮的材質,所有這些都會在性能上有所影響。 還好是在渲染上,這里要重新獲取性能也相對容易,很多渲染的特性都可以直接在控制台中調整。
編輯器的輸出日志,或者游戲的控制台中內,可以:
-
設置控制台變量(cvarname value)
-
獲取當前的狀態(cvarname)
-
查看某個變量的幫助(cvarname ?)
如果需要的話,可以將設置保存到 ConsoleVariables.ini 文件中,語法是:cvarname=value。要使用正確的控制台變量,可以使用DumpConsoleVars,或者利用系統的自動補完功能。大部分渲染變量都是以 r. 開頭。
-
需要了解更多控制台變量以及引擎優化的開關選項的話,請查看 調整引擎功能的級別 頁面。
通用提示
理想情況下,應該盡可能的貼近想要關心的目標來做性能分析。舉個例子來說,一個好的分析案例是,在目標平台上,對帶有已完成 Lightmap 構建的獨立游戲版本進行測試。
要做到好的分析,最好是能夠設置可重現的過程,這樣能隔離開那些可能對結果產生干擾的因素。即便是編輯器也會增加干擾(比如,一次打開 內容瀏覽器 的窗口就會增加渲染的開銷)因此最好是直接分析游戲程序。 在有些情況下,通過修改一些代碼也將會非常有幫助(比如,禁止隨機數的生成)。另外,在希望游戲狀態更穩定的情形下,Pause 命令和 Slomo 0.001 命令也是非常有用的。
多測試幾次可以來獲得分析工具的精確度。Stat 命令,比如 stat unit 和 stat fps 能夠提供一些數據結果。分析的精確度應該做到毫秒級別(ms),而不是用每秒幀數(fps)來衡量。 毫秒的度量方式能夠很容易的來做比較,而幀數的結果要很橫向比較就很困難。在面向一個具體的單獨功能討論時,我們應該只討論它的毫秒數量的性能,而非測量幀數。
如果發現幀數限制在了 30 fps(約 33.3ms)或者 60 fps(約 16.6ms)時,很可能啟用了垂直同步(VSync)。為了更准確的測量性能花費的時間,最好是在分析時去掉垂直同步。
對於一個簡單的場景也不要期望有極高的幀數。為了優化復雜場景的性能,很多設計上的抉擇(比如延遲渲染)會具有一個較高的最低開銷。因此可能會遇到一個整體環境的最高幀數的限制。 需要的話,這個限制可以被手動設置(比如 t.MaxFPS,r.VSync)(譯者注:無論怎么設置,都不可能突破軟硬件環境的下的最高值)
-
關於游戲內容和場景的性能設置上的提示和教程,請參考 性能指南 頁面。
-
關於 stat 命令的信息,請參考 Stat Commands 頁面。
定位到性能局限的原因
現代的硬件有很多單元在並行工作(比如,GPU 上有內存單元,三角面/頂點序列/像素處理等,而 CPU 上是多個 CPU 並行,內存單元等)。通常各個單元都會互相等待其他單元的工作。 首先要做的是找到哪個部分導致了性能的局限。針對這部分的優化都能夠帶來性能表現的改善。如果對錯誤的地方進行優化,則是一個浪費時間的事情,並且有可能會引入新的 BUG,甚至在其他地方引起問題。 一旦對當前局限的部分做了優化后,通常應該重新再做一次分析,一般來說都會找到又一個性能瓶頸處,而這新的瓶頸是由於剛剛的優化改善而暴露出來的,通常在改善前都處於不容易發現的狀態。
首先,要先檢查幀數是被 CPU 所限還是 GPU 所限。任何時候都可以改變程序的負載(比如調整分辨率)來看一下會有什么結果。這里可以通過 stat unit 功能來檢查引擎。
![]() |
---|
命令:stat unit |
游戲的實際單幀時間由這三者之一限制:Game(CPU 游戲線程),Draw(CPU 渲染線程)或者 GPU(GPU)。 圖中我們可以看到 GPU是限制主因(三者最大的一個)。為了取得更少的 單幀 時間,在這個情形下必須先優化 GPU 的負載。
Show Flags
引擎的 Show Flag 可以用來對諸多渲染特性進行開關。編輯器在一個 2D 的界面中已經列出了所有的 Show Flag。可以打開該菜單后對一個或者多個勾選框進行點擊選擇。
在游戲中,可以使用 show 命令。通過 show 可以獲得所有 Show Flag 的列表以及它們各自的狀態。使用 show showflagname 可以開關某個具體的特性。請注意這個方式只在游戲窗口中起效,如果是編輯器窗口, 應該使用編輯器的菜單。還可以通過命令行變量(比如showflag.Bloom)來覆蓋游戲或者編輯器中的 show flag 數值,這也會使得界面功能失效。
一個不錯的分析的起點是從較高層的功能着手,比如 show StaticMeshes,或者 show tessellation。
所有的 Show Flag 都暴露給了命令行變量。比如命令行中 show Bloom,可以通過 showflag.Bloom 0 或者在配置文件相應位置添加 showflag.Bloom = 0。 命令行變量需要打幾個字,但它們能夠覆蓋編輯器界面上的控制,並且可以寫在配置文件中。
分析的時候比較有用的 Show Flag 如下:
Show Flag | 描述 |
---|---|
ScreenSpaceReflections | 切換屏幕空間的反射效果,可能會非常影響性能,對那些達到一定粗造度的像素有效(由 r.SSR.MaxRoughness 調節,或者在后處理的設置中設定)。 |
AmbientOcclusion | 屏幕空間環境遮罩(對有些場景獲益非常有限,比如那些在 Lightmass 中已經對靜態物體做了環境遮罩烘培的狀況)。 |
AntiAliasing | 切換各種抗鋸齒(TemporalAA 和 FXAA),用 TemporalAA 切換到 FXAA(更快,但效果較差)。 |
Bloom | 影響那些受到 lens flares 和 bloom 功能的畫面。 |
DeferredLighting | 切換所有延遲光照通道。 |
DirectionalLights PointLightsSpotLights | 切換不同的光照類型(這在檢查哪種光照類型影響性能時較有用)。 |
DynamicShadows | 切換所有的動態陰影(陰影貼圖的渲染,以及陰影的過濾和投影)。 |
GlobalIllumination | 切換預烘培和動態間接光照(LPV)。 |
LightFunctions | 切換光照函數渲染。 |
PostProcessing | 切換所有后處理效果。 |
ReflectionEnvironment | 切換環境反射效果。 |
Refraction | 切換折射效果。 |
Rendering | 切換整體渲染。 |
Decals | 切換貼花渲染。 |
Landscape Brushes StaticMeshesSkeletalMeshes Landscape | 輪詢切換幾種不同的幾何體的渲染 |
Translucency | 切換透明度渲染。 |
Tessellation | 切換曲面細分(仍將運行曲面細分 shader,但生成更多三角面)。 |
IndirectLightingCache | 切換是否動態物體或者靜態物體具有使用間接光照 Cache 時無效的光照貼圖。 |
Bounds | 顯示編輯器中當前選中物體的邊界框。 |
Visualize SSR | 將所有收到屏幕空間反射的像素顯示為亮橙色(較慢),請看下圖。 |
![]() |
---|
命令行:r.SSR.MaxRoughness 0.9 = 最佳質量(左),r.SSR.MaxRoughness 0.1 = 運行較快(右) |
Unlit(上),show VisualizeSSR(下) |
視圖模式
視圖模式就是一系列的 Show Flag 的預設組合。編輯器界面中,和 Show Flag 單獨分開,也可以直接使用 ViewMode 的命令行來切換。 對於性能比較有用的是:Wireframe,LightComplexity,ShaderComplexity 和 Lit。(分別是線框模式,光照復雜度模式,Shader 復雜度模式 和 正常的光照模式)
幾個不同的視圖模式(按閱讀順序):光照模式,光照復雜度(越暗越好),線框模式,Shader 復雜度(綠色代表性能優良)
如何處理大范圍的不同硬件
虛幻引擎在諸多圖形功能中都預設了 可擴展性。不同的游戲對此有不同的要求,因此建議使用訂制系統。
可以在命令行中輸入 SynthBenchmark 來使用該工具。
FSynthBenchmark(V0.92):===============MainProcessor:...0.025383 s/Run'RayIntersect'...0.027685 s/Run'Fractal'CompiledTarget_x_Bits:64 UE_BUILD_SHIPPING:0 UE_BUILD_TEST:0 UE_BUILD_DEBUG:0TotalPhysicalGBRam:32NumberOfCores(physical):16NumberOfCores(logical):32 CPU PerfIndex0:100.9 CPU PerfIndex1:103.3Graphics:AdapterName:'NVIDIA GeForce GTX 670'(OnOptimus the name might be wrong, memory should be ok)VendorId:0x10de GPU Memory:1991/0/2049 MB ...4.450GigaPix/s,Confidence=100%'ALUHeavyNoise'...7.549GigaPix/s,Confidence=100%'TexHeavy'...3.702GigaPix/s,Confidence=100%'DepTexHeavy'...23.595GigaPix/s,Confidence=89%'FillOnly'...1.070GigaPix/s,Confidence=100%'Bandwidth' GPU PerfIndex0:96.7 GPU PerfIndex1:101.4 GPU PerfIndex2:96.2 GPU PerfIndex3:92.7 GPU PerfIndex4:99.8CPUIndex:100.9GPUIndex:96.7
基於一段時間來生成圖表
基於一段時間來獲取狀態數據並生成圖表也是很有用的方法(比如用游戲內的過場,或者設置一段攝像機路徑作為測試案例)。
下面的圖表就是來自一段安卓設備的過場畫面。在這個過場的開始處和結束處,輸入了命令行命令 StartFPSChart 和 StopFPSChart。 然后用微軟的 Excel 打開結果文件 .csv (保存在 [ProjectFolder]\Saved\Cooked\Android_ES31\SubwayPatrol\Saved\Profiling\FPSChartStats 處)。 在這里例子中,我們刪掉了頭四行,選擇全部,並插入了一個線狀圖的散列表。
![]() |
---|
命令行:StartFPSChart, StopFPSChart |