Unity Shader 基礎入門

閱前提示

記錄Unity Shader 學習筆記魂贬,拿起這塊磚甫窟,砸開Shader的門跟继。
適合人群:Shader 初學者
閱讀方式:目錄順序閱讀
知道的越多种冬,不知道的越多。希望我的文章對你有所幫助
獲取更多:我的博客


Shader

渲染管線:

? 渲染流程主要分為三個階段舔糖,由CPU與GPU完成

1.應用階段(cpu部分)

此階段主要是處理數(shù)據(jù)(硬盤——>內存)娱两,設置渲染狀態(tài),DrawCall

加載數(shù)據(jù)到顯存
設置渲染狀態(tài)
DrawCall

? 將準備的數(shù)據(jù)(點金吗,線十兢,面,材質摇庙,等信息打包傳遞給GPU【圖元數(shù)據(jù)】旱物,通知GPU開始渲染)

2.幾何階段(gpu)
在這里插入圖片描述

該階段主要做的事情是坐標轉換,將空間坐標轉換為屏幕坐標卫袒。

細分下來有如下幾個過程:

頂點著色器(Vertex)

? 實現(xiàn)頂點的空間變化宵呛,頂點著色。

曲面著色器(Tessellation)

? 細分圖元

幾何著色器(Geometry)

? 執(zhí)行逐圖元著色操作夕凝,或用于產(chǎn)生更多圖元

剪裁(Clipping)

? 剪裁不在攝像機內的頂點宝穗,剔除某些三角圖元的面片。

屏幕映射(ScreenMapping)

? 將圖元坐標轉到屏幕坐標新中

3.光柵化階段(gpu)

設置三角面码秉,計算每個像素的顏色逮矛,最終呈現(xiàn)。

三角形設置

? 上階段輸出的三角網(wǎng)格頂點數(shù)據(jù)转砖,計算三角網(wǎng)格须鼎。

三角形遍歷

? 找尋被三角網(wǎng)格覆蓋的像素(片元)

片元著色器

? 可編程,完成重要的渲染技術府蔗。

逐片元操作

? 稱為輸出合并階段晋控,此階段片元將進行很多測試工作。

? 模板測試:用于限制渲染區(qū)域礁竞,或一些高級用法 渲染陰影糖荒,輪廓渲染

? 深度測試:用于判斷遮擋

? 混合:用于處理透明,半透明

數(shù)學

向量/矢量v(x,y,z)

|\vec v| = \sqrt{x^2 + y^2 + z^2}

點積

\vec {v}_1\cdot \vec {v}_2 = {x}_1\times {x}_2 + {y}_1\times {y}_2 + {z}_1\times {z}_2 \vec {v}_1\cdot \vec {v}_2 = |\vec {v}_1||\vec {v}_2|\cosθ

? v1 在v2上的投影長度 (>0 方向相同 反之)
θ = \arccos(\frac{\vec {v}_1}{|\vec {v}_1|}\cdot\frac{\vec {v}_2}{|\vec {v}_2|})

叉積

\vec {v}_1 \times \vec {v}_2 = ({y}_1{z}_2 - {z}_1{y}_2,{z}_1{x}_2 - {x}_1{z}_2,{y}_1{x}_2 - {x}_2{y}_1)

向量叉積來計算垂直于該平面的向量
|\vec {v}_1 \times \vec {v}_2| = |\vec {v}_1||\vec {v}_2|\sinθ

矩陣
單位矩陣

{I}_n = \begin{matrix} 1 & 0 & 0 &. \\ 0 & 1 & 0 &. \\ 0 & 0 & 1 &.\\ .&.&.&.n \end{matrix}\\ I = I^{-1}

置換矩陣

{M^T}_{ij} = {M}_{ji}\\ {AB}^T = B^TA^T

逆矩陣

{M}{M^{-1}} = {I}\\ (AB)^{-1} = B^{-1}A^{-1}

高斯-若爾當消元法

? 逆矩陣的求法
[A\space I] = [I\space A^{-1}]\\ \begin{matrix} ...&1 & 0 & 0 \\ ...&0 & 1 & 0 \\ ...&0 & 0 & 1 \\ \end{matrix} => \begin{matrix} 1 & 0 & 0 &... \\ 0 & 1 & 0 &... \\ 0 & 0 & 1 &...\\ \end{matrix}

正交矩陣

MM^T = I\\ M^T = M^{-1}

正交矩陣 M = \begin{matrix} & \vec a &\\ & \vec b &\\ & \vec c &\\ \end{matrix} \vec a模捂、 \vec b捶朵、 \vec c 單位矢量蜘矢,互相垂直

矩陣變換
基礎變化矩陣

\begin{matrix} {M}_{3*3} & {t}_{3*1} &\\ {0}_{1*3} & {1} &\\ \end{matrix}

法線變換

