您當前的位置:首頁 > 繪畫

(十)、圖形渲染進階知識

作者:由 玉昆 發表于 繪畫時間:2021-12-08

零、前言

我並不是圖形學專業,也不是做引擎開發的,對圖形渲染的理解都是工作中零零碎碎學到的碎片化知識。我所理解的東西並不保證準確甚至可能有錯誤。最近在整理資料的過程中,對之前模糊的概念有了進一步的認識,所以在這裡記錄下來。期望能對還不瞭解這些概念的人以幫助。

有很多東西其實是可以融會貫通的。比如我們常聽人說AlphaTest效能低,如果更進一步瞭解Early-Z、HSR、TBDR之後,就可以理解為什麼Unity要先渲染不透明物體,再渲染半透明物體。我們常聽人說Drawcall影響效能,更進一步瞭解渲染管線,知道什麼是Drawcall,什麼是渲染狀態,就會更進一步瞭解SetPassCalls是什麼東東。

理解本文中列舉的幾個關鍵知識點,也就可以對渲染最佳化有一定的概念了。回過頭可以再找幾篇顯示卡廠商的最佳化相關的文章做參考。

一、渲染管線

(一)、應用程式階段:

1、粗粒度剔除,把不在螢幕內的模型剔除掉。

2、傳遞頂點等引數給GPU,即Drawcall。

(二)、幾何階段:頂點著色器

1、計算頂點的世界座標

float4 posWorld = mul(unity_ObjectToWorld, v。vertex);

2、得到切線空間到世界空間的轉換矩陣

o。tangentToWorldAndPackedData

3、計算頂點光照

o。ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld);

場景是使用Lightmap。所以這個引數存放的是lightmap引數

角色沒有使用lightmap,一般都開啟頂點光照。所以這裡存放的是球諧光照結果。Light Probe。

總結,頂點著色器的工作就是根據輸入的頂點座標等引數,轉換成世界座標,求得切線空間到世界空間的轉換矩陣,計算頂點光照、頂點霧等引數。輸出結果給畫素著色器使用。

(三)、光柵化階段:畫素著色器

1、把法線圖取到的法線轉換成世界法線

s

normal

=

TangentToWorld

i

s

normal

);

2、得到 albedo、spec和反射率

half oneMinusReflectivity;

s。albedoColor = LIGHTING_SETUP(s, s。specColor, oneMinusReflectivity);

3、GI

3。1、設定光照。

o_gi。light = data。light;

o_gi。light。color *= data。atten;

3。2、間接光的diffuse。靜態物體是Lightmap,動態物體是球諧光照。

Lightmap:

o_gi。indirect。diffuse = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, data。lightmapUV。xy));

or 球諧光照:

o_gi。indirect。diffuse = ShadeSHPerPixel(s。normal, data。ambient, data。worldPos);

3。3、間接光的specular。

對天空球進行取樣,根據粗糙度取到不同的mipmap的反射cube。光滑表面取到的圖片精度較高,能反射清晰的天空球。粗糙的表面取到的精度比較低,反射看著就比較模糊。

half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflect(s。eyeVec。rgb, s。normal), perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS) * (1-perceptualRoughness*0。5);

o_gi。indirect。specular = DecodeHDR(rgbm, unity_SpecCube0_HDR);

3。4、我們額外做了一個把漫反射的lightmap合併到specular上的操作,防止金屬丟失lightmap資訊。因為按照計算,金屬反饋高光比較強烈,但是完全丟失lightmap效果就不太好。

o_gi。indirect。specular += max(0, o_gi。indirect。diffuse - UNITY_LIGHTMODEL_AMBIENT。rgb * 0。1 - unity_IndirectSpecColor。rgb); //additive blend

4、PBL

4。1、GGX CookTorrance

half specularTerm = roughness / (s。eyeVec。a * (1。5h + roughness) * d);

4。2、Diffuse

half3 color = s。albedoColor * (gi。indirect。diffuse + gi。light。color * diffuseTerm);

4。3、高光

color += saturate(specularTerm * nl * gi。light。color * s。specColor);

