Unity可編程渲染管線系列(十二)圖像質量(MSAA和HDR)

目錄微信

1 渲染比例函數

1.1 向下縮放性能

1.2 渲染到縮放後的紋理flex

1.3 向上縮放url

2 MSAAspa

2.1 配置.net

2.2 多采樣渲染紋理翻譯

2.3 解析紋理貼圖3d

2.4 無深度解析教程

2.5 Depth-Only 通道

3 HDR

3.1 配置

3.2 紋理格式

3.3 色調映射

3.4 萊因哈德(Reinhard)

3.5 修改Reinhard

本文重點:

一、調整渲染比例

二、支持MSAA

三、啓用HDR,帶有可選的色調映射

這是涵蓋Unity的可腳本化渲染管道的教程系列的第12部分。它涉及經過調整渲染比例,應用MSAA以及與色調映射結合使用HDR緩衝區進行渲染來提升圖像質量。

本教程是CatLikeCoding系列的一部分,原文地址見文章底部。「原創」標識意爲原創翻譯而非原創教程。

本教程使用Unity 2018.4.6f1製做。

(HDR,MSAA和渲染比例一塊兒使用)


1 渲染比例


要渲染的圖像的寬度和高度由相機肯定,這不受管道的控制。可是咱們能夠在渲染到攝像機目標以前作任何咱們想作的事情。若是渲染爲中間的紋理,能夠提供咱們想要的任何大小。例如,咱們能夠將全部內容渲染爲較小的紋理,而後對相機目標進行最後的blit處理以將其縮放到所需大小。這會下降圖像質量,但因爲要處理的片斷較少,所以加快了渲染速度。Lightweight/Universal管道具備「Render Scale」選項來支持此功能,所以咱們也將其添加到咱們本身的管道中。


1.1 向下縮放


將渲染比例的滑塊添加到MyPipelineAsset,初始範圍爲?~1。將分辨率下降到四分之一會使質量降低不少(像素數除以16),而且除非原始分辨率很高,不然極可能沒法接受。

(Render scale 滑塊設置爲最小值)

將渲染比例傳遞給管道實例。

並讓MyPipeline跟蹤它。

在「渲染」(Render)中渲染攝影機時,請肯定在建立渲染紋理以前是否使用縮放渲染,以防出現活動堆棧。縮小渲染比例後,咱們將使用縮放渲染,可是僅對遊戲窗口攝影機使用,所以場景,預覽和其餘攝影機不會受到影響。使用布爾變量跟蹤此決策,讓咱們能夠參照。

還要跟蹤變量中的渲染寬度和高度。它們默認狀況下由相機肯定,可是在使用縮放渲染時必須進行調整。


1.2 渲染到縮放後的紋理


如今,當使用縮放渲染或後處理時,咱們必須渲染爲中間紋理。還要使用布爾值對此進行跟蹤,並在獲取紋理時使用調整後的寬度和高度。

從如今開始,當調用RenderAfterOpaque時,必須將調整後的寬度和高度傳遞到活動堆棧。

RenderAfterTransparent也是如此。如今,咱們必須始終在渲染紋理時釋放紋理,而僅在使用堆棧時才調用RenderAfterTransparent。若是不是,咱們可使用常規blit將縮放後的紋理複製到相機的目標。

(渲染比例一、0.7五、0.5和0.25;放大且無後處理)


調整渲染比例會影響管道渲染的全部內容,但陰影除外,由於陰影具備本身的大小。有時候偶然地,稍微減少渲染比例彷佛會帶來一些抗鋸齒效果。可是進一步減小能夠清楚地看出,這只是細節損失致使的,當blit到最終渲染目標時,會因爲雙線性插值而模糊不清。


渲染比例如何與雙線性插值交互的?

0.5的渲染比例是最簡單的:最終,每塊2×2目標像素只有一個像素。每一個最終像素使用相同的四個權重進行插值,可是有四個可能的方向。


(Render scale 0.5 filtering)


其餘渲染比例尺會生成具備不一樣權重配置的像素,由於從源像素到目標像素的距離會根據比例尺以規則模式變化。

