VR沉浸體驗的要求


以下爲演講實錄:

大家好!今天我來這裏主要介紹的是使用UE4做VR內容的一些優化技巧。VR需要給大家一個沉浸式的體驗,這要求兩點:一點是你的畫面要儘可能的精美,另外一點是你的呈現要儘可能的流暢。

這兩點其實是相互矛盾的,因爲你畫面做的越細緻、越精美,其實你的內容就越重,你的渲染壓力也就越大。你要做到75幀雙眼同時渲染難度就非常高。

我們看用UE4引擎幫你做了多少事情,第一個已經早就完成了。引擎的輸入更新並不是只有一次,傳統引擎輸入可能是遊戲線程一開始有個輸入,把所有這幀的輸入都獲取。獲取完之後遊戲線程再計算遊戲邏輯然後送給渲染線程繪製。這種情況下,假設我們遊戲跑在60幀,最後更新的HMD或者其它輸入設備的最後數據,其實都是要有16毫秒左右的延遲。

最簡單可以做的第一步是引擎在把數據送給渲染線程之前,我們會把整個渲染的View Matrix重新更新一遍,遊戲邏輯是按照這一幀剛開始收集到的數據來計算。視點其實是通過遊戲線程的邏輯線程幾乎已經結束後送給渲染線程來計算的。

爲什麼我要這麼說呢?因爲引擎本身是多線程的,現在很多顯卡都有雙緩存或三緩存的。我們繪製的這一幀,你看到的幀都是前幾幀的內容,這樣給你帶來的延遲是非常重的。少則也有40來毫秒的延遲,超過10毫秒延遲,你就很容易,稍微長一點時間就有不適感。這也是我剛說的,要降低延遲,首先要把渲染的多緩存關掉,也就變成了本來可以多線程渲染的,很多時候需要線程等待遊戲邏輯線程的輸入計算完成才能做這一幀的數據渲染,這其實又對你的渲染壓力造成更大影響。

我們第一步做的是在邏輯線程計算都結束以後重新更新了ViewMatrix。這個是對頭顯設備和輸入設備都做了同樣的操作,包括動作捕捉設備、手柄類的設備,你最後都要捕捉到它的動作。爲了讓延遲更低,所以我們做了一個多次的Deferred的輸入更新。

第二個是我們最近剛做完的一個Demo。這裏有兩個功能,一個是叫Instanced Stereo Rendering,一個是叫HMD Distortion Mask,我們最近測試基本上能在我們的測試Demo上效率提升將近1倍,而且縱觀其他市場上所有支持VR的引擎,還沒有一家在使用這樣的技術。

HMD Distortion Mask,簡單介紹一下。大家都知道通過HMD設備鏡片畸變以後,其實圖像輸出之前是先要反向畸變的,反向畸變後四周其實是黑的,根本不輸出內容的,現在大部分引擎的瓶頸也都是在Pixel Shader(像素着色器)或Fragment Shader(片段着色器)上面,如果我們能讓這些黑色的區域都不去計算PS(像素着色器),黑色的那些區域其實都不經過我們Pixel Shader的運算。其實就能省掉很大的開銷,所以我們做了這麼一個優化。

Instanced Stereo Rendering,這個功能簡單來說,我們VR的輸入在引擎對接,一個是獲取你的ViewMatrix矩陣,在每幀更新時從頭顯設備獲得輸入的ViewMatrix矩陣。另外一個是使輸入的視點往兩邊偏移同距的寬度,來做立體渲染。立體渲染最簡單的做法,引擎的渲染因爲已經是定的,比較簡單的做法就是渲染兩遍,左邊眼睛渲染一遍,右邊眼睛渲染一遍,帶來的開銷就是DrawCall(繪製調用)數翻了1倍。大家做手遊可能對DrawCall都很敏感,尤其是國內的情況,因爲國內現在500塊錢的手機已經算挺好的,主流的開發者面對的是一兩年前的500塊錢的手機,現在主流論點還是手遊的DrawCall要控制在150以下。

