<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>javascript
SIGGRAPH)php
原做:Michal lwanickijava
本篇主要講述 The Last of Us中用到的用到的光照技術,以及解決問題的思路,原做者wanicki是 頑皮狗的引擎工程師,同時也參與了RealTime Rendering 4th的編寫。ios
ppt 原文連接[http://miciwan.com/SIGGRAPH2013/Lighting%20Technology%20of%20The%20Last%20Of%20Us.pdf]app
同時也要感謝下工做室大佬的解惑。函數
因爲遊戲發生在後世界末日,幾乎沒有電,因此沒有人造光源。大部分的光線來自太陽和天空,因此大部分的環境都是由反射光照亮的。工具
有一個很是強大的藝術方向:咱們想展現這個燈光的美麗,它的柔和,它如何在不一樣表面之間傳播,它創造的柔和陰影。咱們想顯示間接光照的鏡面反射高光,並顯示用普通的normal map展現細節。佈局
首先展現一下咱們想要達到的效果性能
如圖所見,全部的光線都很柔和,但同時表面細節也表現的很到位。測試
爲了實現這樣的效果,目前機器性能實時渲染是吃不消的,因此咱們使用了預計算的光照貼圖。雖然光照貼圖應用了這麼多年,可是仍是存在一些根本性的問題。
接縫:在三維空間中相鄰的區域,映射到UV空間中時,可能在不一樣貼圖的相交區域,若是沿分割線作插值的話,不徹底匹配就會產生明顯的接縫。 (打個比方一個圓柱沿豎線剪開,展uv,豎線2側在三維空間中多是連續的,可是uv空間展開以後不連續)
常看法決方法:在運行時,花費額外的開銷,去減弱接縫,或者對物體在uv空間中的位置作一些限制。
爲何沒有用在The Last Of Us中:美術的體量不匹配,不適合當前的項目,效率低下,成本過高,沒法集成到項目的管線中。
咱們發現,咱們的主要矛盾就是接縫兩側插值不匹配的問題,因此咱們經過了修改邊緣紋理的強度,來讓他們匹配起來
如上圖所示的例子,先介紹下概念,綠色和紫色是空間中的2個mesh,紅點虛線是分割邊,在這個分割邊上,取了不少個點,Ci0表示綠色mesh中i點相鄰4個像素的 插值, 在紫色mesh中一樣有一個點Ci1,若是Ci0 = Ci1 最好,咱們把同一個點在相鄰mesh上的偏差定義爲他們的平方差
$$\ C_{i0}= \sum_{j}^{4}{W_{0ij} * T_{0ij}}$$ $$\ C_{i1}= \sum_{j}^{4}{W_{1ij} * T_{1ij}}$$
$$E_i = (C_{i0} - C_{i1})^2 $$
整個光照貼圖的偏差函數,就是各個點的偏差之和。
當有了偏差函數以後,使用最小二乘法,把紋理的值做爲變量,優化過程,經過修改texel的值,確保偏差最小,爲了確保最後的結果不偏離最初計算的值,引入了一個約束懲罰計算值的偏離,這個值用戶能夠調配。
若是你仔細觀察,就會發現,最小二乘最小化,其實在其它不少地方用到過。好比遊戲遊戲中 3D LUT(Look Up Table,直譯過來就是查找表的意思。因此LUT的本質就是輸入一個特定的值轉化爲一個對應的輸出值)管線的顏色校訂,流程以下
比較的結果多是,有嚴重的變色,這時候偏差函數被定義爲兩幅圖片中的平方差,經過修改volume texture 使偏差最小,會取得一個比較好的結果。 LUT擴展閱讀(https://zhuanlan.zhihu.com/p/37717976)
回到燈光中,咱們但願在沒有直接光照的狀況下,避免表面平坦,因此光照貼圖中需要包含光照的方向信息。
咱們評估了不一樣的方案,HL2(半條命)的Radiosity Normal Mapping,用6個方向的vec3來記錄光照信息。(https://drivers.amd.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf)。
好處是相比SH(Sphere harmonic),計算量會稍微少點,可是用在曲面上,由於是插值的緣由,細節丟失的會多一點。
目前2018年UE4和unity都用上了SH。
最後選擇了一個簡單的方案,爲每一個光照貼圖 同時存儲Ambient(環境光)和Directional(方向光)。
經過使用 「環境光」 + 」方向光」 的方案,有幾個好處
對於光照貼圖的每一個texel紋理,烘焙工具會有光照發布的信息,咱們分爲2個組件
咱們經過GI bake 的工具生成了SH(球諧函數sphere harmonics) lightmap,經過這樣的方式(環境光+方向光)表示最終的效果。
$$I = C_{amb} + C_{dir} * max((\vec N,\vec L),0 )$$
經過這種表達方式,還能夠表示表面的高光。
看看效果,感受還不錯。
雖然理想很美好,可是當咱們添加了人物以後,有點蹦。
人物看起來很奇怪,爲何呢,由於人物在與環境交互的時候,會產生陰影,看起來是環境的一部分,而上圖卻沒有。
經過查閱一些資料,咱們在sh指數化的論文中獲得了靈感,用一組球體來近似遮光罩,並經過將它們以一種奇特的方式相乘,結合被描述爲sh向量的可見性函數。
問題是要獲得滿意的陰影,須要高的sh階。斯蒂芬·希爾在《分裂細胞》中用二階sh對AO作了相似的事情。
raytrace one week 第三本 和pbrt14.6章 都有介紹。(https://computergraphics.stackexchange.com/questions/4288/path-weight-for-direct-light-sampling)
圓錐的角度是能夠調整的,可讓美術來控制陰影邊緣的大小,
先經過使用SPU(主機平臺的一種流處理器單元)去渲染陰影到緩衝區,GPU在渲染的時候,從緩衝區中讀數據,再最終渲染出結果。
4-5個角色差很少要6-7ms,可是用了這種方法,代理分割到6個SPU單元,2ms就搞定了。
這樣能夠很好的提升運算效率,在測試場景中,模型精度講到1/4,計算獲得的陰影基本很難看出區別,很是有效。