(Render scale 0.75 filtering)


1.3 向上縮放


咱們能夠按比例縮小圖像質量以提升性能。也能夠作相反的事情:以性能爲代價擴大規模以提升圖像質量。爲此,在MyPipelineAsset中將最大渲染比例增長到2。

而且還能夠在MyPipeline.Render中激活縮放渲染。

(渲染比例1.2五、1.五、1.75和2)


(Render scale 1.5 和2 filtering)


進一步增長渲染比例不會改善圖像質量。在3的時候,咱們獲得的結果與渲染比例1相同,而在4的時候,咱們以每一個像素2×2塊的塊返回,但距離更近。那是由於單個雙線性blit只能平均四個像素。利用更高的比例將須要一個通道,每一個片斷執行一次以上的紋理採樣。儘管可行,但這是不切實際的,由於所需的工做比例與渲染比例成平方關係。SSAA 4x將須要使用渲染16倍的像素。


2 MSAA


SSAA的替代方法是MSAA:多樣本抗鋸齒。想法是相同的,可是執行方式不一樣。MSAA跟蹤每一個像素的多個樣本,而沒必要將其放置在常規網格中。最大的區別是片斷程序每一個片斷的每一個圖元僅被調用一次,在原始分辨率下調用。而後將結果複製到柵格化三角形覆蓋的全部子樣本中。這顯着減小了必須完成的工做量,但這意味着MSAA僅影響三角形的邊緣,而沒有其餘影響。高頻表面(High-frequency surface)模式和alpha裁剪的邊緣仍然有鋸齒。


alpha-to-coverage是什麼?

這是在某種程度上平滑alpha裁剪邊緣的技巧,在某些狀況下能夠產生不錯的效果。本教程將不涉及它。


2.1 配置


爲MyPipelineAsset添加一個選項以選擇MSAA模式。默認狀況下,MSAA是關閉的,其餘選項是2×,4×和8×,能夠用枚舉表示。枚舉值表示每一個像素的樣本數量,所以默認值爲1。

(MSAA模式)


爲何不支持MSAA 16×?

能夠支持,可是與8倍相比,它幾乎沒有額外的質量增益,由於很是昂貴,而且沒有普遍的支持。


將每一個像素的樣本量傳遞到管道實例。

並在MyPipeline中對其進行跟蹤。

並不是全部平臺都支持MSAA,最大樣本數也有所不一樣。超過最大值可能會致使崩潰,所以咱們必須確保保持在限制以內。咱們能夠經過將樣本計數分配給QualitySettings.antiAliasing來實現。咱們的管道不使用此質量設置,但在分配給它時會注意執行限制。在分配給它以後,咱們將其複製回咱們本身的樣本計數。咱們惟一須要知道的是,當不支持MSAA時,它會產生零,咱們必須將其轉換爲樣本計數1。


2.2 多采樣渲染紋理


每一個相機都設置了MSAA支持,所以請在「Render」中跟蹤用於渲染的樣本,若是相機未啓用MSAA,則將其強制爲1。而後,若是最終每一個像素有多個樣本,則必須渲染爲中間的多采樣紋理,簡稱MS紋理。

爲了正確配置渲染紋理,咱們必須在GetTemporaryRT中再添加兩個參數。首先是讀寫模式,這是顏色緩衝區的默認模式,而對於深度緩衝區則是線性的。下一個參數是樣本計數。

在禁用全部後期處理的狀況下嘗試此操做。

(MSAA 2×,4×,8×,和沒有MSAA比較 render scale爲 2)


MSAA是否能夠與定向陰影一塊兒使用?

對於咱們的渲染管道,它工做正常。Unity的管道有麻煩,由於它們使用屏幕空間通道來級聯定向陰影。在本教程中,咱們會再遇到相似的問題。


與將渲染比例增長一倍相比,MSAA 4X的最終效果要好於渲染比例2,但須要注意的是,渲染比例不只影響幾何邊緣,還影響全部事物。你也能夠將兩種方法結合起來。例如,渲染比例爲2的MSAA 4x大體可與渲染比例爲1的MSAA 8x大體相比,儘管它使用16個樣本而不是每一個最終像素使用8個樣本。