我這裏隨便介紹一下,我們Epic做的一個Demo在iPhone5和5s上就能跑得很流暢,跑到30幀的一個Demo。在AppStore上可以免費下載,叫《Zen Garden(禪意花園)》。這個Demo我們主要秀的一個技術就是蘋果的Metal的API,跟現在DX12,OpenGL Next就是Vulkan,包括之前AMD推的Mantle,這一系列大家的主流想法都差不多,包括Console(主機)的那些,比如說索尼一貫的API其實都是這樣,我暴露給你更底層的控制,API的Level更低一點,你自己在引擎裏面去做Draw和Batch的優化。CPU上的開銷就會降到更小。一些做渲染的API,比如說DrawCall這樣的API,開銷不單單是在CPU上,GPU的開銷也非常大。這也是爲什麼移動芯片會對DRAW CALL那麼敏感,開發遊戲會要求大家把DRAW CALL限制在很低的程度。

使用了這些新的圖形API以後,對底層控制更細緻以後,我們可以做很大範圍的優化,比如說我剛纔介紹的《Zen Garden》Demo,最極端的情況下,保持30幀的情況下,渲染的DRAW CALL數可以到5000、到7000,這是非常誇張的數值,在iPhone5IPhone和5s上能夠跑起來的應用。這裏Instanced Stereo Rendering解決的也是一個類似的問題

在大部分圖形API還沒有更新到下一代之前,DrawCall那麼敏感,怎麼解決這個問題?大家考慮一下雙屏立體渲染的時候,視點做那麼小範圍的偏移,我們繪製的內容幾乎是相同的,我Camera看到的東西基本上差不多,尤其是場景裏的Mesh之類的Bounds一般都會超出一些,周圍兩個視角看到不一樣的東西,但都是需要繪製的。這個時候做Instance的思路是什麼?我這兩個繪製並不是完整的繪製兩遍,而是把其中所繪製的Mesh做一個Instance。也就是說Mesh數會翻倍,而頂點數將近減半。

大家用過UE4可以知道,我們做大量草木渲染的時候,做大量同樣物件擺放的時候,我們會用到叫Instanced Static Mesh Component這樣一個東西,這個東西可以有一大批一模一樣的東西,它只記錄每個Instance的Transform的Matrix,也就是說我只記錄它的Position、Uniform的Scale和Rotation的這些信息,每個Instance只記這些信息,因爲它用到的頂點信息都是一樣的。這樣就可把一批東西並在一個DrawCall上。雙屏渲染就是把兩屏的東西都看成一個Mesh的兩個Instance,這樣就可以把本來翻倍的DRAW CALL減到跟以前一樣。假設你的場景本身已經有了大量Instance的情況下,其實圖形API的Instance和Index Buffer也是有上限的,所以在這種情況下,可能Instance的效果不是很明顯,但大部分情況下,在座的各位普通情況下做到的應用和遊戲裏面,這樣基本上都能提升50%以上的效率,這些技術現在是隻有我們支持的。

我們現在正在做,可能在12月中,或者到明年初就會提供的功能,這個跟AMD還有Nvidia合作的,大家知道Nvidia做VR的GameWorks裏有一些功能,其實非常實用,包括多GPU的渲染,還有一個比較有用的多分辨率的渲染Multi-Resolution,因爲我們知道人眼都只對你關注的,看的中間位置比較敏感一些,所以其實屏幕中間的分辨率渲染的更高一點,周圍的渲染更低一點,這也是降低我剛纔說的Pixel Shader瓶頸問題,跟剛纔的HMD Mask有異曲同工的妙處。

這裏是引擎內建已經有的內容,對於不管是第三方的硬件商,HMD的接入商,還是對內容開發者來說,都是大家需要了解,但不需要關心的內容,這也是底層已經儘可能的幫開發者做的一些優化。

下面我主要要講的內容還是開發者自己本身需要用到的一些內容。爲了方便起見,我們自己做的VR Demo都是經過深度優化的,我來剖析的話,前期的那些項目工程,我這裏其實也已經沒有了,所以剖析的效果可能不是那麼好。因爲我拿到的數據都是優化後的數據,我這裏先隨便拿一個Demo來做一個簡單的剖析。

