1. 場景管理的資料結構:

總結,遊戲開發最常用的空間資料結構是四叉/八叉樹和BVH樹,而BSP樹基本上隻能應用于編輯器上,k-d樹則隻能用在特殊問題應用場景。
2. 幀同步與狀态同步:
https://gameinstitute.qq.com/community/detail/132935
https://gameinstitute.qq.com/community/detail/115782
3. 描述一下渲染管線?
渲染管線的主要功能是決定在給定虛拟相機、三維物體、光源、照明模式,以及紋理等諸多條件的情況下,生成或繪制一幅二維圖像的過程。概念上可以将圖形渲染管線分為三個階段:應用程式階段、幾何階段、光栅化階段。
建議閱讀《Unity Shader入門精要》P72-P85,深入了解渲染流水線中涉及的坐标變換。
參考《RTR3提煉總結》P6-P32,《Unity Shader入門精要》P6-P17。
4. 齊次坐标: 既能夠用來明确區分向量和點,同時也更易用于進行仿射變換。
仿射變換是線性變換後進行平移變換(其實也是齊次空間的線性變換),使用齊次坐标使得仿射變換可以以統一的矩陣形式進行表示。
https://guangchun.wordpress.com/2011/10/12/affineandhomogeneous/
https://www.cnblogs.com/csyisong/archive/2008/12/09/1351372.html
https://zhuanlan.zhihu.com/p/73123357
5. 螢幕後處理?
将場景渲染到一個附加到幀緩沖對象上的顔色紋理中,之後将在一個橫跨整個螢幕的四邊形上繪制這個紋理。既然整個場景都被渲染到了一個紋理上,我們可以簡單地通過修改紋理資料建立出一些非常有意思的效果。
https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/05%20Framebuffers/
6. 延遲渲染?
可以将延遲渲染( Deferred Rendering)了解為先将所有物體都先繪制到螢幕空間的緩沖(即 Gbuffer, Geometric Buffer,幾何緩沖區)中,再逐光源對該緩沖進行着色的過程,進而避免了因計算被深度測試丢棄的⽚元的着色而産⽣的不必要的開銷。 也就是說延遲渲染基本思想是,先執行深度測試,再進行着色計算,将本來在物空間(三維空間)進行光照計算放到了像空間(二維空間)進行處理。
延遲渲染的優點:
- 隻渲染可見的像素,節省計算量。
- 對後處理支援良好。
- 在大量光源的場景優勢尤其明顯。
延遲渲染的缺點:
- 記憶體開銷較大。
- 讀寫 G-buffer 的記憶體帶寬用量是性能瓶頸。
- 對半透明物體的渲染存在問題。在這點上需要結合正向渲染進行渲染。
- 對多重采樣抗鋸齒(MultiSampling Anti-Aliasing, MSAA)的支援不友好,主要是因為記憶體開銷和記憶體帶寬需要太大。
- 由于對像素點進行着色,無法針對每種物體使用自定義的着色器。
Gbuffer中儲存的資訊包括:頂點位置向量、漫反射顔色向量、法向量、鏡面強度(Specular Intensity)浮點值、光源的位置和顔色向量、錄影機的位置向量等等。
另外可參考:
https://learnopengl-cn.github.io/05%20Advanced%20Lighting/08%20Deferred%20Shading/
https://zhuanlan.zhihu.com/p/102134614
7. 着色處理方法?
平滑着色(Flat shading)、高洛德着色(Gouraud shading)、馮氏着色(Phong shading)。
高洛德着色的缺點:
- 着色後仍然可以看出一個個小平面的效果
- 高洛德着色對于強高光反射的表面, 可能會産生失真(artifacts)。如果在多邊形的中心有高光,而且這個高光沒有擴散到該多邊形的任何頂點,使用Gouraud着色法就不會渲染出任何效果;而如果正好是多邊形的頂點上有高光,那麼這個點上的高光是正确的,但插值會導緻高光以很不自然的形式擴散到相鄰的多邊形上。
- 另外注意 Phong Shading 和 Phong Lighting Model 的差別,前者是考慮如何在三個頂點中填充顔色,而後者表示的是物體被光照産生的效果。
參考《RTR3提煉總結》P38
8. 透明物體渲染?
要想讓混合在多個物體上工作,我們需要最先繪制最遠的物體,最後繪制最近的物體。普通不需要混合的物體仍然可以使用深度緩沖正常繪制,是以它們不需要排序。但我們仍要保證它們在繪制(排序的)透明物體之前已經繪制完畢了。當繪制一個有不透明和透明物體的場景的時候,大體的原則如下:
- 先繪制所有不透明的物體。
- 對所有透明的物體排序。
- 按順序繪制所有透明的物體。
https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/03%20Blending/
9. Draw Call?
DrawCall很簡單,就是CPU對圖形繪制接口的調用,CPU通過調用圖形庫(directx/opengl)接口,指令GPU進行渲染操作。每一次繪制CPU都要調用DrawCall,而在調動DrawCall前,CPU還要進行很多準備工作:檢測渲染狀态、送出渲染所需要的資料、送出渲染所需要的狀态。而GPU本身具有很強大的計算能力,可以很快就處理完渲染任務。當DrawCall過多,CPU就會很多額外開銷用于準備工作,CPU本身負載,而這時GPU可能閑置了。
優化方法例如批處理(Batching):盡量把小的DrawCall合并到一個大的DrawCall中,這就是批處理的思想。使用批處理我們需要在CPU和RAM中合并網格,合并的條件至少是:同材質、同貼圖、同shader,最好網格頂點格式也一緻。
https://zhuanlan.zhihu.com/p/26077873?refer=c_83023344
10. 執行個體化?
執行個體化這項技術能夠讓我們使用一個渲染調用來繪制多個物體,來節省每次繪制物體時CPU -> GPU的通信,它隻需要一次即可。如果想使用執行個體化渲染,我們隻需要将glDrawArrays和glDrawElements的渲染調用分别改為glDrawArraysInstanced和glDrawElementsInstanced就可以了(注意執行個體化數組的使用)。
可以使用uniform數組傳遞每個執行個體的資料,但數量很大的時候就用不了了,uniform數組有大小限制。最好的做法是使用執行個體化數組。執行個體化數組(Instanced Array),它被定義為一個頂點屬性(能夠讓我們儲存更多的資料),僅在頂點着色器渲染一個新的執行個體時才會更新。通過調用glVertexAttribDivisor這個函數告訴OpenGL該什麼時候更新頂點屬性的内容至新一組資料。
https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/10%20Instancing/
11. 邊緣檢測算子:Sobel算子、Canny算子等。
https://www.cnblogs.com/wj-1314/p/9800272.html
12. 提前深度測試及其失效的情況
現在大部分的GPU都提供一個叫做提前深度測試(Early Depth Testing)的硬體特性。提前深度測試允許深度測試在片段着色器之前運作。隻要我們清楚一個片段永遠不會是可見的(它在其他物體之後),我們就能提前丢棄這個片段。片段着色器通常開銷都是很大的,是以我們應該盡可能避免運作它們。當使用提前深度測試時,片段着色器的一個限制是你不能寫入片段的深度值。如果一個片段着色器對它的深度值進行了寫入,提前深度測試是不可能的。OpenGL不能提前知道深度值。
提前深度測試失效的情況包括:
- 開啟Alpha Test:由于Alpha Test需要在像素着色器後面的Alpha Test階段比較,是以無法在像素着色器之前就決定該像素是否被剔除。
- 開啟Alpha Blend:啟用了Alpha混合的像素很多需要與frame buffer做混合,無法執行深度測試,也就無法利用Early-Z技術。
- 開啟Tex Kill:即在shader代碼中有像素摒棄指令(DX的discard,OpenGL的clip)。
- 關閉深度測試。Early-Z是建立在深度測試開啟的條件下,如果關閉了深度測試,也就無法啟用Early-Z技術。
- 開啟Multi-Sampling:多采樣會影響周邊像素,而Early-Z階段無法得知周邊像素是否被裁剪,故無法提前剔除。
- 以及其它任何導緻需要混合後面顔色的操作
參考 Learn OpenGL 和 GPU架構 核心問題筆記
13. 卡通着色(Toon Rendering/ Cel Rendering):卡通着色基本的三個要素
- 銳利的陰影(Sharp shadows)
- 少有或沒有高亮的點(Little or no highlight)
- 對物體輪廓進行描邊(Outline around objects)
使用 2-tone 方法來表示光照效果和陰影區域。也稱為硬着色方法(Hard Shading),可以通過将傳統光照方程元素重新映射到不同的調色闆上來實作。具體的着色方法,可以了解為在 Fragment shader 中測試每個像素漫反射 diffuse 中的 NdotL值,讓漫反射形成一個階梯函數,不同的 NdotL 區域對應不同的顔色。
參考《RTR3提煉總結》P166-P167
14. 描邊算法:輪廓描邊的渲染方法?
分為以下五種:
- 基于視點方向的描邊
- 基于過程幾何方法的描邊
- 基于圖像處理的描邊
- 基于輪廓邊緣檢測的描邊
- 混和輪廓描邊
參考《RTR3提煉總結》P167-P171
另外可參考:https://zhuanlan.zhihu.com/p/25939794
https://blog.csdn.net/candycat1992/article/details/45577749
15. 判斷點是否在三角形内:
https://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html
16.射線與球體相交檢測?
聯立光線方程和表面方程求解方程。
17. 如下圖
若兩個 AABB 在三個次元上的區間都重疊,則兩者相交。
OBB 要使用最多 15 個分離軸去判斷兩者是否相交。
參考
AABB碰撞檢測
OBB碰撞檢測
Cocos2d-x教程-三維物體OBB碰撞檢測算法
18. 漫反射方程1/π的由來?
19. 怎麼光栅化一個三角形?
計算三角形的最小包圍盒,判斷包圍盒中的每個像素是否位于三角形内,是的話則進行着色。
20. PBR知道嗎?它的一些模型?比如高光模型這些?
PBR即基于實體的渲染。渲染方程(Render Equation)是用來模拟光的視覺效果最好的模型。而PBR的渲染方程是用以抽象地描述PBR光照計算過程的特化版本的渲染方程,被稱為反射方程。
fr 就是雙向反射分布函數(Bidirectional Reflectance Distribution Function, BRDF),它的作用是基于表面材質屬性來對入射輻射度進行縮放或者權重。BRDF分為漫反射和鏡面反射兩個部分。
漫反射模型用的是朗伯BRDF模型:
其中c代表的是Albedo或表面顔色,類似漫反射表面紋理。
高光模型由3個函數(D,F,G)和一個标準化因子構成。
- D (Normal Distribution Function,NDF):法線分布函數,估算在受到表面粗糙度的影響下,取向方向與中間向量一緻的微平面的數量。這是用來估算微平面的主要函數。
- F(Fresnel equation):菲涅爾方程,描述的是在不同的表面角下表面反射的光線所占的比率。
- G(Geometry function):幾何函數,描述了微平面自成陰影的屬性。當一個平面相對比較粗糙的時候,平面表面上的微平面有可能擋住其他的微平面進而減少表面所反射的光線。
圖形學/OpenGL/3D數學/Unity
21. 知道什麼是IBL嗎?怎麼生成cubemap?
基于圖像的光照。反射方程中計算漫反射輻照度的部分可以預計算出一個新的cubemap,這個cubemap存儲了用卷積(convolution)計算出的每個采樣方向(或像素)ωo的漫反射積分結果。
卷積(convolution)是對資料集的每個入口應用一些計算,假設其它所有的入口都在這個資料集裡。此處的資料集就是場景輻射或環境圖。是以,對cubemap的每個采樣方向,我們可以顧及在半球Ω的其它所有的采樣方向。
為了卷積環境圖,我們要解決每個輸出ωo采樣方向的積分,通過離散地采樣大量的在半球Ω的方向ωi并取它們輻射的平均值。采樣方向ωi 的半球是以點p為中心,以ωo為法平面的。
這個預計算為每個采樣方向ωo存儲了積分結果的cubemap,可被當成是預計算的在場景中所有的擊中平行于ωo表面的非直接漫反射的光照之和。這種cubemap被稱為輻照度圖(Irradiance map)。
22. 深度測試在PC端和移動端的不同?在什麼階段做,光栅化前還是之後?
- 第一個問題不懂,也查不到。
- 深度測試是在片元着色器之後執行的,也就是光栅化之後。但現代GPU有提前深度測試技術,在光栅化之前。
23. SSAO的原理?
對于鋪屏四邊形上的每一個片段,我們都會根據周邊深度值計算一個遮蔽因子。這個遮蔽因子之後會被用來減少或者抵消片段的環境光照分量。遮蔽因子是通過采集片段周圍球型核心(Kernel)的多個深度樣本,并和目前片段深度值對比而得到的。高于片段深度值樣本的個數就是我們想要的遮蔽因子。
24. 頭發怎麼渲染?
參考知乎收藏,暫時未研究
25. 陰影的做法?
Shadow Mapping
參考陰影映射
26. 靜态光照的烘培技術了解過嗎?
參考 輻射度算法
27. 光線追蹤為什麼會出現噪點,怎麼解決?
産生噪點主要有兩個原因:
- 積分過程中光線采樣不足
- 生成入射光線樣本與真實光線的分布有偏差。
在光線追蹤過程中,如果能精确的求解出渲染方程,算出每個點的反射顔色,那麼渲染出的圖檔接近真實照片,不會出現噪點。在求解方程的過程中,對于每個點反射光線的顔色是自發光顔色+反射光顔色,對于自發光部分一般為一個常數值,而反射部分則是一個半球上的積分計算。對于理想鏡面反射,光線的反射隻在一個方向上有值,并不需要生成很多樣本去做積分運算,可以做特殊處理,但是對于漫反射部分,如果要精确的計算出結果,則需在對入射到該點的半球面上的所有光線做積分運算,而直接求解該方程的積分比較困難,在實際光線追蹤應用中則是使用蒙特卡羅的方式近似求解。而在積分過程中需要采樣大量的光線樣本才能讓積分收斂接近真實值,如果采樣不足或者生成的光線樣本分布與真實光線的分布存在偏差就可能會出現噪點。
如何解決噪點問題呢?
噪點是因為采樣引起的,是以我們可以改進采樣來降低它,分為兩種方法:
- 其中改進采樣最簡單有效的解決辦法是提高光線采樣數量,對于路徑追蹤來說,就是提高每個像素點随機生成的光線路徑數量。但是提高采樣數量一方面會增加計算時間,另一方面采樣數量與噪點收斂并不成線性比例,采樣數量提高到一定程度後,噪點降低的幅度變化很小。
- 另外一種改進采樣的方法是重要性采樣(Importance Sampling),由于均勻采樣(Uniform Sampling)生成的光線樣本在各個方向上機率都相同,并不會對燈光特殊對待。在實際應用中,如果能讓随機生成的光線樣本有極大的機率偏向燈光的方向也可以減少噪點。為了防止對燈光的過度采樣,我們還需要對采樣的結果用機率密度函數(pdf-probability density function )做權值調整。這種非均勻采樣,再對采樣結果用pdf權重調整的方式叫重要性采樣。
除此之外,還有一種方法是對最終生成的圖像做後期處理以實作降噪,即通過降噪算法,将極低采樣的光線追蹤結果重建出非常接近用大量采樣渲染得到的收斂後的圖像。
28. 靜态陰影和動态陰影怎麼混合?
???
29. 光線追蹤的抗鋸齒怎麼解決的?
增大采樣率
30. 怎麼渲染鏡子裡面的物體?
方法一:
- 先把除了鏡子外的其他物體渲染到背景緩沖區。
- 清理模闆緩沖區,整體置為零。
- 僅将鏡面渲染到模闆緩沖區中。将模闆測試設定為每次都成功,并且在通過測試時用1來替換模闆緩沖區元素。如果深度測試失敗,則模闆緩沖區對應的像素保持不變。
- 将鏡子前的物體的鏡像渲染到背景緩沖區及模闆緩沖區中。
- 運用透明混合技術把鏡面渲染到背景緩沖區中。
方法二:
- 把錄影機位置按鏡子表面平面進行反射變換
- 從反射的視點渲染場景至一張紋理
- 最後把該紋理再渲染至該反射性表面上。
31. 如何求正交矩陣的逆?
正交矩陣的轉置矩陣和逆矩陣相等
32. 做紋理映射的時候為什麼要做透視矯正?以及如何做透視校正?
三角形面上的正确插值不是線性的,這是由于在投影平面上的相同步長随着三角形面與相機之間的距離增加而在三角形面上産生了更大的步長。圖形處理器必須采用非線性插值的方法來計算紋理坐标映射,以避免紋理映射圖的扭曲變形。
透視插值的公式:
33. 對頂點的法線和位置進行變換的時候有沒有差別?可不可以用同一個矩陣?什麼時候可以用同一個矩陣?
一般情況下,對位置進行變換的矩陣M,若要同時進行法向量變換,需要用M的逆轉置矩陣。然而,當M不包含非統一縮放或者切變的時候,可以直接用M進行法向量變換。
34. 歐拉角、四元數、矩陣描述旋轉的優缺點?介紹一下四元數的插值。
35. 如何判定圓形和線段是否相交?(要求用線性代數的方法)
???
36.msaa發生在什麼階段?延遲渲染為什麼對msaa支援不好?
光栅化階段。主要原因是帶寬消耗太大。參考延遲渲染與MSAA的那些事
37.檢測點是否在扇形之内
面試題:檢測點是否在扇形之内
38. 解析頂點變換中mat4中每個元素在相應階段的作用(左上角mat3、第四列、第四行)
MVP矩陣
39.給定平面上三個點構成三角形,然後随機擷取三角形内某個點
我覺得應該是用拒絕采樣的方法,先随機生成一個三角形包圍盒内的點,判斷在不在三角形内,在的話就保留;否則丢棄并繼續生成直到求得一個在三角形内的點。
40.mipmap和LOD
LOD:當模型離錄影機(可以是人物錄影機或其他錄影機)很遠時,然後根據距離的遠近使用不同模型級别,遠的時候就選擇低級别的模型,近的時候選擇高細節模型,這樣就可以減少模型上面的頂點和面片數量進而提高性能。
mipmap:mipmap針對的是紋理貼圖,大白話就是,一個模型身上會有貼圖,當我們對這個貼圖使用了MipMap技術之後,那麼在遊戲運作中這個模型的貼圖會根據錄影機距離模型的遠近而調整不同的不同品質的貼圖顯示。判斷模型表面距離錄影機遠近的原理是利用ddx和ddy函數計算UV的偏導數,根據UV變化快慢來決定mipmap級别的。參考 渲染的本質:紋理采樣時如何确定正确的mipmap level
41.螢幕後處理如何實作高斯模糊
将場景渲染到一個附加到幀緩沖對象上的顔色紋理中,在像素着色器中對這張紋理進行後處理(高斯模糊),之後将在一個橫跨整個螢幕的四邊形上繪制這個紋理。
42.向量法求異面直線的距離
異面直線的距離
43.介紹一下你知道的光照模型
Blinn-Phong:
Ambient:
Diffuse:
Specular:
其中p是反光度。
PBR參考第20條總結
44.渲染管線中的剔除包括哪些?三維遊戲場景中如何用CPU進行初步剔除不在錄影機範圍内的遊戲對象?
渲染管線中的剔除包括:
- 視錐剔除(軟體)
- 基于Portal的剔除(軟體)
- Clipping&Backface Culling(硬體)
判斷一個物體是否位于視錐棱台内。在實踐中,由于模型往往是比較複雜的,很難精确計算它和視錐體的交集,是以一般是用軸對齊包圍盒(AABB),有向包圍盒(OBB)或者包圍球(BSphere)代替模型本身進行相交計算。
對于複雜場景來說,線性數組的周遊方式往往不夠高效,這時候也可以将場景以層次結構組織起來進行剔除(譬如QuadTree,Octree等)。
(可用BVH樹。除了層次包圍體,其他的空間資料結構同樣也可以用于視錐裁剪,包括上文提到的八叉樹和BSP樹。但是當渲染動态場景時,這些方法便會顯得不夠靈活,不如層次包圍體。)
參考 剔除:從軟體到硬體
遊戲開發中的渲染加速算法總結
45. 紋理映射的算法有哪些?講一下雙線性插值算法。
- 最近點采樣
- 線性紋理過濾
- 各向異性紋理過濾
- 等等
利用比例t,顔色值u0,u1插值出紅色點的顔色值:
46. 碰撞檢測的算法
- 分離軸定理
- GJK算法
47. 透視變換後,為什麼每個分量要除以w?
透視投影為了實作近大遠小的效果,需要把坐标除深度。一般光栅化渲染管道會用齊次坐标,是以在投影矩陣裡加入了這個運算,最後把齊次坐标轉換回歐氏坐标(做除法)。
參考 透視除法
48. 如何避免萬向節死鎖?
使用四元數表示旋轉?
49.背面剔除和遮擋剔除分别在渲染管線哪個階段?
背面剔除:在圖元裝配階段結束之後,根據使用者指定的手向,把面向錄影機或者背對錄影機(一般是背對錄影機)的三角形剔除,剔除後的三角形就不會再進入到Pixel Shader和Rasteriaztion的流程裡。
遮擋剔除:深度測試/提前深度測試的時候。
50.如何判斷兩個矩形相交?
相當于第17條的二維情況:
若兩個 AABB 在兩個次元上的區間都重疊,則兩者相交。
OBB 要使用最多 8 個分離軸去判斷兩者是否相交。
參考
AABB碰撞檢測
OBB碰撞檢測
Cocos2d-x教程-三維物體OBB碰撞檢測算法
51.介紹一下蒙特卡洛方法和積分的估計函數的有偏性和一緻性的概念。
蒙特卡洛積分:
一般在工程實踐中,面對的函數千變萬化,我們很難直接計算得出某個函數的積分的解析解。為了求解函數積分的數值解,蒙特卡洛法是一種強大的積分方法。它的推導過程如下:
假設我們想去求得函數g的積分,首先根據大數定理,任意給定一個實數函數f和随機變量x~p(x),可以得到:
令g=fp,代換上式可得:
它的期望值為:
也就是說,當N取的足夠大時,結果将無限逼近解析積分。
綜上所述,蒙特卡洛方法是一種可以近似計算任意函數積分的數值方法。它的計算分為以下步驟:
1.對一個滿足某種機率分布的随機數進行抽樣
2.使用該抽樣計算g(x)/p(x)的值,作為樣本
3.最後對所有的樣本累加求平均
用蒙特卡洛積分法求積分涉及到兩個問題:1.如何對一個任意分布函數進行抽樣; 2.如何減少方差
第一個問題的解決方法:逆變換算法和取舍算法
第二個問題的解決方法:重要性采樣
- 有偏性:估計量為 I N I_N IN,則 B ( I N ) = E ( I N ) − I B(I_N)=E(I_N)-I B(IN)=E(IN)−I稱為偏差。若偏差為0,則改估計是無偏估計,否則是有偏估計。蒙特卡洛估計是無偏估計。
- 一緻性:當采樣數量 N N N達到無窮大時,估計量 I N I_N IN收斂到 I I I的機率為1,則該估計具有一緻性。
理論上我們比較青睐無偏估計,它使整個估計過程中随機量的分布都以真實值為中心,結果永遠是正确的。但無偏估計不應該引入更大的方差,否則我們需要更大的代價去消除由于方差導緻的錯誤(例如噪點)。
參考《全局光照技術》第4章
52.介紹一下MSAA的原理
MSAA即多重采樣反走樣(multisample antialiasing)。技術原理:
53.知道Alpha Blend和Alpha Test嗎?
- Alpha test是指在fragment shader 裡通過判斷alpha是否滿足一定的條件進而來決定是否discard該fragment,不滿足條件的fragment就被discard,不能通過alpha test。
- Alpha blend是指通過alpha通道來混合兩個或多個物體的顔色,通常用來渲染半透明的物體,如透過玻璃窗看風景。Alpha blend會打開GL_BLEND,然後通過blend相關的OpenGL ES API來控制blend的方式,進而實作将color buffer中的顔色與目前渲染的fragment顔色混合!
54.PBR的金屬度和粗糙度的差別是什麼?比如說粗糙度一樣,金屬度分别為0和1,他們的表現有什麼差別?
光與物體表面進行互動分為兩種方式:光澤反射和漫反射。對于非金屬材質,光澤反射的RGB分量是一樣的,即它不會改變入射光的顔色,僅改變其亮度,是以光澤反射反映的是光源本身,幾乎與物體表面的真實顔色無關。而漫反射部分指的是光折射進物體内部,在物體内部經曆一定的散射後重新從表面散射回原媒體中。是以我們說的物體表面“真實顔色”其實是一個反射率,它表明在其他光照在表面進行漫反射時,在每個方向上的反射率是多少。
PBR有4個材質參數,介紹如下:
- Base Color:物體在白色光照下表面的真實顔色。
- Roughness:材質的粗糙度。越粗糙,入射光越向更多方向反射,物體表面越來越接近Base Color的顔色。越光滑,物體表面越多地反射周圍的環境。Roughness為0形成鏡面反射。
- Metallic:純淨的物體,要麼該參數為0,要麼為1。金屬會将折射進物體表面的光全部吸收,進而使金屬材質将不會有光從表面内部再散射出來,是以金屬材質沒有漫反射部分。
- Specular:入射光垂直于表面時菲涅爾反射率的值,用在Schlick近似計算菲涅爾反射比中。
以上摘自《全局光照技術》
根據光照中metallic的用途,我的看法如下:金屬度會影響Specular的值,金屬的Specular更大,也就是反射率更大。是以粗糙度相同時,比如粗糙度為0,那麼金屬更能看清楚周圍環境,當然此時非金屬也能看到周圍環境,因為粗糙度為0。
55.HDR裡面的tonemapping簡單介紹一下。為什麼要用tonemapping,不用的話有什麼問題?
HDR渲染和其很相似,我們允許用更大範圍的顔色值渲染進而擷取大範圍的黑暗與明亮的場景細節,最後将所有HDR值轉換成在[0.0, 1.0]範圍的LDR(Low Dynamic Range,低動态範圍)。轉換HDR值到LDR值得過程叫做色調映射(Tone Mapping)。
在實時渲染中,HDR不僅允許我們超過LDR的範圍[0.0, 1.0]與保留更多的細節,同時還讓我們能夠根據光源的真實強度指定它的強度。比如太陽有比閃光燈之類的東西更高的強度,那麼我們為什麼不這樣子設定呢?(比如說設定一個10.0的漫亮度) 這允許我們用更現實的光照參數恰當地配置一個場景的光照,而這在LDR渲染中是不能實作的,因為他們會被上限限制在1.0。因為顯示器隻能顯示在0.0到1.0範圍之内的顔色,我們肯定要做一些轉換進而使得目前的HDR顔色值符合顯示器的範圍。
56.Shader裡面如何計算ddx和ddy,描述一下這兩個函數的原理
在光栅化的時刻,GPUs會在同一時刻并行運作很多Fragment Shader,但是并不是一個pixel一個pixel去執行的,而是将其組織在2x2的一組pixels分塊中,去并行執行。而偏導數就正好是計算的這一塊像素中的變化率。從上圖可以看出來ddx 就是右邊的像素塊的值減去左邊像素塊的值,而ddy就是下面像素塊的值減去上面像素塊的值。其中的x,y代表的是螢幕坐标。
參考 Unity shader 中ddx/ddy偏導數的原理和簡單應用
57.射線與球體相交檢測
- 參數方程法
- 優化法
參考 射線與球的相交測試
58.光照計算為什麼必須線上性空間中進行?伽馬校正怎麼做?
- 光照計算必須線上性空間中進行的原因:shader中計算光照的時候,光照公式都預設是線上性空間中進行的。(這是我的看法)
- 對于在非線性空間中的貼圖,需要将其值做一個反 Gamma 校正(即 Gamma 次方),得到一個線性的值,再用于 Shader的計算。但是對于本身已經是線性空間的貼圖,比如某些 HDR 光照圖、法線貼圖、高度凹凸貼圖或者任何非顔色值的貼圖,則都不要使用反Gamma 校正。對于非線性空間的貼圖,盡可能存為 sRBG 格式,對于校正效率更高、更省事,還能得到正确的反鋸齒效果。
- 最終輸出的值在用于顯示之前,需要做一個 Gamma 校正(即 1/gamma 次方)。使用 sRBG 格式的FrameBuffer,則可以自動地在硬體級别做這個處理,而且可以有正确的 Blending 值。
參考 論線性顔色空間的重要性
59.螢幕上的像素點反算出世界空間中的坐标的計算方法
假如我們在後處理shader中能夠拿到一個像素的歸一化坐标即NDC坐标(包括深度),并且得知裁剪空間中點的齊次坐标的w分量,那就可以一步一步反推出世界坐标:先将NDC坐标乘以w轉換到裁剪空間,再乘以投影矩陣的逆轉換回相機空間,最後再乘以世界坐标系到相機坐标系的轉換矩陣的逆——也就是相機坐标系到世界坐标系的轉換矩陣,就反推出了世界坐标。
不過實際在Unity的後處理shader中,我們往往隻能拿到像素的歸一化坐标,拿不到w。是以我們要用另外的辦法。一般我們在後處理shader中,能拿到的是裁剪空間的坐标x,y,z,螢幕的高寬,以及相機的near,far和FieldofView(FOV)。有了這些資訊,我們就有辦法将螢幕坐标直接變換到相機空間的坐标,而無需得知w和投影矩陣的逆。
參考 在Unity的後處理shader中通過螢幕像素坐标和深度貼圖反推世界坐标