(MSAA 4× and 8×,render scale 2)


2.3 解析紋理貼圖


雖然咱們能夠直接渲染爲MS紋理,可是不能以常規方式直接從它們讀取圖像。若是要對像素進行採樣,則必須首先對其進行解析,這意味着將全部採樣取平均值以得出最終值。整個紋理在特殊的「Resolve Color」通道中當即進行解析,該通道在採樣以前自動插入。

(在最終blit以前解決顏色)


解析MS紋理會建立一個臨時的常規紋理,該紋理在全部新紋理渲染到MS紋理以前一直有效。所以,若是咱們屢次採樣而後渲染到MS紋理,則最終將得到相同紋理的額外解析通道。激活啓用了模糊的後效果堆棧時,你會看到此信息。在強度爲5的時候,咱們得到了3個解析通道。

(解析三遍,模糊強度5。)


附加的解析通道沒有用,由於咱們的全屏效果沒法從MSAA中受益。爲了不沒必要要地渲染到MS紋理,咱們能夠一次渲染到中間紋理,而後使用它代替相機目標。爲此,能夠在MyPostProcessingStack中的RenderAfterOpaque和RenderAfterTransparent方法中添加示例參數。若是啓用了模糊而且使用了MSAA,則將其複製到已解析的紋理並將其傳遞給Blur。

將渲染樣本添加爲MyPipeline.Render中的參數。

如今將三個解析通道減小爲一個,再加上一個簡單的blit。

(只用了一次 模糊強度爲5)


2.4 無深度解析


顏色樣本經過對它們進行平均來解決,但這不適用於深度緩衝區。平均相鄰深度值沒有任何意義,也沒有可使用的通用方法,所以多采樣深度根本沒法解析。因此,啓用MSAA時,深度條紋效果不起做用。


使效果再次起做用的幼稚方法是在啓用深度條紋時不將MSAA應用於深度紋理。首先,向MyPostProcessingStack添加一個getter屬性,該屬性指示是否須要從深度紋理讀取。僅在使用深度條紋效果時才須要。

如今,咱們能夠跟蹤MyPipeline.Render中是否須要可訪問的深度紋理。僅當須要深度時,才須要得到單獨的深度紋理,不然咱們能夠經過設置顏色紋理的深度位來解決。並且,若是確實須要深度紋理,那麼讓咱們明確地始終將其樣本設置爲1,以禁用它的MSAA。

這也會影響繪製不透明效果後設置渲染目標。

最後須要釋放哪些紋理。

(MSAA 8×的深度條紋)


如今,啓用MSAA時會顯示深度條紋,可是抗鋸齒功能彷佛已損壞。發生這種狀況是由於深度信息再也不受MSAA的影響。咱們須要另尋解決方案。


2.5 Depth-Only 通道


咱們須要一個MS深度紋理來進行常規渲染,並須要一個非MS深度紋理來進行深度條紋效果。能夠經過爲深度紋理建立自定義解析過程來解決此問題,但不幸的是,對此的支持很是有限。另外一種方法是經過添加Depth-Only的通道將深度渲染兩次,以將其渲染到常規深度紋理。這是昂貴的但可行。當深度緩衝區與MSAA結合使用時,例如當級聯方向陰影須要屏幕空間陰影通道時,這就是Unity的實現方式。


這是否意味着Unity的Depth-Only 通道不影響常規渲染?

確實。它不用於填充深度緩衝區,咱們也不會使用它。


首先要區分是能夠直接使用深度紋理仍是由於MSAA處於活動狀態而須要一個Depth-Only通道。咱們如今擁有的獲取紋理和設置渲染目標的邏輯適用於不使用MSAA的狀況。

若是須要,在調用RenderAfterOpaque以前添加Depth-Only通道。就像不透明的通道同樣,除了咱們使用DepthOnly做爲通道名稱,不須要渲染器配置,而且必須設置和清除深度紋理做爲渲染目標。