大家在MarketPlace上都可以看到,是Particle(粒子)的Cave這樣一個Demo。展示一些粒子效果,粒子本來就是很費的東西,這個Demo不是爲VR準備的,所以這個Demo在VR設備上跑起來,幀數非常低,可能只有三四十幀。

我們來看一下大概的一個優化思路是什麼樣子的。當然第一步很簡單粗暴,先看看瓶頸在哪裏。這些命令對於使用過UE4或者稍微有一些Profiling經驗的人肯定是第一步要做的事情。既然要優化,就要把力量花在你該花的地方,第一步肯定是查找你的瓶頸,看看是CPU Bounding還是GPU Bounding。第二步Stat fps就是看FPS,如果FPS已經滿足了,當然進一步優化總是好事,但是也沒有必要,因爲畢竟優化也是要花費人力、物力的,已經滿足你的目標,就沒有進一步優化的必要。

如果沒有滿足,接下來Stat unit這個東西主要有三個數據信息,大家能看到這裏有一個是Game,一個是Draw,一個是GPU。Game是遊戲邏輯線程這一幀所耗費的時間。Draw也是GPU端的,是渲染線程所耗費的時間。GPU就是GPU耗費的時間。從這裏就能推斷出你是CPU端的Bounding還是GPU端的Bounding,是邏輯線程的Bounding還是渲染線程的Bounding。

對於VR內容,我個人認爲以現在的硬件來看,CPU邏輯線程Bounding的可能性幾乎爲零。如果是CPU邏輯線程Bounding,一定是哪裏的實現或設計出現了嚴重的問題。因爲VR體驗裏不會有非常重的邏輯運算。

我看到那麼多VR Demo裏面,邏輯運算最重的應該是我們自己做過的一款叫《Bullet Train》的Demo,裏面有非常大量的AI,有尋路,是一個類似第一人稱射擊的遊戲,有各種設計的彈道都是ProjectTiled的實體,而不是一個射線檢測,所以動態運算量,CPU的運算量會比較大,但即使是這樣,CPU還是很富裕。跟傳統遊戲來比,我們的電腦CPU已經非常強了,VR對於邏輯的要求,其實跟普通的大型遊戲來比是要輕得多的,所以CPU的Bounding,如果是邏輯線程的Bounding,一般來說意味着哪裏代碼寫的有問題。

比如說大量是靜態的對象,你可能現在是動態的在Tick,然後Tick裏面你做了一些,比如說非常長的空循環之類的不合理的行爲,這個東西其實通過我們的Profiler可以很容易一眼就看出來。

我今天要講的大部分都是GPU的Bounding,一個就是我剛纔說的,如果你Draw Call偏高的話,其實是同時渲染線程Bounding和GPU Bounding都會發生。因爲有時候渲染線程是要等GPU的,你看到數字,這裏可以看到GPU是28毫秒,總的Frame時間也是28毫秒,毫無疑問就是GPU Bounding。因爲這裏面用了大量的Particle和大量的半透,而且是比較暗的場景,肯定Translucency會佔的比重比較大一點,這個色調肯定也是後期處理可能佔的比重也比較大一點。

一般來說GPUBounding的更大的可能性都是在Pixel Shader上面,我剛纔說的這兩個都是影響Pixel Shader的,這是第一感覺看場景以後的。接下來我們來看看具體用什麼比較快的方法能定位問題,然後解決我們的問題。

第一步能做的,這是一個命令行HMD SP 100,我們的HMD接入的設備大部分都有這樣一個Debug的命令行,叫HMD SP,SP(Screen Percentage)是屏幕的比例,相當於是輸出分辨率是固定的,但Render Buffer的分辨率可以調整,100%以後,你會覺得畫面有點糊,不夠精細,因爲眼睛看的是當中的,所以一般我們默認值是120%,如果你的渲染幀數有富裕,甚至調到150%也是可以的,而且這個命令是實時生效的,你可以在遊戲過程中,根據不同的關卡,甚至不同的進程,Camera的位置,來控制參數調整到不同的值,可以在運算比較富裕的時候,展示更精細一點的效果,在優化壓力也很大,沒有辦法做進一步優化的情況下,讓畫面稍微變的糊一點,讓幀數有比較好的提升,這個效果是非常明顯的。

