遊戲中還原真實世界——神奇的鏡子


3樓貓 發佈時間:2024-02-02 11:32:24 作者:Hakumen Language

前言

過年前準備開一個趣味性強一些的系列,給沒什麼遊戲開發基礎的玩家科普一些豆知識,主要談談為什麼遊戲世界還無法完全模擬真實的物理世界,以及一些細節的現狀和發展脈絡。
這次是玩《波斯王子 失落的王冠》中,我偶然看到一些場景爬牆時會有自己的鏡像反射,讓我聯想到了很多不同3D遊戲中的鏡子和鏡面反射渲染的例子,產生了這個選題。
文中可能有些描述不夠精確,但總的來說應該是沒有技術認知上的錯誤。如有不對也歡迎糾正。

1 引擎的默認渲染下的鏡子會是什麼樣

傳統的渲染(對比光線追蹤來說)方式,介紹到最簡單的程度就是先確定三角面,後著色繪製(這裡面有一些三角面的組織形式和各種優化,就不展開了)。
(圖中展示了從三角面到像素的光柵化( Rasterization )過程,廣義的光柵化也包含從頂點變換到著色的全部流程)
一個引擎的攝像機拍攝到的物體,在非遞歸的情況下(光線追蹤就是一個遞歸方案),為其渲染提供信息的來源是其自身的一些屬性定義——例如顏色、反光程度等等,可以提煉稱為一個物體的渲染材質(Material)。顏色可以由貼圖、自發光顏色、疊加顏色等信息來提供,反光程度常見的有粗糙度模型或金屬度模型(處理大多數實心物體);後續其實還引入了一些其它複雜屬性,但也沒超出預定義的範疇,在當前課題下不展開了。
如果鏡子在渲染時的呈現完全來自於這些定義(也是傳統渲染方式中常規的情況),結合場景中設置的光源,把這些信息代入到一系列換算中,會得到一個最終的顏色——一個反光程度和明暗程度看著似乎對,但是不能反射其它物體的鏡面。
又由於這個鏡面很平,所以對於反射的光線,要麼幾乎看不到,要麼就會非常亮。這就只取決於光源和鏡子的夾角了。
(圖中是《最終幻想7 重製版》中的克勞德臨時房屋的鏡子。圖中的鏡子和刀背就屬於前面提到的光線反射情況,作為虛幻4引擎做的遊戲這個場景做得略粗糙了)

2 只反射靜態物的鏡子

(圖中的圓球展示了這種反射技術)
如果是固定角度看的鏡子,大家可能會想到把需要照出來的物體“截圖”下來作為貼圖“貼”在鏡子上是不是就行了。這種方案實際上的思路也確實如此,整體引入了一種叫預渲染的方案,在編輯時擺好場景後,先生成一個採樣好的場景採樣資源——常常是一個貼圖映射多面體(CubeMap);在運行時,引擎支持鏡子的渲染混合場景某一面的採樣貼圖,呈現反射出場景某個面的效果。這套方案及其擴展也被稱為基於圖像的照明技術(簡稱IBL) 。
(圖中展示了一個CubeMap的例子)
這種方案除了也看不到動態物體外,其實能想到還有一些問題。例如:
1)正常不同角度看向鏡子中的一些物體,其中物體對應的“透視”是會變化的;但是從採樣貼圖中看過去,由於其實是一張圖換了角度看,其實會有些許彆扭感,因為是“失真”的。尤其和鏡子夾角越大,就越假。
2)光源如果會顯著變化,這種採樣也是失效的。採樣結果的顏色只能均勻變化,可能從基礎視覺上都無法反映應有的結果了。(例如加了一個點光源之類)
因為多少有些“不夠真”,所以這個方案常常用來以較低的分辨率覆蓋場景中各類需要反射的面積不大的材質,例如金屬管、泥水坑等等。大場景還常常用表面粗糙、做舊等方案來模糊這個反射面,以減少失真感,同時儘量降低採樣分辨率以提高性能。

3 反射動態物體的鏡子