4。4、菲涅爾

color += surfaceReduction * gi。indirect。specular * lerp(s。specColor, saturate(s。smoothness + (1 - oneMinusReflectivity)), fresnelTerm);

總結,畫素著色器最終得到的就是一個顏色值,由輸入的紋理+光照得來。光照分直接光和間接光。直接光由漫反射(Diffuse)和高光(Specular)組成。間接光由Lightmap、ReflectionProbe得來,這些圖都是Unity烘焙場景時得到的,IBL說的就是間接光的處理。最後再加上PBR中常見的菲涅爾效果的計算。

(四)、延遲渲染(Deferred Rendering)和前向渲染(Forward Rendering)

1、延遲渲染會先進行頂點著色,把模型都渲染到螢幕上,然後再進行光照等複雜邏輯的計算。

好處是多光照模型下,效能很好,效果也很好。

2、延遲渲染一般分成兩個步驟(2個Pass)

第一個Pass渲染G-Buffer。正常渲染一遍場景,經過頂點著色器模型座標變換和片段著色器,計算色彩(diffuse),法線(normal),高光(specular)、深度(depth)、陰影(shadow)等,並把結果快取到記憶體中備用。

第二個Pass利用G-Buffer貼圖中的資料重構每個片段的位置資訊並進行逐光源的光照計算。最後結果會疊加到光照計算結果和陰影等輸出最終的畫素顏色。

3、延遲渲染的好處是可以處理多光源的情況。缺點是無法正確處理半透明,且會消耗更多的視訊記憶體頻寬。

4、還有一種 Forward+ 渲染。思路是將螢幕劃分為一個一個的塊兒,控制每個塊兒的影響燈光數量,從而減輕運算壓力,讓前向渲染也可以處理多光源的情況。不過這個貌似並沒有被廣泛應用。主流遊戲引擎還都是延遲渲染+前向渲染。

5、在移動平臺下,我們都是使用前向渲染。因為從需求來說,手機遊戲一般只有一個實時方向光,幾乎沒有或者很少使用實時點光源,有實時動態光照的需求,一般都是使用LightProbe解決。這種情況下因為燈光數量很少,延遲渲染沒有應用的意義。另外,移動平臺裝置基本上都是TBDR架構,這種情況下相當於硬體層面做了延遲渲染的活,我們在軟體層面就更加沒有使用延遲渲染的必要了。

二、線性空間與Gamma空間的理解

(一)、什麼是Gamma校正 (Gamma Correction),為什麼要進行Gamma矯正

1、早期CRT顯示器,輸入的電流和顯示的亮度不是線性關係,波形是一個下弦曲線(Gamma2。2,即Pow2。2,顏色值會經過2。2的冪計算)。這個影響引數就是Gamma值。

為了正確顯示顏色,需要對輸出給顯示器的顏色進行Gamma校正(Gamma1/2。2,一個上弦曲線,Pow0。45)。

2、人眼睛對暗部的分辨程度要明顯高於對亮度的分辨程度。進行Gamma校正,可以更好的儲存有效顏色資訊。

3、現代的液晶顯示器雖然沒有電流和亮度的問題。但是一方面為了相容CRT顯示器,另外一方面Gamma校正也有顯示意義,所以現在的顯示器都保留了Gamma校正。

4、如果將來科技進步了,人們以32位去儲存顏色資訊而不是現在的8位,那麼Gamma校正就沒有存在的價值了。

(二)、sRGB顏色標準

1、我們透過相機拍攝的圖片,或者是ps儲存的圖片,預設都是以sRGB標準儲存的,顏色經過Gamma0。45的校正。顏色值經過 Pow0。45 儲存,顯示器顯示的時候會進行 Pow2。2,那麼最終顯示的結果就是真實的顏色值。

2、視覺表現上,Gamma0。45 會使圖片變亮,Gamma2。2 會使圖片變暗。

(三)、Gamma空間下的處理流程

1、輸入的圖片是sRGB標準的圖片,Gamma0。45。