大家看到經過調整以後,我們的整個一幀的渲染時間,已經變到了18、19毫秒,剛剛是28毫秒,已經減掉了三分之一,非常非常的明顯,說明就是Pixel Shader的Bounding,很明顯。一般來說我們判斷是Pixel Shader瓶頸,還是Vertex Shader瓶頸,最簡單的做法就是設置分辨率。HMD的輸出分辨率固定,沒有辦法設置,所以我們提供了這樣一個Debug命令行,你通過這個調整,就能馬上知道,首先能確定是不是GPU Pixel Shader的Bounding,是這個Bounding的話,然後來看影響有多少,而且這個值,雖然理論上是越高越好,但是其實有時候也跟內容有關係。比如說我內容色調不一樣,可能對銳度、精細度的邀請也沒有那麼高,有時候100完全可以接受,甚至我們有些Demo就是放到90的,大家有沒有感受?有什麼不對的地方。這個就是根據項目來,對你來說優化壓力比較大,你可以把這個參數放小一點,這是一個最立竿見影的調整效果。

接下來這個是Editor裏面內建的,我們是調整整個渲染Quality的Scale Ability的設置,本來默認都是開在Epic上面,Epic是最牛逼的畫面效果,我現在先把它調到中等,一下子13毫秒,爲什麼是13毫秒?其實是因爲我們限制了幀數75幀。事實上,如果我們把幀數限制關掉以後,發現可能更短,可能已經能跑到100多幀,這是一個最快的效果。大家看到已經到75幀,是不是滿足我們優化的效果了?可以說是,但肯定也不是,因爲這是以犧牲大量的畫面的渲染效果爲前提的。做這樣一個設置,只是爲了讓我們快速的定位到哪一檔差不多的設置能滿足我們的幀數要求。

接下來要做的就是比較細緻的分析,到底哪些地方有問題了。有一個Profiling的命令行叫Profile GPU或GPU Profile都一樣,這兩個命令行的快捷鍵是“Ctrl+Shift+,”,這個東西在Editor裏面,或者在遊戲Runtime都可以實時的運行,你只要輸入這個命令,我們就會做這一幀的GPU Profiling。我是推薦大家不要在編輯器裏做,起碼出一個Standalone的進程來做這件事。因爲編輯器Slack等各方面也都是要經過渲染前的開銷的,這些東西可能會誤導你對Profiling一些開銷的判斷,所以最好是在Standalone的Game裏面來做這樣一個Profiling行爲。

做完後大家能看到,比較大頭的幾個,一個是Base Pass,一個是Deferred Decals,一個是Lighting,然後是SSR(Reflection Environment),然後是剛剛說到的半透(Translucency),然後是一個後期處理效果(Postprocessing)。最厲害的是Base Pass和Postprocessing。渲染管線相當複雜,我這裏不會更細的闡述,因爲大家制作內容可能也不是那麼關注引擎底層的細節。

我先簡單說一下基本的概念。我們默認是把Pre Z Pass關掉的,如果你看到Base Pass高,引擎提供了很大的便利性,我們有一個命令行,可以打開Early Z Pass,這樣會影響DRAW CALL,因爲有些東西會先繪製一遍。帶來的好處是Base Pass的開銷會大量降低,這個需要你根據自己的場景去嘗試。你看看是打開Early Z Pass總的GPU開銷來的高,還是關掉來的高。在這裏會發現打開Early Z Pass會帶來很大的收益。

大家看到之前是總共一幀用掉了12毫秒,優化後只用掉了8毫秒,另外幾個Decal,我們看你的鏡頭所在位置,首先這個跟你的VR設計內容有關係。如果你看到場景在移動,你自己沒有在移動,尤其移動速度比較快,而且不是線性情況下,人很容易暈,現在很多做VR內容的開發者都從設計層面上解決這個問題,當然我們有可以移動的設備,但是這個設備對大部分人來說,還算是不太實際的設備。從設計上規避,我們儘可能的站在原地不動,然後用Teleport。甚至我可以提供一個思路,比如說我要移動到另外一個地方,比如說按鍵或者手柄各種操作以後,我看到一個虛擬的Avatar。我站在這裏,我看到一個第三人稱的角色往那邊移,Camera並沒有移動到那邊。然後我把某個鍵鬆掉,然後人就Teleport過去。以這樣的形式來呈現就可以避免暈眩。