我是《電馭叛客2077》的PS4Pro版的早期受害玩家,除了各種流式加載慢導致的BUG外,對於遊戲裡的照鏡子需要“讀一下”記憶猶新——當然這個是性能上的Trade Off,是一種妥協後的設計;類似的設計在《死亡擱淺》等遊戲裡也能看到。(*Trade Off這種不太好翻譯的詞還是保留其原詞,避免為其引入不必要的貶義)
具體來說就是遊戲裡的鏡子,在不交互的狀態下看過去表面是模糊的,點了按鈕進行交互後才顯示出自己照鏡子的畫面(此時自己距離鏡子的距離也相對固定)。一方面原因是常規第一人稱視角下自己的頭是不顯示的(有一個版本影子都沒頭,這個不展開了);另一方面就是交互後才開啟了另一個渲染攝像機,這也是下面要提的第一種方案。
1)鏡像攝像機
首先,這個方案是可以覆蓋動態物體和光源變化的,顯然比前一個方案要“真”很多。不能大規模的、常駐的這麼弄的原因也很簡單——每多一個額外的攝像機都是額外的性能消耗,即使降低精度都會大大影響其原本的畫質空間(可以粗略的理解成要渲染的東西翻了倍)所以如果鏡子在畫幅中佔比很小的時候,雖然也可以常駐開一個攝像機做鏡像,但是確實很浪費。
如果對鏡像渲染的內容降低分辨率,是否能節省性能呢?答案是隻能節省顯存,不能減少渲染過程的性能消耗。
這個方案裡還有一個優化奇才,就是Capcom——在《生化危機8》裡有一段八尺夫人照鏡子的過場動畫,動畫結束後夫人一怒之下打碎了梳妝檯,導致鏡子也碎了。這一段雖然是實時渲染的,但是鏡子中的夫人動畫是預渲染的視頻(所以如果你的幀數不穩或很低,就能看到鏡子內外不同步的“奇觀”);之後主角進入場景,由於鏡子也打碎了,也就不用耗性能去處理鏡子的渲染了。
(圖中展示了前面提到的這一段過場動畫)
對於畫幅比較大,視角更可控的一些場合,還有另一種鏡像渲染的方案。
2)屏幕空間鏡面反射
(圖中的車底在反射面上看不到,其實是這個方案的一個問題)
一個經典的場合,假設畫幅的大約一半是湖面,另一半是湖面上要反射的場景,這時可以不從湖底打一個攝像機來渲染反射的內容,而是直接用對應反射位置的場景渲染結果進行採樣(加點噪聲後處理之類)。
這種方案的優勢是不用額外的攝像機就能搞定。先渲染場景,再渲染鏡面反射的部分;鏡面反射的內容是基於已渲染出像素的而不需要從頭繪製,性能上優於額外開攝像機的方案。反射算法的核心主要基於一種叫做Ray Marching(光線步進 )的思路。
相應的,限制也很明顯,例如反射畫幅大於畫面中被反射的場景物體的畫幅時,就會丟失待反射信息,導致失真——遇到這種情況很多遊戲裡看著就是黑的不反射,最多加點模糊啥的就糊弄過去了。
在前光線追蹤時代,這些渲染的方案往往被稱為各種“Trick”;又因為不像物理法則能有普適性,在場景渲染上把這種一事一議的具體需求做好做對,就是渲染優化的重要方面了。(*Trick這種不太好翻譯的詞還是保留其原詞,避免為其引入不必要的貶義)
更多基於實時渲染採樣或Ray Marching的方案還有一些,這裡就不展開了。

4 光線追蹤

(圖中展示了一個充滿反射物體的環境的例子。其實光線追蹤還能覆蓋環境光遮蔽(AO)和軟陰影等等課題,使其以更接近物理法則的方式計算出來)
經歷了前幾個話題,瞭解了反射渲染的一些案例後,就能明白為什麼要在性能允許的情況下引入光線追蹤了——整體思路上還是想以類似物理法則的方式,用一套泛用性更強的方法解決仿真渲染中的各種光傳播問題。現在廣義的光線追蹤往往指包含了路徑追蹤(Path Tracing)的一系列解決更真實渲染的方案。
要簡單的理解光線追蹤,可以認為此時引擎渲染中的視線或光線是可以遞歸彈射的,這種彈射和傳播是符合物理規律的(應有的折射、衍射、漫反射、能量衰減等)——此時以上所有案例中的反射都可以用統一的光線追蹤方案解決了。
在不使用光線追蹤的情況下,影子、室內光照、間接光照等等數不清的渲染課題都要一事一議的用具體的算法來單獨製作和優化;在使用光線追蹤時就是一套方案一視同仁了——越接近真實物理法則運行,渲染方案的泛用性就越強了,只需要一些Trade Off而不需要什麼Trick了。
但是光線追蹤和之前傳統管線那些替代方案是不太能並存的,所以其實大型遊戲開發既要合理使用光追又要對傳統管線優化,至少近10年的渲染優化成本都是加倍的。

結語

實時光線追蹤是一個不斷高速發展的過程,技術細節上我也還在不斷學習,這方面我也是落伍的;但是實際上還有大多數硬件是無法支持質量略高的實時光線追蹤的,因此前面介紹的那些方案還會廣泛並大量存在於3D電子遊戲中,一事一議的來做反射可能會是5年內仍然會延續下去的一個開發課題。
下次更新估計是年後,會繼續更這個系列。

© 2022 3樓貓 下載APP 站點地圖 廣告合作:asmrly666@gmail.com