若一個點T 的變換矩陣為M,則法線N的變換矩陣為M逆轉置矩陣
{T}_B{N}_B =(M{T}_A)(G{N}_A) = 0 \\ G = (M^{-1})^T = (M^{T})^{-1}\\ {T}_B = M{T}_A\\ {N}_B = (M^{-1})^T{N}_A

Unity Shader

四種Shader
  1. Standard Surface Shader 表面著色器模板(Unity后臺轉換為頂點/片元著色器)

    Shader "Custom/NewSurfaceShader" {
        Properties {}
        SubShader {
            Tags { "RenderType"="Opaque" }
            //[RenderSetup]
            CGPROGRAM
            ENDCG
        }
        FallBack "Diffuse"
    }
    
  1. Unlit Shader 頂點/片元著色器

    Shader "Unlit/NewUnlitShader"
    {
        Properties{}
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
            Pass
            {
                CGPROGRAM
                ENDCG
            }
        }
    }
    
    1. Image Effect Shader 屏幕后處理效果模板

    2. Compute Shader 常規(guī)渲染流水線無關的計算

第一個Shader
Shader "Unlit/SimpleShader"
{
    SubShader
    {
        Pass
        {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                float4 vert(float4 v:POSITION):SV_POSITION
                {
                    return UnityObjectToClipPos(v);//對頂點坐標進行了裁剪空間轉換
                }

                fixed4 frag():SV_TARGET
                {
                    return fixed4(1,1,0,1);
                }
                ENDCG   
        }
    }
}
vertex

? 聲明了哪個函數(shù)包含頂點著色器代碼

? 頂點著色器:逐頂點執(zhí)行

fragment

? 聲明了哪個函數(shù)包含了片元著色器代碼

? 片元著色器:逐片元執(zhí)行

頂點與片元的關系

? 在渲染管線中,GPU執(zhí)行的開始便是頂點作色器综看,它的輸入來自CPU,主要工作是 坐標轉換逐頂點光照品腹,且可以為后續(xù)階段輸出數(shù)據(jù)

? 片元著色器作用于光柵化階段,三角形遍歷階段會檢查每個像素是否被三角網(wǎng)絡覆蓋红碑,如果被覆蓋的話就會生成一個片元舞吭。

光照
漫反射

{C}_{diffuse} = ({C}_{light}*{M}_{diffuse})\max(0,\vec N\cdot\vec L)

_LightColor0.rgb * _Color.rgb * saturate(dot(worldNormal,worldLight))
半蘭伯特模型(Half Lambert)

{C}_{diffuse} = ({C}_{light}*{M}_{diffuse})\max(0,\alpha(\vec N\cdot\vec L) + \beta)\\ \alpha,\beta \space 一般取0.5

_LightColor0.rgb * _Color.rgb * (dot(worldNormal,worldLight)*0.5 + 0.5)

目的在于把[-1,1]映射到[0,1],模型的背光面也會有明暗變化析珊。因為普通漫反射會與0做比較羡鸥。

高光反射光照模型(Phong)

{C}_{specular} = ({C}_{light}*{M}_{specular})\max(0,\vec v\cdot\vec r)^{{m}_{gloss}} \\ \vec r = \vec l-2(\vec n\cdot \vec l)\vec n

Clight是入射光的顏色和強度,材質的高光反射系數(shù)Mspecular忠寻,視角方向V和反射方向R點乘的結果的光系數(shù)Mgloss次方

fixed3 reflectDir = normalize(reflect(worldLight,worldNormal));
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex));
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(viewDir,reflectDir)),_Gloss);
Blinn

{C}_{specular} = ({C}_{light}*{M}_{specular})\max(0,\vec n\cdot\vec h)^{{m}_{gloss}} \\ \vec h = \frac{\vec v + \vec l}{|\vec v + \vec l |}

紋理
屬性:_MainTex ("Texture", 2D) = "white" {}
聲明:
sampler2D _MainTex;
float4 _MainTex_ST;
// float2 uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
float2 uv = TRANSFORM_TEX(v.texcoord,_MainTex);//縮放與平移確定最終紋理坐標
float3 TexelsValue = tex2D(_MainTex,uv);//通過紋理坐標采樣紋素值

紋理名_ST 代表紋理屬性 ST(scale,translation)

X_ST.xy 代表縮放惧浴,X_ST.zw 代表平移

法線紋理

凹凸映射有兩種方式:

? 高度紋理:顏色深淺表示凹凸

? 法線紋理:通過法線擾動方向確定凹凸

因為法線分量范圍[-1,1] 像素的分量范圍[0,1]
normal = pixel*2-1

模型空間的法線紋理

? 實現(xiàn)簡單,直白奕剃,計算少衷旅。但得到的是絕對法線信息,僅可用于創(chuàng)建時的模型纵朋。

切線空間的法線紋理