2、直接將取樣結果帶入光照公式計算。將結果寫入FrameBuffer。

3、顯示器經過 Gamma2。2,最終顯示成正確的顏色。

(四)、線性空間下的處理流程

1、如果圖片本身就是線性儲存的,那麼就直接取樣即可。

如果圖片是sRGB儲存的,則需要進行 Remove Gamma Correction(Pow 2。2),將顏色轉換到線性空間。

OpenGLES3。0有硬體指令支援,不需要對每個畫素執行Pow操作,否則效能太低了。這也是為什麼線性空間需要OpenGLES3。0的原因。

2、光照計算線上性空間進行。計算完的顏色進行 Gamma校正(Pow 0。45),轉回Gamma空間。這裡同樣有硬體指令支援。

3、顯示器經過 Gamma2。2,最終顯示成正確的顏色。

(五)、為什麼PBR都應該使用線性空間

1、各種光照公式都是線上性空間進行的。比如,1的亮度就應該是0。5的亮度的2倍。但是在Gamma空間下,圖片是 Gamma0。45 處理的。這個係數被帶入光照公式中,計算結果顯然就不對了。 表現結果是亮的地方很容易就曝光嚴重。

2、選擇Gamma空間,則引擎不會對輸入和輸出做Gamma校正。而因為圖片儲存時都是經過Gamma校正的,所以光照計算帶入了 Gamma0。45,最終得到的顏色就跟實際光照結果有偏差了。

3、選擇線性空間,則光照計算都是線上性空間下計算的,輸出的時候才進行Gamma校正轉回Gamma空間。所以光照結果是準確的。

(六)、Unity中紋理 sRGB 選項

1、Gamma空間下,引擎不會對圖片做Gamma校正,是否勾選sRGB選項無影響。

2、線性空間下,勾選sRGB選項,則代表圖片是在Gamma空間儲存的。引擎在載入這些圖片的時候會先執行 Remove Gamma Correction 的操作,恢復到線性空間。

3、線性空間下,如果美術工作流程已經統一,圖片輸出的時候儲存線上性空間,則不需要勾選 sRGB選項。反之,儲存在Gamma空間的,則需要勾選。

4、類似的,shader中輸入的顏色預設也會被認為是 sRGB 顏色,會自動進行 Remove Gamma Correction 的操作。而如果自己定義的 Float 引數也想 Remove Gamma Correction,則需要在引數前新增 [Gamma] 的字首。

三、TBDR、Early-Z和渲染順序

(一)、GPU架構

1、GPU的渲染架構有 IMR(Immediate Mode Rendering,主要用於PC平臺),TBR(Tile-Based Rendering,主要用於移動平臺)和TBDR(Tile-Based Deferred Rendering,針對TBR做了進一步最佳化,主要是PowerVR在用)。

2、大部分手機的GPU用的都是手機的System memory和一塊容量很小的,頻寬比System memory更高的專供OnChip memory。

SRAM,GPU的OnChip memory。可以理解為小區的便利店。雖然比較小,但是訪問速度很快。

DRAM,視訊記憶體,離GPU較遠,可以理解為市中心的超市。比較大,但是訪問速度慢。

從GPU對FrameBuffer的訪問,就相當於一輛貨車大量的在家(GPU)和市中心超市(DRAM)之間往返運輸。頻寬的消耗和發熱量之大,是手機上無法接受的。

3、對移動平臺而言,功耗是第一位。因為功耗意味著發熱量、耗電量、晶片大小等等。

對功耗影響最大的是頻寬。所以對移動晶片而言,第一考慮的不是渲染效能,而是如何透過快取減少頻寬消耗。即,減少對視訊記憶體的訪問。

(二)、IMR、TBR和TBDR

1、IMR(Immediate Mode Rendering),是立即渲染模式。每個畫素渲染的時候直接訪問DRAM,並寫入到FrameBuffer上。PC平臺的顯示卡都是IMR架構。

2、TBR(Tile-Based Rendering),基於Tile渲染。適合移動平臺。