在這種情況下,我們大部分的時候視點都是固定的,這時候會發現很多位置的貼花Decal等,在屏幕上佔的象素非常低,這種情況下可以把它去掉。我們知道用這種技術是爲了提升畫面效果,但有些時候你需要做一些取捨,比如說這個東西帶來的提升不那麼明顯,那你就可以去掉。Translucency也是一樣。

很多粒子特效,尤其是糊到你臉上的東西是非常非常費的,半透的儘可能不要使用。然後就是後期處理,大部分後期處理肯定都是全屏的都要處理的,所以儘可能的減低後期處理,我們在大部分的Demo裏面都是沒有使用後期處理。

這幾個優化完之後對幀數的影響非常明顯,我們剛纔已經看過了調整分辨率是會很大的提高幀數的,說明是Pixel Shader的Bounding,我們做的這一些包括Translucency和Decal,這些大部分都是影響了提升這一部分的效率。這是優化完以後,優化完以後幀數就已經到75幀了,這是因爲剛說過這裏限幀了。其實現在已經120幀,甚至150幀了。

我們把畫面配置效果,剛剛調過去了,忘調回來了,我們現在調回來,好像依然有75幀,就是說剛剛優化起到效果了。一開始我們做這樣一個設置是降低畫面質量,提升幀數,在我們進一步分析以後,現在我們能把畫面效果再重新調回來,依然達到比較流暢的幀數。

另外還有一些手段,比如說用我們內建的編輯器裏面的一些ViewMode,就能看到比如說這裏的Shader的複雜度,那些有大量半透的粒子,有一些貼花的地方顏色都會比較深。我們的這個ViewMode裏的綠顏色就說明Shader是比較簡單的,紅色就是說明Shader比較複雜,粉色就是非常非常複雜,白色就已經複雜的一塌糊塗了。一般來說,我們場景都會控制在紅色和綠色之間,如果發現你有大量的粉色和白色,Shader肯定已經太過複雜,一定要做比較針對性的優化。

下面的Stat scenerenering,這個也可以看總的DRAW CALL數量,我們最近在970上可以跑到75幀的Demo,我剛纔說的叫《Bullet Train》的Demo,視野最開闊的時候DRAW CALL有1500多,其實已經非常高了。最近CryTek剛剛出來一個恐龍的那個在Steam上免費,那個DRAW CALL數比我們低,當然頂點數很高有大概8M,它的Index Buffer也很高,因爲它是大量的草木環境,所以它用了巨量的Instance,但是在其他的環節上都是我們的數據要高的多,因爲我剛剛說到的,我們做的那個Instance Rendering和HMD Mask的優化,所以使得我們能有比較好的效率,能在大量渲染的負擔更重的情況下,能有一個更流暢的效果。

Stat Scenerenering就可以看到我們比較細緻的一些渲染的Profiling數據,甚至你可以通過,比如說有很多Particle,甚至有些有比較複雜的UI,又會有一些Decal,一些Static(靜態的)和動態的Mesh,,你來第一時間衡量,哪些東西對你的渲染造成最大的影響,你可以先把這一幀的渲染停下來,然後我們有一個Show Flag,可以把每一類我剛說的東西去開關,來看看這些東西對DRAW CALL和幀數的影響。

例如,如果你發現Static Mesh一關,好像DRAW CALL影響從1500降到了可能只有3、400,說明基本上所有的開銷都是在Static Mesh上面,可能需要場景美術去做更大的優化。如果也就降到8、900,說明你有很大的開銷在其他上面,你去優化場景是得不償失的。