將所需的過程添加到Lit着色器。它是默認通道的拷貝,其中除去了實例化,剪切和LOD淡入淡出的全部功能。它不會寫入顏色信息,所以請將其顏色掩碼設置爲零。它始終寫入深度,並依賴於單獨的DepthOnly HLSL文件中的專用頂點和片斷函數。

DepthOnly.hlsl是Lit.hlsl的副本,其中刪除了全部不影響深度的數據。

咱們只關心位置和UV座標。片斷功能僅適用LOD並執行裁剪。它的最終結果就是零。

如今,在深度條紋和MSAA再次起做用以前,咱們得到了Depth-Only通道。不幸的是,深度條紋效果自己沒法從MSAA中受益,所以仍然會在嚴重影響圖像的地方引入鋸齒。Unity的級聯方向陰影以相同的方式干擾MSAA。

(深度條紋具備功能性MSAA 8倍)


可是後來得到渲染的透明幾何體仍然能夠從MSAA中受益。

(透明,帶有MSAA和深度條紋)


3 HDR


咱們將討論的最後一個主題是高動態範圍渲染。到目前爲止,紋理的每一個顏色通道的範圍爲0-1,所以它能夠表示強度爲1的光照級別。可是入射光的強度沒有固有的上限。太陽是很是明亮的光源的一個例子,這就是爲何你不該該直接看它的緣由。它的強度遠大於咱們在眼睛受損以前所能感知的強度。可是許多常規光源也會產生強度超過觀察者極限的光,尤爲是近距離觀察時。例如,我將場景中的點光源的強度增長到100,並將白色球體的發射強度提升了一步。

(高強度光和自發光)


結果是過亮的像素被吹散爲均勻的白色,而且在邊緣附近有一些顏色偏移。HDR渲染的目的是防止圖像的很是亮的部分退化爲均勻的白色。這將須要存儲明亮的數據並將其轉換爲可見的顏色。


3.1 配置


經過向MyPipelineAsset添加「Allow HDR」切換,將其傳遞給管道實例,使咱們的管道是否支持高動態範圍渲染成爲可選。

MyPipeline只須要跟蹤它。

(HDR 開啓)


3.2 紋理格式


要存儲超過1的顏色值,咱們須要更改用於渲染紋理的紋理格式。若是咱們的管道和攝像機都啓用了HDR,則咱們須要默認的HDR格式,不然咱們可使用常規默認值。區別在於HDR紋理的顏色通道包含浮點值而不是8位值。所以它們須要更多的內存,這意味着你僅應在須要時使用HDR。


咱們沒必要根據是否啓用HDR來決定renderToTexture,由於在不使用後期處理的狀況下也沒有理由使用HDR,由於最終的攝影機目標是每通道LDR 8位。

HDR顯示器呢?

Unity當前不支持HDR顯示器,所以咱們也不能支持。除此以外,HDR顯示的問題是使用顏色分級的遊戲必須在色調映射以後(或同時)進行此操做,從而生成常規的LDR圖像,而後在發送以前將其轉換回HDR 到顯示器上,而後它會作本身的事情。


不使用渲染紋理時,請不要使用HDR。所以,讓咱們也用MSAA,並不進行其餘後處理。最初的結果看起來沒有什麼不一樣,只是抗鋸齒質量變差了。之因此發生這種狀況,是由於只有在全部值均爲LDR時,平均顏色才能很好地起做用,不然很是明亮的樣本將主導結果。所以,當涉及HDR顏色時,MSAA會下降。

(MSAA×4都可打開和關閉HDR)


在MyPostProcessingStack中添加所需的參數。咱們只須要將其用於DepthStripes中的臨時紋理,由於不管如何須須在LDR中執行模糊處理才能得到最佳效果。


3.3 色調映射


從HDR到LDR的轉換稱爲色調映射,它來自攝影和膠片開發。傳統的照片和膠片範圍也頗有限,所以已經開發了許多技術來執行轉換。沒有惟1、絕對正確的方法來處理此問題。可使用不一樣的方法來設置最終結果的氣氛,例如經典的電影外觀。可是,調整顏色屬於色調分級以後的顏色等級。咱們只關心下降圖像的亮度,以使其最終落在LDR範圍內。