為了減少GPU訪問SystemMemory的次數(延遲高、功耗高),將螢幕分成一小塊兒一小塊兒,確保這一小塊渲染所需要的絕大部分資料都能同時裝進小小的OnChip memory,從而實現整個渲染大部分操作都可以在頻寬較高的OnChip memory上完成。

TBR是以犧牲執行效率為代價,換來功耗降低。在移動平臺直接訪問FrameBuffer會有很大的頻寬開銷,進而影響功耗。所以TBR把螢幕分成格子之後,每個格子可以訪問SRAM(OnChip memory),一整塊都訪問好之後,再整理轉移回DRAM。

3、TBDR(Tile-Based Deferred Rendering),基於Tile的延遲渲染。只對玩家能看到的畫素做 pixel shader。透過HSR將不可見的點剔除掉。大幅減少對視訊記憶體頻寬的消耗。

HSR,Hidden Surface Removal,隱藏面消除。在光柵化階段真正開始前實現畫素級裁剪。

4、TBDR,相對於IMR,多了一個FrameData的資料,裡面包含了有效資訊,可以進行剔除操作。

TBR架構下,是不能來一個CommandBuffer就處理一個的,因為任何一個CommandBuffer都可能會影響到整個的FrameBuffer,如果來一個就畫一個,那麼GPU可能會在每一個DrawCall上都來回搬遷所有的Tile。所以TBR的策略一般是對於CPU過來的CommandBuffer,只對他們做VetexProcess,然後對VS產生的結果暫時儲存。只有必須重新整理整個FrameBuffer的時候(比如Swap Back and Front Buffer、glFluash、glReadPixles等等)才會真正的做光柵化。

這個暫存的資料就是FrameData。FrameData是TBR特有的在GPU繪製時所需的儲存資料。既然TBR是等待所有的FrameData資料一起繪製pixel,那麼就可以實現Deffered Rendering。硬體巧妙的利用TBR的FrameData佇列實現了一種延遲渲染。即,儘可能只渲染那些最終影響FrameBuffer的畫素。

5、為什麼PC平臺不使用TBR?因為實際上直接對DRAM進行讀寫速度是最快的。TBR需要一塊兒塊兒的繪製然後往DRAM複製。可以簡單理解為TBR是犧牲了執行效率,來解決更重要也更難處理的頻寬功耗。

(三)、Early-Z和HSR

1、現代顯示卡(無論是IMR還是TBR),會在執行畫素著色器之前,先進行一輪深度測試,就是EarlyZ。以避免會被深度測試剔除的片元,執行復雜的畫素著色器的邏輯。這樣可以減少視訊記憶體頻寬的消耗。

如果沒有Early-Z,那麼很有可能螢幕上一個畫素點會被渲染七八次,視訊記憶體頻寬消耗成倍的增加。

2、AlphaTest在畫素著色器才會執行clip操作,才知道會不會剔除這個點。因此使用AlphaTest後,EarlyZ會無效。所以AlphaTest在移動平臺效能比較低。

discard或者clip會導致Early-Z Culling無效。

3、HSR,Hidden Surface Removal,隱面剔除。這個是PowerVR的專利技術,它可以在硬體層面對被遮擋的點進行剔除。它可以保證螢幕上的點不會被重複渲染,比Early-Z更加高效。

支援HSR的裝置(一般是iOS裝置),可以不用對物體進行排序,因為HSR已經可以保證裁剪掉被遮擋的片元,也就不依賴Early-Z了。

對不支援HSR的裝置,還是需要對物體進行排序,以儘可能的利用好Early-Z。

4、HSR比Early-Z更加高效。

一方面不用對物體排序了,省去了軟體層面排序的CPU開銷。

另外一方面Early-Z無法有效保證一個點不會被重複渲染。比如一個超大的模型,軟體層面排序應該是離攝像機較近的,應該先渲染,但是實際上它的很多點都是被遮擋的,應該被剔除掉。

(四)、渲染順序

1、不透明物體,離攝像機近的先繪製,這樣它會因為ZTest剔除掉後面的渲染內容,效能更好。