? 自由度高柿顶,記錄的是相對法線信息,適用于不同的網(wǎng)格操软。

? 可進行UV動畫

? 可壓縮嘁锯。切線空間下法線紋理的Z方向總是正方向,因此可靠XY方向推導Z方向寺鸥。

切線空間下的代碼:

//把模型空間下切線方向桩盲,副切線方向秘血,法線方向 排列得到模型空間到切線空間的旋轉矩陣
//副切線由其他兩個做叉乘得到友酱,乘w 是為了區(qū)分方向(因為有兩個)
// float3 binormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w;
// float3x3 rotation = float3x3(v.tangent.xyz,binormal,v.normal);
// TANGENT_SPACE_ROTATION;//內置宏,效果同上
TANGENT_SPACE_ROTATION;
//計算切線空間下的光線與視角
o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)); //模型——>切線
o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));

//計算切線空間下的法線坐標
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentViewDir = normalize(i.viewDir);

fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
fixed3 tangentNromalDir;
tangentNromalDir = UnpackNormal(packedNormal);//法線紋理設置成 normal map 后使用此方法
// tangentNromalDir.xy = (packedNormal*2 - 1)*_BumpScale;
tangentNromalDir.xy *= _BumpScale;
tangentNromalDir.z = 
sqrt(1-saturate(dot(tangentNromalDir.xy,tangentNromalDir.xy)));//根據(jù)xy推導z
漸變紋理

通過漸變紋理使漫反射輪廓鮮明兼丰。

原理是由半蘭伯特而來,利用HalfLambert 使法線和光線的點積的范圍變?yōu)榱薣0,1]笆载,從而在UV上以halfLambert為坐標采樣扑馁。

fixed halfLambert = 0.5*(dot(worldNormalDir,worldLightDir)) + 0.5;
fixed3 diffuseColor = tex2D(_RampTex,float2(halfLambert,halfLambert)).rgb * _Color.rgb;
fixed3 diffuse = _LightColor0.rgb * diffuseColor;
遮罩紋理

遮罩紋理為我們提供了更為精確(像素級)地控制模型表面的各種性質。

例如:可以通過一張遮罩紋理的R通道的值來控制高光反射的強弱凉驻。

fixed specularMask = tex2D(_SpecularMark,uv).r * _SpecularScale;
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(i.worldNormal,blinnDir)),_Gloss) * specularMask;

所以腻要,通過增加遮罩紋理,我們可以控制更多的表面屬性涝登。

透明
透明度測試

判斷一個片元透明度滿不滿足條件從而進行舍去雄家,保留的片元將于普通的不透明物體一起處理。無其他特殊開關胀滚,即物體要不就是純透明趟济,要不就是不透明乱投。

clip(texColor.a - _Cutoff);
//當 a - 定義的系數(shù) < 0 是將執(zhí)行 discard 指令剔除該片元
透明度混合

真正意義上的半透明。它會將當前片元顏色于存儲在顏色緩沖中點顏色進行混合顷编。但此混合會關閉深度寫入戚炫,所以必須要注意渲染順序。

相關鏈接

CG標準函數(shù)庫

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末媳纬,一起剝皮案震驚了整個濱河市双肤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钮惠,老刑警劉巖茅糜,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異萌腿,居然都是意外死亡限匣,警方通過查閱死者的電腦和手機抖苦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門毁菱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锌历,你說我怎么就攤上這事贮庞。” “怎么了究西?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵窗慎,是天一觀的道長。 經(jīng)常有香客問我卤材,道長遮斥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任扇丛,我火速辦了婚禮术吗,結果婚禮上,老公的妹妹穿的比我還像新娘帆精。我一直安慰自己较屿,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布卓练。 她就那樣靜靜地躺著隘蝎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪襟企。 梳的紋絲不亂的頭發(fā)上嘱么,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音顽悼,去河邊找鬼曼振。 笑死辉川,一個胖子當著我的面吹牛,可吹牛的內容都是我干的拴测。 我是一名探鬼主播乓旗,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼集索!你這毒婦竟也來了屿愚?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤务荆,失蹤者是張志新(化名)和其女友劉穎妆距,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體函匕,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡娱据,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盅惜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片中剩。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抒寂,靈堂內的尸體忽然破棺而出结啼,到底是詐尸還是另有隱情,我是刑警寧澤屈芜,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布郊愧,位于F島的核電站,受9級特大地震影響井佑,放射性物質發(fā)生泄漏属铁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一躬翁、第九天 我趴在偏房一處隱蔽的房頂上張望焦蘑。 院中可真熱鬧,春花似錦姆另、人聲如沸喇肋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝶防。三九已至,卻和暖如春明吩,著一層夾襖步出監(jiān)牢的瞬間间学,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留低葫,地道東北人详羡。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像嘿悬,于是被迫代替她去往敵國和親实柠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354