色調映射是一種後期處理效果,能夠是可選的,所以請將其切換添加到MyPostProcessingStack中。

(開啓色調映射)


它是經過本身的過程完成的,所以爲其添加一個枚舉值和方法,最初只是使用其本身的探查器樣本進行塗抹。設置源ID和目標ID參數RenderTargetIdentifier,以便咱們能夠靈活地傳遞給它。

若是禁用了模糊,則在RenderAfterTransparent中,將色調映射到攝像機目標而不是常規blit。不然,當使用色調映射或MSAA時,經過適當的遍歷建立解析的紋理。所以,在這種狀況下解決可能意味着MSAA解決,色調映射解決或二者兼而有之。

將新的通道添加到PostEffectStack着色器。

並將所需的功能添加到HLSL文件。最初返回的顏色爲負1,飽和度。這能夠指示咱們哪些像素包含過亮的顏色。

(只有過亮的顏色)


3.4 萊因哈德(Reinhard)


色調映射的目的是下降圖像的亮度,以使均勻的白色區域顯示各類顏色,從而揭示丟失的細節。就像你的眼睛不適應忽然明亮的環境,直到再次看的清楚。可是咱們不想均勻地縮小整個圖像,由於那樣會使深色變得難以區分,將高亮度換成曝光不足。所以,咱們須要一個非線性轉換,該轉換不會減小不少暗值,但會減小不少高值。在極端狀況下,零保持爲零,而且接近無窮大的值減少爲1。完成的函數爲 c/(1 + c),其中c是顏色通道。該功能被稱爲Reinhard色調映射操做,最初由Mark Reinhard提出,只是他將其應用於亮度,而咱們將其應用於各個顏色通道。使咱們的色調映射通道使用它。

(沒有VS有 Reinhard RGB 色調映射)


結果是保證沒有任何過亮像素的圖像,可是整個圖像已經去飽和並有些暗了。徹底處於滿強度狀態的像素減半,你能夠在禁用HDR的狀況下應用色調映射來清楚地看到。

(色調映射在LDR圖像上的應用)


咱們不能在解決MS紋理以前執行色調映射嗎?

能夠,經過自定義解析通道,在對每一個樣本進行平均以前對每一個樣本執行色調映射,這比每一個像素執行一次代價更高。除此以外,像bloom這樣的後處理效果還須要HDR數據。爲了使這些工做有效,解析通道必須在平均後轉換回HDR,以近似原始強度。

3.5 修改Reinhard


色調映射有多種方法-可使用顏色分級對其進行進一步調整-但每通道RGB Reinhard最簡單,所以咱們先將其保留下來。可是咱們能夠進行的簡單調整是經過調整壓縮爲LDR的值範圍來限制效果的強度。超出此範圍的任何東西都保持明亮。這樣一來,咱們就能夠減小對亮度較弱的場景的調整,或者接受一些亮度太高的效果,以保持較暗的顏色不變。

Reinhard也描述了此調整,並將函數轉換爲,其中w 是白點,或本例中的最大色調映射範圍。若是 w是無限的,那麼咱們將再次擁有原始函數,當w 爲1時,色調映射將不執行任何操做。

w從1到5)

爲該範圍添加一個配置選項,最小值爲1,由於較低的值會過分曝光整個圖像。最大值能夠爲100,足以近似原始功能。而後計算,並將其做爲Reinhard函數的修改器發送到GPU。

而後,着色器只需計算

(色調映射範圍減小到2)


如今咱們結束了原始的SRP教程系列,該系列從尚處於實驗階段開始。Unity 2019發生了不少變化。爲此,有一個新的自定義SRP系列,它以更現代的方式涵蓋了新舊主題。


歡迎掃描二維碼,查看更多精彩內容。點擊 閱讀原文 能夠跳轉原教程。










本文翻譯自 Jasper Flick的系列教程

原文地址:

https://catlikecoding.com/unity/tutorials








本文分享自微信公衆號 - 壹種念頭(OneDay1Idea)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索