2、半透明物體,必須從後往前畫,先畫離攝像機遠的物體,才能保證渲染結果正確。

3、shader非常複雜的模型,儘量後繪製。比如T4M的地表shader,取樣了七八張圖紋理,那麼它最後繪製,更加容易被Z-Culling剔除掉。

4、不透明物體(2000)——AlphaTest物體(2450)——半透明物體(3000),這個渲染順序有利於HSR或者Early-Z的最佳化。

Alpha-Test 在不透明物體繪製完畢之後再繪製,可以避免Alpha-Test導致EarlyZ失效,最後繪製,至少不會影響到之前不透明物體的EarlyZ。

5、RenderQueue2500,區分了不透明和半透明。半透明物體(2500以上)永遠在不透明物體(2500以下)後繪製。

如果物體的RenderQueue在2500的同一側,則sortingOrder優先順序更高:

Camera Depth > Sorting Layer > Order In Layer > RenderQueue > 距離相機的距離

(五)、TBDR的相關最佳化

1、不使用FrameBuffer的時候及時Clear。在RenderTexture上,當不使用RT之前,呼叫一次Discard,可以在某些移動裝置上提高效能。

2、每幀渲染之前儘量Clear。

3、對於大部分Android裝置,預先進行的Early-Z pass可能可以大大減少overdraw。Early-Z發生在整個光柵化之前,因為它處理的是FrameData。

對於iOS裝置(PowerVR),因為它內部有硬體支援去處理FrameData(HSR),所以不需要Early-Z。

4、得益於TBR架構,Blending和MSAA效率很高。

5、避免大量的Drawcall和頂點。在PC上Drawcall和頂點數量對GPU沒有太多嚴重影響。但是對於TBDR,DrawCall過多意味著FrameData資料過多,嚴重情況下可能會出現記憶體放不下的情況,這種情況下對FrameData的訪問速度奇慢。

所以對於移動裝置,Drawcall不只影響CPU,還會影響到GPU。

頂點數量在一定範圍內影響不大,但是如果達到1M,那麼可能就會觸發上面提到的極端情況,會大幅影響效能。

6、PowerVR 使用 HSR 進行隱面剔除。不需要對不透明物體進行排序。

其他Android裝置上使用 Early-Z,需要對不透明物體進行排序。從前往後繪製,會更好的利用Early-Z。

四、Drawcall的理解