ViewMode、Wireframe能看到我們的網格信息,這裏你能看到,比如說比較遠的地方網格非常密,大家知道,如果一個三角面片渲染在2x2象素以內是非常浪費的。我剛纔說的在設計上,我們很多內容都是視點固定的,既然在這個視點看到的內容離你那麼遠,密度就完全不需要那麼高,這時候你可以儘可能的對模型做一些簡化。

剛纔我說的這是一個非常快速的例子,就是拿一個實際的例子來講,我隨便拿到一個Demo,用什麼樣比較快的方法能優化到一個可以在VR裏面跑起來,導致你不暈眩的一個效果。實際上如果你真的做優化,其實有非常多的東西要來關注。

我接下來說的東西可能更細緻一點,但是總體思路跟剛纔一樣。我們先是尋找限制你幀數的原因。測試之前,先要找到一個穩定的環境。我們在做GPU Profiling的時候,我希望不要在編輯器模式下跑,希望你在Standalone的Game裏面跑,或者你即使是在編輯器裏面,你也用編輯器去跑一個Standalone的進程,然後來做Preview。你在測試的時候,因爲Camera移動,你的Oculus Update的信息都是不一樣的,你可能會針對一些,比如說某個角度幀數特別低,你可以把遊戲邏輯停下來,然後把渲染也停下來,這時候你可以用Debug Camera去看看你調的內容,以及不應該被繪製的內容是不是被繪製了。

剛剛我也說到還有一點,我們有一些幀數設置,你可以去把限制最高幀數的設置先打開,因爲在我們降低整個渲染效果以後,很容易就到上限了。所以在做優化的時候,希望先把幀數上限去掉,然後把垂直同步關掉。

這些都是在判斷問題和調試之前要創建的一個比較穩定的環境,當然包括你的目標硬件有沒有在跑其他程序,這些都是有關係的。我們希望在一個比較穩定的環境下,你最終的目標環境下來做這樣一個測試。

這個我剛剛大概解釋過了,就是用Stat unit可以看到這幾個模塊每一幀耗費的毫秒數。這個就能看出來是GPU Bounding,而不是因爲我設置了幀數的上限。因爲如果我設置幀數上限,那一定是Game這裏的毫秒數最高,因爲Game會去每一幀判斷是不是達到上限了,如果沒有達到上限,我還可以Sleep,所以我主線程的時間會跟整個Frame是一樣。如果Game跟Frame一樣可能不是遊戲主線程瓶頸,第一點先查看是否限幀。如果達到目標幀數,又是Game和Frame數值一樣,基本上就是你限幀的關係。

SceneRendering這裏能列出最敏感的信息就是DrawCall,可以看到這裏的DrawCall數量。DrawCall數量多的原因上面說了,計算公式基本上是Mesh數量乘上ID再乘上投影的燈光數。
   
一個比較簡單且高效的優化手段是這樣,我們提供了一些統計的工具在編輯器裏面,你打開Statistics統計面板,按照使用次數排序,能看到被你使用最多的Mesh對象是哪一個,你看一下它的ID是多少,如果它的ID是負數個數,你有很大的可能性,可以做一個非常快的優化。

比如用到了30個不一樣的Mesh資源,其中有50%是用了同一個資源,比如說我就渲染這樣一個場景,很有可能大量的都是椅子,我們先不說椅子做Instance的情況,假設每個椅子是一個獨立的Static Mesh Component的一個Actor,我發現椅子用了三個ID,相對來說我讓美術把ID合併一下,假設這個Mesh佔了一半,本來1500個DRAW CALL,其中有800DRAW CALL是椅子的,我改一下,這800裏面的三分之二就省掉了。並不是說讓美術盲目的判斷Static Mesh造成的影響太大,我就讓美術把所有的Static Mesh,場景裏面的東西能合併的就合併,並不是這樣。一個是Instance這樣的手段,一個是通過使用頻度來減少它的ID,優先減少頻度使用高的對象的ID。

另外你Staionary的燈光,或者動態燈光,儘可能的減少,並且能不要投影的就不要投影,並且減少Overlaid(覆蓋)。

