天天看點

unity urp内置lit材質源碼解析(上)

之前我釋出過一篇對urp的内置shader lit的結構解析,發現自己說的也不完善,這次直接對源碼進行一個解析,并提升一下自己的記憶。

如果你找不到這個shader,那麼就有可能你不是urp渲染管線。自己搜尋。

在前向渲染pass裡面,我們可以看到,urp裡面已經不再使用cg語言,而是改用了HLSL渲染語言,其實沒大差别,隻是裡面的一些函數,和一些實作方法出現了變動。

#pragma exclude_renderers gles gles3 glcore 上來你會看到這麼一句話,就是後面那幾個渲染器不會生成對應渲染器的shader。這裡再補一句,我們寫的shader不是最終在程式上運作的,因為為了相容多平台,我們隻需要寫一套shader,然後unity會根據我們寫的shader生成對應平台的運作的shader。

接下來,就是一大堆的宏:

unity urp内置lit材質源碼解析(上)
unity urp内置lit材質源碼解析(上)

unity會根據你設定的宏,生成相應的shader變體,就相當于一個開關,是以,如果宏過多的話,shader變體會幾何倍增,那麼占用的記憶體也會集合倍增。shader的變體其實就是實際運作時的shader,你開關一個宏,它會生成相應的兩個shader。如果宏過多,它會生成兩套,和其它宏疊加的,你會發現你的shader變體巨多,在哪裡看你的變體數量:

unity urp内置lit材質源碼解析(上)

你點選後面的show,會打開有宏關鍵字的變體清單。

unity urp内置lit材質源碼解析(上)

這裡定義了你的頂點着色器和片元着色器。渲染的時候,渲染引擎會找到相應的shader去運作。

unity urp内置lit材質源碼解析(上)

最後,引入了相應的代碼,#include就是引入相應的檔案代碼。

litInput.hlsl 裡面主要聲明了變量,還有就是初始化pbr使用的表面資料。

LitForwardPass.hlsl 裡面就是定義頂點着色器和片元着色器函數和其它運算函數,以及一些擷取資料的函數。接下來,我們一個一個的解析。

LitInput.hlsl

unity urp内置lit材質源碼解析(上)

開頭的這個是為了防止多次引入,是以,設定了一個宏,這個宏隻是為了防止多次引用,占用多餘記憶體,不會生成額外變體。

unity urp内置lit材質源碼解析(上)

再下面就是引入了多個檔案,都是一些内置的。

Core.hlsl 就是unity官方内置的一些函數和宏,友善我們使用。

CommonMaterial.hlsl 定義了一些pbr材質使用的函數

SurfaceInput.hlsl 定義了表面材質通用的屬性和函數,比如基礎貼圖什麼的,都在這裡面定義的,裡面的函數也都是通用的,比如

unity urp内置lit材質源碼解析(上)

這個函數,可以讓我們求出目前的透明度,以及是否需要裁切。

ParallaxMapping.hlsl 這個是時差偏移的相應函數

DBuffer.hlsl 這個是使用延遲渲染管線用到的函數,我們前向渲染不需要。

unity urp内置lit材質源碼解析(上)

這裡是如果你使用了細節貼圖,将根據宏定義一個新的宏,防止後面判斷宏的時候麻煩。

unity urp内置lit材質源碼解析(上)

這些就是内置pbr材質所需要的一些屬性,為什麼要用CBUFFER括起來,是因為為了使用urp的新功能srp合批,srp合批優勢在于,我們不再需要保持相同的材質球也能合批,隻要使用了相同的shader,就可以實作srp合批。

ps:這裡需要提醒一句,如果你要實作srp合批,那麼,你的shader裡面的pass裡面使用的CBUFFER必須保持一緻,要不然你shader上面就會提醒你這個:

unity urp内置lit材質源碼解析(上)

再往下面看:

unity urp内置lit材質源碼解析(上)

這裡聲明的是對正交相機使用的一些常量,我一般修改的時候,會把這一段删除掉。

unity urp内置lit材質源碼解析(上)

這裡聲明了pbr的一些貼圖,urp裡面每個貼圖需要攜帶其貼圖的采樣器,這個采樣器就是你在貼圖上面設定的貼圖拼接模式,

unity urp内置lit材質源碼解析(上)

如果你不想使用貼圖的,而是想固定住它的采樣模式,不管它貼圖怎麼設定的,我們可以直接寫内置的這些采樣器的命名:

unity urp内置lit材質源碼解析(上)

此截圖至:https://blog.csdn.net/lsccsl/article/details/118086659