(一)、Drawcall和渲染狀態(RenderState

1、Drawcall就是OpenGL或者DX中的渲染介面。提交頂點給GPU。

Drawcall過多,CPU傳遞給GPU的渲染指令就越多。同時一個Drawcall通常還會面臨資料複製、渲染狀態設定等等。如果GPU壓力越大,CPU就必須等待GPU執行完畢才能處理下一幀,所以CPU會空置。帶來的影響是Profiler中會看到 Gfx。WaitForPresent 或 Graphics。PresentAndSync。

2、SetPassCalls,要渲染一個模型只處理頂點是不夠的,還要有材質資訊、紋理資訊、材質中的開關狀態等等。這些就是渲染狀態。在渲染佇列中,是渲染狀態和渲染指令交替進行的。

如果一批模型材質等都相同,那麼就不需要設定渲染狀態,只處理渲染指令即可。相對效能會提升很多。在Unity中的表現就是Drawcall很高,但是SetPassCalls比較低。

(二)、StaticBatch和DynamicBatch

1、合批的目的是減少Drawcall。合批是有對應的CPU和記憶體開銷的。大多數時候減少Drawcall有利於提升整體效能。但是如果濫用合批,可能會導致CPU開銷更大,產生負最佳化。

2、動態合批為了平衡CPU消耗和GPU效能最佳化,將實時合批條件限制在比較狹窄的範圍內。靜態合批則犧牲了大量的記憶體和頻寬,以使得合批工作能夠快速有效的進行。

(三)、GPU Instancing

1、GPU Instancing 沒有動態合批那樣對網格數量的限制,也沒有靜態網格那樣需要這麼大的記憶體,它很好的彌補了這兩者的缺陷。

2、GPU Instancing 並不透過對網格的合併操作來減少Drawcall,GPU Instancing 的處理過程是隻提交一個模型網格讓GPU繪製很多個地方,這些不同地方繪製的網格可以對縮放大小,旋轉角度和座標有不一樣的操作,材質球雖然相同但材質球屬性可以不同。

3、GPU Instancing、動態合批、靜態合批三者所擅長的各不相同,有互相彌補的地方,各自本身也存在著不同程度的限制和優缺點。從整體上來看,GPU Instancing 更適合同一個模型渲染多次的情況,而動態合批(Dynamic batching)更適合同一個材質球並且模型面數較少的情況,靜態合批(Static batching)更適合當我們能容忍記憶體擴大的情況。

五、其他

(一)、PBR的金屬工作流和反射工作流的區別

1、金屬工作流和反射工作流的差異在於輸入的紋理是什麼。正常情況下都是用金屬工作流。

1。1、金屬工作流的紋理是金屬度、光滑度資訊。

Albedo Texture的rgb通道為albedo;a通道對應於Alpha;

其Diffuse Color需要透過以下方法來計算:

oneMinusReflectivity = unity_ColorSpaceDielectricSpec。a*(1-metallic);

diffColor = albedo * oneMinusReflectivity;

其Specular Color需要透過以下方法來計算:

specColor = lerp (unity_ColorSpaceDielectricSpec。rgb, albedo, metallic);

注意:unity_ColorSpaceDielectricSpec在unity內部的值為half4(0。04, 0。04, 0。04, 1。0 - 0。04) //linear space。

1。2、反射工作流的紋理是高光資訊。

Albedo Texture的rgb通道對應光照運算方程中的diffuse color;a通道對應於Alpha;

Speculer Texture的rgb通道對應光照運算方程的F0;a通道對應光照運算方程的Smoothness;

其oneMinusReflectivity = 1-SpecularStrength(specColor);//SpecularStrength函式是來獲取rgb通道最大值;

2、根據輸入的 albedoColor和其他引數,獲取實際的 diffuseColor、specColor和 oneMinusReflectivity。即diffuse顏色、高光顏色和反射率。用來輸入到光照函式中。

(二)、Mipmap的理解

1、Mipmap的優點:

1。1、避免遠處物體的鋸齒或者閃爍感,效果表現更好。

1。2、Texture Cache,紋理取樣的快取命中率上升,減少對視訊記憶體的直接訪問,減少頻寬io,進而提高渲染效率。

2、Mipmap的缺點:多消耗了1/3的記憶體,增大包體積。

3、渲染時會根據畫素點的uv座標計算,決定取哪個層級的mipmap。多層mipmap之間可以進行插值。所以同一個物體不同的畫素點可以是不同的mipmap。也就是說mipmap層級的選擇是畫素級別的。

個人理解,mipmap對頻寬的最佳化體現在快取命中率上,也就是因為不需要訪問視訊記憶體,從而減少了頻寬的消耗。而不是因為只傳遞小圖片導致頻寬消耗降低。

4、很多時候不開Mipmap效果無法接受,所以對於3D視角的遊戲而言,Mipmap是必開的。

5、2D的元素,比如UI圖片,是不需要開Mipmap的。

6、Trilinear - 三線性過濾。很多圖片尤其是法線,開了mipmap就要選擇三線性過濾。預設選擇線性過濾,紋理取樣是4個點,而三線性過濾會取樣8個點,在兩級mipmap之間進行混合。如果不使用三線性過濾,可能會導致在視野遠方,存在明顯的一條分界線,其產生的原因就是分界線前後取樣了不同層級的mipmap,導致顯示結果產生明顯差異。

沒有開啟mipmap的圖片,線性過濾和三線性過濾結果是一致的。三線性過濾是專門對mipmap進行最佳化的取樣方式。

(三)、視訊記憶體和視訊記憶體頻寬的理解

1、PC機,CPU和顯示卡是兩個獨立的硬體,記憶體和視訊記憶體是完全獨立的。而對於手機而言,CPU和GPU都在一個SOC上,共用一個物理記憶體。當然GPU會有邏輯上獨立的記憶體空間,作業系統核心的記憶體管理不會處理這塊兒記憶體區間。

2、視訊記憶體頻寬的主要消耗不是傳輸紋理上,只要視訊記憶體(記憶體)足夠,紋理是一直在視訊記憶體中的,不存在傳輸開銷。也就是說紋理填充率一般不會形成效能的瓶頸。

視訊記憶體頻寬的開銷主要在GPU對視訊記憶體資料的訪問上。開啟Mipmap,紋理取樣時Texture Cache(一個儲存圖片資料的只讀cache,在shader processor附近,有高吞吐率和低延遲)容易命中。進而避免GPU對視訊記憶體的訪問,也就可以降低頻寬開銷。

3、補充下GPU的記憶體型別,主要是對各級快取有一些概念。對快取有一定的 瞭解,也就可以理解提高快取命中為什麼很重要。比如,減少貼圖尺寸不僅僅可以最佳化記憶體佔用,還會因此提高快取命中率,進而提高渲染效能。Mipmap對效能的最佳化也體現在這裡。

PC機的GPU記憶體跟CPU很像,也是多級快取機制。包括,Register,Shared Memory,Texture L1 Cache,Instruction Cache,L2 Cache,DRAM。各類儲存器容量依次增大,相應的在晶片上的位置也離核心單元越來越遠,同時訪存延遲也越來越大。

移動裝置的GPU沒有專用的視訊記憶體,而是和CPU共享同一塊兒物理記憶體,快取機制也是一致的。不同之處在於,GPU上有一塊兒On Chip Memory的快取。這個硬體是TBDR的實現基礎。

(四)、Unity下幾種Lighting模式

1、Baked Indirect,僅預先計算間接光照,不執行陰影預計算。陰影完全實時生成。所以遠處沒有陰影,近處是ShadowMap的陰影。

2、Shadowmask,烘焙間接光和陰影。動態模型和場景可以受實時方向光影響。即實時方向光可以改變場景色調。

當選擇為 Distance Shandowmask 之後,陰影光照圖可以與實時陰影按照Shadow Distance設定的距離進行混合。近處顯示實時陰影,遠處顯示ShadowMask。實時陰影更加清晰,Shadowmask受精度影響,效果不如實時陰影好。

Shadowmask模式會將實時光和烘焙的光混合,同樣可以混合實時陰影和烘焙的陰影。那麼它就需要知道哪裡是陰影,這個就需要 ShadowMask 圖。

3、Subtractive,烘焙直接光照、間接光照和陰影。改變方向光不能影響場景。在此模式下,參與實時計算的只有動態物體的實時光照和動態物體對靜態物體的投影。陰影直接被烘焙在lightmap上,所以不需要ShadowMask圖。

(五)、LUT,用貼圖快取中間計算結果。

參考洛城寫的文章,因為很多人會對LUT存在誤解或誤用,所以copy了一段文字在這裡。

1、很多時候,我們會把一些數學上的中間計算結果快取到一張貼圖裡,這些貼圖的數值本身不代表視覺資訊,而是純粹的數字。比如Marschner Hair Mode用LUT去存BRDF;UE4用LUT去儲存PBR的環境光BRDF。

2、LUT帶來的效能損耗有兩點:

2。1、貼圖本身是數值,所以只能用無損格式,無法壓縮,所以bytes per pixel是比較大的,比一般貼圖佔用更多讀取頻寬。

2。2、對於貼圖的取樣是基於LUT的uv計算的,而相鄰畫素算出的uv通常都沒有空間連續性,這就表示每次LUT的取樣幾乎都會導致cache miss,所以這類LUT比一般貼圖的取樣更慢。

3、結論:儘量使用擬合函式去代替LUT取樣,對於Mobile GPU來說,永遠不要嘗試用LUT去最佳化一段shader;對於Desktop GPU來說,慎重考慮使用LUT。

標簽: 渲染  GPU  GAMMA  光照  視訊記憶體