這裏就是我剛纔說的計算公式。這個命令行跟我剛纔說的另外一種方式功能差不多。判斷一下有沒有什麼東西出錯的,這個命令行叫VisualizeOccludedPrimitives,綠色的框就是說這些被Occlude掉沒有繪製的Primitive對象。如果你發現有對象是在它後面的,但是並沒有被綠色的框畫出來,那就意味着有一些東西不對了。一般來說是什麼不對?一般來說是你的Bounds設的太大了。比如說尤其是對於Static Mesh這樣的對象,如果你不是Root Motion的一些動畫,很有可能我人站在這個位置,從這裏移動到那裏,其實我的Root沒有變化,這個時候我的Bounds自動就會變的非常大,最終的結果,我人明明站在某建築後面,被遮擋掉了,但還是在繪製它,引擎認爲這個東西是可見的。這些情況下,需要美術注意,可以通過這樣的命令行來調試發現這樣的問題。

另一種方式是,你Freeze住這一幀的渲染,用Debug Camera去漫遊這個場景,看看從你漫遊之前的Camera位置,需要被遮擋掉的那些對象是不是還能繪製的出來,如果繪製出來,一定是我剛纔說的比如說Bounds設置有問題。這個是跟我剛纔說的配合起來,ToggleDebugCamera可以在Freeze Render那一幀情況下,跑到它的背後去看看被遮蔽的東西有沒有能繪製出來,繪製出來了,就說明有問題。

還有就是ADB和bounding box的計算,如果你的東西不是LocalSpace有旋轉的話,其實它的Bounds也會變大。尤其是長條的物件。

然後一個比較費的就是ParticleParticle,通過Stat Particle能看到Particle的詳細信息。能把一些特別費的Particle尤其是靠Camera比較近的,半透比較多的,利用率比較高的那些做集中的優化。有一些比較離的比較遠的,大家可以多做一些Particle的LOD。遠的那些其實不太敏感。我們知道GPU在做立體渲染(Stereo Rendering)的時候,離屏幕近的那些ParticleParticle很容易穿幫。因爲離視點越近,視差看到的位移就越遠。一般來說,我們的遊戲引擎裏面的Particle都不是一個實體3D空間的對象,其實是類似叫Billboard的東西。它永遠朝向你的Camera,當兩次渲染的時候,它永遠是朝向你左邊一個Camera,右邊是這樣的,並不是實際在中間,視差到兩邊的例子。離你眼睛越近越大的Particle,在3D渲染下錯誤越明顯。這時一般會用一些創造性的作假手段,比如說用一個實體的Mesh來做這樣的Particle,我們也有很多Demo來演示比較有技巧性的Particle。比如說爆炸,比如說一些煙霧軌道,我這裏就不着重介紹了。

我剛纔說的這些就是爲了說明,對屏幕影響比較大的Translucency這些Particle,大部分情況下都可以轉化成Mesh的形式,並不一定要半透。這就是我剛纔說的我們的一個統計工具,靜態場景的統計工具,可以按照上面任何一列做排序。頂點數最多、使用數最多等等,按使用數最多排序,你能看到這個Mesh用了多少ID,是不是需要做進一步的優化。

還有一些比較Tips(技巧性)相關的功能,比如說可以選中一組對象做同樣的優化。比如說這一組Mesh都要做同樣的優化,比如說這一組Mesh對東西的影響都比較小,我都不希望它接受Cast Shadow,或者說我都希望統一對它做某一些優化參數設置如LOD設置等,一個比較簡單的辦法,場景裏面選中它,右鍵可以選中所有使用這個Mesh的對象,選中後你可以打開一個叫Property Matrix的東西,這時候你可以勾選自己需要用到的屬性,勾選了屬性以後,那個頁面上會把橫向是所有你選中的對象,縱向是你選中的屬性,以一個Matrix的形式列出來,你可以很清晰的看到,你同一類對象的參數屬性。因爲當美術不停的往裏面放了很多燈光,有些屬性調整,可能自己也記不清楚了,可以通過這樣Matrix的工具來很方便的把所有你關注的對象的屬性都列出來,很明顯,一眼就能看出來,而且可以做批量調整,非常方便。