接下來

unity urp内置lit材質源碼解析(上)

這段就是,根據你使用的工作流,來實作不同的SAMPLE_METALLICSPECULAR函數定義,供後面使用,如果你是高光工作流,那麼我引擎将去擷取高光貼圖,如果不是,那麼引擎将使用金屬度貼圖。我們一般都是使用自己定義的工作流,一般還是金屬工作流,比如将 ao roughness metallic 設定道一張一張貼圖裡面。(一般都把粗糙度的使用G通道,意思是G通道的更準确一些,畢竟粗糙度的漸變比較多,ao隻是烘焙的環境遮蔽,金屬度一般不是0就是1,要求最低)

unity urp内置lit材質源碼解析(上)

這個函數,就和上面定義的函數呼應上了,這個函數,主要是通過你設定的資料來求出目前材質的高光光滑度的。你可以打開一個lit材質看一下

unity urp内置lit材質源碼解析(上)

我們可以在這裡選擇相應的工作流,然後選擇unity也非常善解人意的讓你可以選擇你的光滑度是在基礎貼圖裡面,還是在定義的高光顔色貼圖a通道裡面(高光工作流)或者金屬度貼圖a通道裡面(金屬工作流)。然後,我們再看這個函數,就明了了很多,如果你設定了金屬高光光滑度貼圖,我們将擷取金屬貼圖,然後根據你設定從哪個a通道去擷取高光光滑度進行設定。如果沒有設定,我們将判斷你是哪個工作流,擷取高光顔色,然後再根據你的選擇生成高光光滑度。

unity urp内置lit材質源碼解析(上)

這個就簡單了,擷取烘焙的AO貼圖,用了g通道的值,并且根據你設定的AO強度,和白色進行了插值。

unity urp内置lit材質源碼解析(上)

這個是生成塗層的遮罩和塗層光滑度,傳回二維向量。如果你沒設定貼圖,或者沒開啟塗層,那麼将傳回預設值,也就意味着沒有開啟。

unity urp内置lit材質源碼解析(上)

這個是擷取視差偏移的值,轉換到uv偏移上面,時差偏移這裡就不講解實作原理了。

unity urp内置lit材質源碼解析(上)

這裡是進行縮放細節貼圖的基本色。

unity urp内置lit材質源碼解析(上)

這個是混合細節貼圖基本色和預設的基本色。

unity urp内置lit材質源碼解析(上)

這裡是細節法向和預設法向的混合。

這裡多提一嘴,細節貼圖的作用,細節貼圖主要是為了展現物體的細節,如果将細節直接烘焙到基本顔色貼圖和基本法向貼圖上,那麼要求基本貼圖的精度以及分辨率要高,降低渲染性能,增加記憶體占用。是以,我們通常會使用額外的細節貼圖,來進行重複使用,來實作細節表現,比如放大以後,皮膚的細節。

unity urp内置lit材質源碼解析(上)

這個是初始化pbr表面材質所需資料的函數,每個pass渲染中都需要使用。如果你需要Lit的shader自定義,那麼需要保留這個函數,就是這個LitInput函數實作是shader裡面的多個pass都可以引入的那種。是以,我們需要保證SurfaceData資料的統一

unity urp内置lit材質源碼解析(上)

看一下函數内部的運算。

unity urp内置lit材質源碼解析(上)

首先實作了基本色和透明度。

unity urp内置lit材質源碼解析(上)

然後調用上面的SampleMetallicSpecGloss函數,擷取到高光顔色和光滑度。

随後計算出來了最終基本色,就是貼圖顔色*基本色顔色。

後面就是根據工作流,設定金屬度和高光顔色。高光工作流沒有金屬度一說,是以設定了1,顔色是從函數裡面算出來的顔色。金屬工作流,r通道就是金屬度,高光顔色直接設定0.

然後下面就是直接從specGloss的a通道擷取到光滑度(和粗糙度相反)

unity urp内置lit材質源碼解析(上)

然後從貼圖上擷取到切線空間的法向。

unity urp内置lit材質源碼解析(上)

擷取烘焙的AO。

如果你設定了自發光,将擷取到自發光的顔色。

unity urp内置lit材質源碼解析(上)

如果你有塗層,那麼我們将計算塗層的遮罩和塗層的光滑度。

unity urp内置lit材質源碼解析(上)

如果你設定的細節貼圖,那麼我們将計算細節相關,并和基本的貼圖進行融合。

由于篇幅比較長,這一篇就先解析到這吧。具體實作留到下一篇。

繼續閱讀