這就是我剛纔說的一些Showflag,用來判斷哪些類型的Primitive的繪製對象,對你的幀數影響比較大。這個我剛剛在Showcase示例裏面也講到了,比較方便的,一開始就可以用來調整的HMD的調試命令行。

其實比較主要的,一個是SHADER的複雜度,一個是燈光,一個是後期處理,還有一個是投影。有很多高級的優化技巧,比如說,我們儘可能把Reflection Capture減少,不讓它們Overlaid,甚至把整個場景的SSR都關掉,在《Bullet Train》Demo中就關掉了SSR,但是你能看到很明顯,在火車站的大理石石板上,人和廣告燈箱牌是有倒影的,那些東西是我們自己做的材質,做了一個模擬SSR的材質,這樣就相當於打開逐對象的SSR計算,就可以省去很多不必要的開銷。包括我們在《Showdown》用到的一些Cast Shadow的技巧,我們把大部分的Dynamic Shader都已經去掉了,通過一些簡單的Blueprint的控制,比如說人腳步離地面的遠近,來Scale他腳下黑色的陰影面片大小,這樣可以很好的滿足視覺效果。

我剛纔介紹引擎默認的有一些Viewmode,可以方便的看到Shader複雜度、貼圖密度、燈光密度,引擎各方面的開銷都可以看到。另外一些比較次要,但是對幀數影響也比較明顯的showflag,這些開銷非常大,但是有些時候完全可以捨棄掉。在我們的Demo裏面大家看到畫面效果非常好,但是我們很多時候都不用後期處理和動態投影。

這裏也是我剛纔說的一些,我們在《Showdown》裏面用到的,右邊是太糊了,可能看不太清楚。右邊是我們《ShowDown》的設置,這是我們比較推薦的後期處理的設置,儘可能把所有東西都關掉,右邊的設置就是在《ShowDown》Demo裏面用到的設置。
GPU Profiler是更細緻的每個環節的列表。

除了剛纔說的這些是技術手段上的內容,還有更多的是大家需要在製作之前就制訂一些規範,比如說你最終的目標是跑在什麼樣的硬件上面的,你美術製作的時候,在一開始可能做一些Protype的時候,設置一些美術的標準,根據這個標準來做,後期再做比較統一的優化,這樣效率可能會比較高一點。
   
VR既需要更好的效果,又需要更高的流暢度,但同時VR本身對你的開銷又更高,所以對優化的要求就更大。在剛剛那些內容優化,我們都找到了以後,接下來更細一步的就是美術重新去做美術資源了,來做LOD,做遠處的剔除不必要的東西。也是一些我們用到的渲染參數調整優化。

我們後處理的一些設置。大家能看LPV(一種動態GI的solution)這種東西肯定不能開的。AA,我們基本上也可以不用,所有的AA基本思路就是超採樣,但因爲都是通過採樣定律來做的,要麼是時間上,要麼是空間上的。如果Screen Percentage已經可以提高了,對你來說就不需要開AA了,比如說已經150%了,自然而然就已經AA了。大家知道爲什麼Retina屏幕的手機有些基本上不需要開AA,就是這個原因。這是引擎內建可以做渲染參數調整的一些設置。時間關係,後面的一些設置我就先帶過了。Shader材質的一些統計數據。這裏的Pixel和Vertex Shader的指令數。通過調整Shader來做一些優化。然後燈光儘可能不要Overlap。
   
最後我想說的是,你總是要先定一個目標,如果你的目標機器是非常差的機器,怎麼樣做優化,都不可能滿足你的目標除非改變設計初衷。如果你的目標就是非常強的Titan X或980等,很多時候你也不一定需要做有優化,包括有時候你要認準你的機器,我們很多時候開發可能用的是工具性的比如至強的處理器,主屏可能比較低,CPU的核數比較高,我在編譯開發環境上有優勢,但是引擎做渲染的時候,優勢比較差。有時候你會發現有影響,甚至CPU Bounding怎麼回事,隨便換一塊正常的遊戲用的i7 CPU馬上就解決問題了,根本不需要做什麼優化。其他的就是設計上的考慮,基本上就是這些。

謝謝大家!
發佈了9 篇原創文章 · 獲贊 23 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章