unity Shader Lab(cg hlsl glsl)着色器入門教程 以及 vs2019 支持unity shader語法(更新中2019.9.5)

前言:如果你對cg glsl hlsl 頂點着色器 片段着色器 表面着色器 固定渲染管線 等等有所疑惑,或是想學會unity的渲染,看這一篇就足夠了。我會不斷更新知識點與案例。

讓vs支持shader

點擊vs的工具>擴展和更新>聯機>visual studio marketplace
搜素shader
點擊下載
重啓vs
彈出installer,點擊修改 即可。

一,基礎知識

關於着色器語言與Shader Lab

着色器語言有三種:
hlsl(DirectX)
glsl(OpenGL)
cg(支持以上兩種)
Shader Lab 是unity封裝了cg、hlsl、glsl的unity專有着色器語言。shaderlab具有跨平臺、圖形化編程、便於着色器與unity通信等優點。在unity2018.3.5f以後版本,可以使用圖形化工具shader graph來大幅縮減shader編程成本,使這個令人頭疼的語言走入尋常百姓家。。。。。但作爲一個unityer最好具有基本的Shader Lab編程能力,至少了解基本效果的代碼實現過程。

mesh、材質、着色器的與模型的關係

把模型比作一隻兔子,那mesh就是兔子的骨架,頂點就是骨架的端點,片段就是由頂點組成的面,材質就是皮肉用來裝飾片段的,shader就是用來控制如何顯示材質的。

關於頂點、片段處理器

頂點着色器和片段着色器都有自己獨立的硬件處理單元。該硬件處理單元擁有非常強大的並行運算能力,非常擅長矩陣計算,片段處理器還可以告訴查詢紋理信息。

白話:頂點着色器負責定位像素位置!片段着色器負責修改像素顏色!!

頂點着色程序與片斷着色程序通常是同時存在,相互配合,前者的輸出作爲後者的輸入。不過,也可以只有頂點着色程序。如果只有頂點着色程序,那麼只對輸入的頂點進行操作,而頂點內部的點則按照硬件默認的方式自動插值。例如,輸入一個三角面片,頂點着色程序對其進行phong光照計算,只計算三個頂點的光照顏色,而三角面片內部點的顏色按照硬件默認的算法(Gourand明暗處理或者快速phong明暗處理)進行插值,如果圖形硬件比較先進,默認的處理算法較好(快速phong明暗處理),則效果也會較好;如果圖形硬件使用Gourand明暗處理算法,則會出現馬赫帶效應(條帶化)。
而片斷着色程序是對每個片斷進行獨立的顏色計算,並且算法由自己編寫,不但可控性好,而且可以達到更好的效果。
由於GPU對數據進行並行處理,所以每個數據都會執行一次shader程序程序。即,每個頂點數據都會執行一次頂點程序;每個片段都會執行一次片段程序。
片段就是所有三維頂點在光柵化之後的數據集合,這些數據沒有經過深度值比較,而屏幕顯示的像素是經過深度比較的。

頂點着色器、片段着色器與表面着色器的關係

作用

頂點着色器負責頂點座標變換,片段着色器負責像素的顏色計算。頂點着色器計算好座標信息後傳入片段着色器計算顏色。所以頂點着色器和片段着色器是合作關係。
表面着色器是封裝了頂點和片段着色器的新api。與他們屬於上下層關係。
shader編譯時會將表面渲染代碼編譯成多個pass代碼塊,再分解成頂點/片元着色器。

區別

頂點着色器用於處理頂點。片段着色器用於處理面。
表面着色器是對頂點着色器與片段着色器的進一步封裝。
即是說,表面着色器有一套即成的處理辦法,不用去搞那些細節。
而頂點着色器和片段着色器更接近底層,可以處理一些細節問題。

着色器的工作流程
請求
3D應用或遊戲
3D API : OpenGL DirectX 接口
GPU Front End : GPU前端
Primitive Assembly : 圖元裝配
Programmable Vertex Proccessor : 可編程頂點處理器
Rasterization and interpolation : 光柵化與插值
Pixel Operation: 像素處理
Frame Buffer : 幀緩存
Programmable Fragment Proccessor: 可編程片段處理器

二,Shader Lab語法

基本結構
Shader "path/name" {
 	Properties{
 		//_CG變量名 ("unity可見的變量名", 屬性類型) = 值
 		_Color ("My Color", Color) = (1, 1, 1, .5) 
 	 } 
 	 Subshader{
 	  }
 }
  • path/name :unity編輯器中檢索的位置和shader名。shader名儘量與shader文件名一樣。
  • Properties:shader屬性,用於cg與unity通信。
  • Subshader:shader解決方案。每個shader程序包含至少一個subshader,用於解決硬件性能兼容問題。shader的主代碼部分都寫在這裏
Properties

屬性的結構:_CG變量名 (“unity可見的變量名”, 屬性類型) = 值
例:_Color (“My Color”, Color) = (1, 1, 1, .5)

屬性類型表

類型 說明 實例
Int 整型 (.1, 2)
Float 浮點數 .5
Vector 四維向量 (.5, 1 , 1, 0.5)
Range 範圍1-2.3的浮點數 (1, 2.3)
Color RGBA顏色 (1,1,1,.5)
2D 2d貼圖, 2d紋理,默認值可以爲一個代表默認tint顏色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一個 ”white”{}
3D 3d貼圖
Cube 6面立方貼圖 ”white”{}
Rect 矩形貼圖 ”white”{}
SubShader
SubShader { 
	Tags { "RenderType" = "Opaque" "ForceNoShadowCasting" = "True" "IgnoreProjector" = "True"}   
	LOD 100
	 Pass{
		 	Fog{Mode OFF}
		 	
		 	//固定渲染器
			Material{
               	Diffuse[_Color]  //設置漫反射
       		}      
            Lighting On
	        SeparateSpecular On   //啓用高光顏色
            //設置紋理
            SetTexture[_MainTex]{
		 	//表面渲染器
		 	#pragma surface surf Lambert
		 	//頂點渲染器
			#pragma vertexvert
			//片段渲染器
		 	#pragma fragment frag
	 }
	Pass{
	}
}
Tags

tags可以填寫多個命令,可以控制渲染時機。可以通過在unity的asset窗口中點擊shader查看tags生效情況。

標籤 說明
“RenderType”=“Opaque” 系統在渲染不透明物體時調用該shader
“RenderType” = “Transparent” 系統在渲染透明物體時調用該shader,絕大部分透明的物體、包括粒子特效都使用這個
“RenderType” = “Background” 系統渲染背景時調用,天空盒都使用這個
“RenderType” = “Overlay” 系統渲染gui鏡頭時調用,GUI、鏡頭光暈都使用這個
“IgnoreProjector”=“True” 忽略Projectors
“ForceNoShadowCasting”=“True” 不生成陰影
“Queue”=“xxx” 指定渲染隊列順序,下面有詳細說明

Queue的說明

關鍵字 說明
Background 最先調用的,用來渲染天空盒或背景
Geometry 默認值,用來渲染非透明物體(一般情況下,場景中的絕大多數物體應該是非透明的)
AlphaTest 用來渲染經過Alpha Test的像素,單獨爲AlphaTest設定一個Queue是出於對效率的考慮
Transparent 以從後往前的順序渲染透明物體
Overlay 用來渲染疊加的效果,是渲染的最後階段(比如鏡頭光暈等特效)

這些預定義的值本質上是一組定義整數,Background = 1000, Geometry = 2000, AlphaTest = 2450, Transparent = 3000,最後Overlay = 4000。在我們實際設置Queue值時,不僅能使用上面的幾個預定義值,我們也可以指定自己的Queue值,寫成類似這樣:“Queue”=“Transparent+100”,表示一個在Transparent之後100的Queue上進行調用。通過調整Queue值,我們可以確保某些物體一定在另一些物體之前或者之後渲染,這個技巧有時候很有用處。(比如遮擋描邊效果,應該就是這麼來的)

LOD

細節等級。大家玩喫雞的時候,從飛機上跳下,這時看到地圖上的建築都是比較粗糙的塊,當距離慢慢拉近,建築模型變得越發精緻,這就是LOD技術,根據不同的範圍使用不同的模型。shader的LOD也是同樣用法,不同細節等級,使用不同的LOD。在Unity的Quality Settings中可以設定最大LOD值,噹噹前LOD小於shader LOD時,那個sub shader就會失效.
VertexLit及其系列 = 100
Decal, Reflective VertexLit = 150
Diffuse = 200
Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
Bumped, Specular = 300
Bumped Specular = 400
Parallax = 500
Parallax Specular = 600### 三、實例

pass

pass是實現着色器具體代碼的地方。一個subshader內可以有多個pass。但儘可能用較少的pass實現是對性能的考慮。

pass內的tags說明
pass內的tags有別與subshader中的tags

取值 例子 說明
Always “LightMode”=“Always” 不管是用哪種渲染路徑,該pass總是會被渲染。但不計算任何光照
Forwardbase “LightMode”=“ForwardBase” 用於向前渲染,該pass會計算環境光,重要的平行光,逐頂點/SH光源和lightmaps
ForwardAdd “LightMode”=“ForwardAdd” 用於向前渲染,該pass會計算額外的逐像素光源,每個pass對應一個光源
Deferred “LightMode”=“Deferred” 用於向前渲染,該pass會渲染G緩衝,G-buffer
ShadowCaster “LightMode”=“ShadowCaster” 把物體的深度信息渲染到盈盈映射紋理(shadowmap)或一張深度紋理中,用於渲染產生陰影的物體
ShadowCollector “LightMode”=“ShadowCollector” 用於收集物體陰影到屏幕座標Buff裏
PrepassBase 用於遺留的延遲渲染,該pass會渲染法線和高光反射的指數部分
PrepassFinal 用於遺留的延遲渲染,該pass通過合併紋理、光照和自發光來渲染得到最後的顏色
Vertex、VertexLMRGBM和VertexLM 用於遺留的頂點照明渲染

pass 內的代碼分爲:固定渲染管線、可編程頂點/片段渲染管線,可編程表面渲染管線。
下面是對三種渲染管線的詳細介紹。

pass中的ragma

ragma用於對渲染器的控制。
ragma 參數表

命令 參數 實例 說明
vertex #pragma vertex name 將函數name的代碼編譯爲頂點程序
fragment #pragma fragment name 將函數name的代碼編譯爲片元程序
geometry #pragma geometry name 將函數name的代碼編譯爲DX10的幾何着色器
hull #pragma hull name 將函數name 的代碼編譯爲DX11hull着色器
domain #pragma domain name 將函數name 的代碼編譯爲DX11 domain着色器
fragmentoption option #pragma fragmentoption option 添加選項到編譯的OpenGL片段程序。對頂點程序或編譯目標不是opengl的程序無效
target target 2.0、target 3.0、target 4.0、target 5.0 #pragma target name 設置着色器的編譯目標,對應不同版本的着色器模型
only_renderers space separated d3d9(direct3d 9)、d3d11、opengl、gles(opengl 2s 2.0)、xbox360、ps3、flash #pragma only_renderers space separated names 僅編譯到指定的渲染平臺
exclude_renderers space separated d3d9(direct3d 9)、d3d11、opengl、gles(opengl 2s 2.0)、xbox360、ps3、flash #pragma exclude_renderers space separated names 不編譯到指定的渲染平臺
glsl #pragma glsl 爲桌面系統的opengl進行編譯時,將cg/hlsl代碼轉爲glsl代碼
glsl_no_auto_normalization #pragma glsl_no_auto_normalization name 編譯到移動平臺glsl時(ios/android), 關閉在定點着色器中對法線向量和切線向量自動進行規範化

着色器中的參數

從應用階段傳遞模型數據給頂點着色器時 常用的語義
命令 實例 說明
POSITION 模型空間中的頂點位置,一般是float4類型
NORMAL 頂點法線,float3類型
TANGENT 頂點切線 float4
TEXCOORD0~N 該頂點紋理座標,0是第一組,一般是flkoat2 或float4類型
COLOR 定點顏色,通常是fixed4或float4類型
從頂點着色器傳遞給片元着色器時 常用的語義
命令 實例 說明
SV_POSITION 裁剪空間中的頂點座標,結構體中必須包含一個用該語義修飾的變量
COLOR0 用於輸出第一組頂點顏色
COLOR1 通常用於輸出第二組頂點顏色
TEXCOORD0~TEXCOORD7 通常用於輸出紋理座標
片元着色器輸出給unity時常用的語義
命令 實例 說明
SV_Target 輸出值將會存到渲染目標(render target)中
unity 內置的矩陣變換
命令 實例 說明
UNITY_MATRIX_MVP 當前的模型觀察投影矩陣,用於將頂點/方向矢量從模型空間變換到裁剪空間
UNITY_MATRIX_MV 當前的模型觀察矩陣,用於將頂點/方向矢量從模型空間變換到觀察空間
UNITY_MATRIX_V 當前的觀察矩陣,用於將頂點/方向矢量從世界空間變換到觀察空間
UNITY_MATRIX_P 當前的投影矩陣,用於將頂點/方向矢量從觀察空間變換到裁剪空間
UNITY_MATRIX_VP 當前的觀察投影矩陣,用於將頂點/方向矢量從世界空間變換到裁剪空間
UNITY_MATRIX_T_MV UNITY_MATRIX_MV 的轉置矩陣
UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆轉置矩陣,用於將法線從模型空間變換到觀察空間,也可以用於得到UNITY_MATRIX_MV的逆矩陣
_Object2World 當前的模型矩陣,用於將頂點/方向矢量從模型空間變換到世界空間
_World2Object _Object2World的逆轉矩陣,用於將頂點/方向矢量從世界空間變換到模型空間
unity 頂點轉換函數
命令 說明 實例
float4 UnityObjectToClipPos(float3 pos) 將一個點從object空間轉換成相機在均勻座標下的剪輯空間。這就相當於 mul(UNITY_MATRIX_MVP, float4(pos, 1.0)), 應該在它的位置上使用。
float3 UnityObjectToViewPos(float3 pos) 將一個點從object空間轉換爲view空間。這就相當於mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz, 應該在它的位置上使用。

輔助函數

命令 說明 實例
unity 內置的攝像機和屏幕參數
命令 實例 說明
float3 _WorldSpaceCameraPos 該攝像機在世界空間中的位置
float4 _ProjectionParams x=1.0 或-1.0(使用反轉的投影矩陣渲染時是負數),y=Near,z=Far,w= 1.0+1.0/Far, 其中near和far分別是近裁剪平面和遠裁剪平面與攝像機的距離
float4 _ScreenParams x=width,y=height,z=1.0+1.0/width,w=1.0+1.0/height, 其中width和height分別是該攝像機的渲染目標 (render target)的像素寬度和高度
float4 _ZBufferParams x=1-Far/near,yFar/Near, 最x/Far,wy/Far,該變量用於線性化Z緩存中的深度值
floart4 unity_OrhoParams x=width,y=height,z無意義,w=1.0(該相機是正交相機)或w=0.0(透視相機),其中width和height是正交投影相機的寬和高
float4x4 unity_CameraProjection 該攝像機的投影矩陣
floart4x4 unity_CameraInvProjection 該攝像機的投影矩陣的逆矩陣
float4 unity_CameraWorldClipPlanes 該攝像機的6個裁剪屏幕在世界空間下的等式,按左右上下近遠的順序裁剪平面
時間變量
命令 實例 說明
float4 _Time _Time.x;_Time.y; _Time.z; _Time.w; t是自該場景加載開始所經過的時間,4個分量分別是t/20,t,2t,3t
float4 _SinTime t是時間的正限制,4個分量分別是t/8,t/4,t/2,t
float4 _Costime t是時間的餘弦值,t/8,t/4.t/2,t
float4 unity_DeltaTime dt是時間增量,4個值分別是dt,1/dt,smoothDt,1/smoothDt

UnityCG.cginc 庫

UnityCG.cginc 該文件中包含了很多即成的參數方法。使用十分方便

引入文件
CGPROGRAM
#include "UnityCG.cginc"
ENDCG
unitycg.cginc 常用結構
命令 參數 實例 說明
appdata_base 頂點位置、頂點法線、第一組紋理座標 float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord: TEXCOORD0; 可用於頂點着色器的輸入
appdata_tan 頂點位置、頂點切線、頂點法線、第一組紋理座標 float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; 可用於頂點着色器的輸入
appdata_full 頂點位置、頂點切線、頂點法線、四組(或更多)紋理座標i cfloat4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; #if defined(SHADER_API_XBOX360) half4 texcoord4 : TEXCOORD4; half4 texcoord5 : TEXCOORD5; #endif fixed4 color : COLOR; 可用於頂點着色器的輸入
appdata_img 可用於頂點着色器的輸入 float4 vertex : POSITION; half2 texcoord : TEXCOORD0; 可用於頂點着色器的輸入
v2f_img 裁剪空間中的位置、紋理座標 可用於頂點着色器的輸出
unitycg.cginc 常用函數
命令 參數 實例 說明
float4 WorldSpaceViewDir(float4 v) 輸入一個模型空間中的頂點位置,返回世界空間中從該點到攝像機的觀察方向
float4 UnityWorldSpaceViewDir(float4 v) 輸入一個世界空間中的頂點位置,返回世界空間中從該點到攝像機的觀察方向
float4 ObjSpaceViewDir(float4 v) 輸入一個模型空間中的頂點位置,返回模型空間中從該店到攝像機的觀察方向
float4 WorldSpace LightDir(flaot4 v) 僅用於向前渲染。 輸入一個模型空間中的頂點位置,返回世界空間中從該點到光源的光照方向。沒有被歸一化
float4 ObjectSpaceLightDir(float4 v) 僅用於向前渲染中,輸入一個模型空間中的頂點位置, 返回模型空間中從該點到光源的光照方向。沒有被歸一化
float4 UnityWorldSpaceLightDir(float4 v) 僅用於向前渲染中,輸入一個世界空間中的頂點位置, 返回世界空間中從該點到光源的光照方向。沒有被歸一化
float3 UnityObjectToWorldNormal(float3 norm) 把法線方向從模型空間中轉換到世界空間中
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量從模型空間中變換到世界空間中
float3 Unity WorldToObjectDir(float3 dir) 把方向矢量從世界空間變換到模型空間中

shader數學函數:

函數 說明 實例
radians(degree) 角度變弧度(一般默認都用弧度)
degrees(radian) 弧度變角度
sin(angle), cos(angle), tan(angle) 三角函數
asin(x) arc sine, 返回弧度 [-PI/2, PI/2];
acos(x) arc cosine,返回弧度 [0, PI]
atan(y, x) arc tangent, 返回弧度 [-PI, PI];
atan(y/x) arc tangent, 返回弧度 [-PI/2, PI/2];
pow(x, y) x的y次方
exp(x) 指數, log(x)
exp2(x) 2的x次方, log2(x)
sqrt(x) x的根號;
inversesqrt(x) x根號的倒數
abs(x) 絕對值
sign(x) 取當前數值的正負符號,返回 1, 0 或 -1 (x>0;x=0;x<0)
floor(x) 底部取整
ceil(x) 頂部取整
fract(x) 取小數部分
mod(x, y) 取模, x - y*floor(x/y)
min(x, y) 取最小值
max(x, y) 取最大值
clamp(x, min, max) min(max(x, min), max);
mix(x, y, a) x, y的線性混疊, x(1-a) + y*a;
step(edge, x) 如 x smoothstep(edge0, edge1, x): threshod smooth transition時使用。 edge0<=edge0時爲0.0, x>=edge1時爲1.0
length(x) 向量長度
distance(p0, p1) 兩點距離, length(p0-p1);
dot(x, y) 點積,各分量分別相乘 後 相加
cross(x, y) 差積 x[1]*y[2]-y[1]*x[2], x[2]*y[0] - y[2]*x[0], x[0]*y[1] - y[0]*x[1]
normalize(x) 歸一化 length(x)=1;
faceforward(N, I, Nref) 如 dot(Nref, I)< 0則N, 否則 -N
reflect(I, N) I的反射方向 I -2*dot(N, I)*N, N必須先歸一化
refract(I, N, eta) 折射 k=1.0-etaeta(1.0 - dot(N, I) * dot(N, I)); 如k<0.0 則0.0,否則 etaI - (etadot(N, I)+sqrt(k))*N
matrixCompMult(matX, matY) 矩陣相乘, 每個分量 自行相乘 r[j] = x[j]*y[j];
lessThan(vecX, vecY) 向量 每個分量比較 x < y
lessThanEqual(vecX, vecY) 向量 每個分量比較 x<=y
greaterThan(vecX, vecY) 向量 每個分量比較 x>y
greaterThanEqual(vecX, vecY) 向量 每個分量比較 x>=y
equal(vecX, vecY) 向量 每個分量比較 x==y
notEqual(vecX, vexY) 向量 每個分量比較 x!=y
any(bvecX) 只要有一個分量是true, 則true
all(bvecX) 所有分量是true, 則true
not(bvecX) 所有分量取反

3 着色器實例

1. 固定渲染管線

固定功能管線着色器的關鍵代碼都在Pass的材質設置Material{}和紋理設置SetTexture{}部分。
目前固定着色器已經逐漸退出市場,只在爲兼容一些老舊硬件設備而存在。

Shader "Custom/VertexList" {
    Properties {
    	//設置與unity通信的變量,用來通過unity編輯器獲取素材資源及參數
        _Color("Main Color",Color) = (0,1,1,0.5)
        _SpecColor("Spec Color",Color) = (1,1,1,1)
        _Emission("Emissive Color",Color) = (0,0,0,0)
        _Shininess("Shininess",Range(0.01,1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Pass{
                Material{
                       Diffuse[_Color]  //設置漫反射
                       Ambient[_Color]  //環境光
                       Shininess[_Shininess]  //光澤度
                       Specular[_SpecColor]  //高光色
                       Emission[_Emission]  //自發光
                }      
                Lighting On
                SeparateSpecular On   //啓用高光顏色
                //設置紋理
                SetTexture[_MainTex]{
                		constantColor[_Color]   //設置顏色常量
                   	//混合命令
                   	combine texture * primary DOUBLE,
                   	texture *constant
                }
            }
    }
}
2 .頂點/片段渲染管線

功能強大,且用途最多的渲染器

頂點/片段渲染管線 卸載pass塊中,用CGPROGRAM 標籤包裹。

該shader 會實現根據觀察方向而變色的效果

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/SurfaceShader"{   
	 SubShader    {        
 		Tags { "RenderType" = "Opaque" }       
		LOD 100
		Pass {           
        		 	//CG代碼塊   
        		 	CGPROGRAM                
        		 		//一個 CGPROGRAM 塊中必須有且只能有一個vertex 和一個fragment
        		 		#pragma vertex vert                
        		 		#pragma fragment frag
                			//引入unityCG處理庫 
                			#include "UnityCG.cginc"
                			//定義一個數據結構,該結構包含一個4維向量,一個三維向量      v2f的意思是頂點to片元          
                			struct v2f{ 
	                			//獲取位置
	                			float4 pos : SV_POSITION;
	                			//獲取顏色                    
	                			float2 color : COLOR0;                
	                		};
                			//頂點程序代碼,用於計算位置和顏色。   v2f是剛纔新建的數據結構,vert是在cgprogram註冊的用於頂點計算的程序名  
                			//該方法輸入值appdata_base v是與模型關聯後自動輸入的,他的輸出值會自動傳入到片段代碼塊。所以相關聯的頂點和片段方法的輸出和輸入類型一定要一致        
                			v2f vert(appdata_base v){
	                			//創建v2f數據 o
	                			v2f o;                    
	                			//計算位置                    
	                			o.pos = UnityObjectToClipPos(v.vertex);                    
	                			//計算顏色                    
	                			o.color = v.normal* 0.5 + 0.5;                    
	                			//返回該v2f數據                    
	                			return o;                
	                		 }                
	                		 //片段程序代碼   
	                		 //該代碼塊會自動接受頂點着色器的輸出值,而他的輸出值會交給像素着色器最終顯示在屏幕上
	                		 half4 frag(v2f i) : COLOR{
	                		 	//返回輸入的顏色,並設置透明度爲1                    
	                		 	return half4(i.color,.5,1);                
	                		 }            
	                	ENDCG        
	        	}    
	}    
	//如果以上代碼塊失敗,則用默認vertexlit渲染器
	Fallback "VertexLit"
}

總是按方向着色

3. 表面渲染管線

備受unity寵愛的渲染器

在Unity中,表面着色器的關鍵代碼用Cg/HLSL語言編寫,然後嵌在ShaderLab的結構代碼中使用。使用表面着色器,用戶僅需要編寫最關鍵的表面函數,其餘周邊代碼將由Unity自動生成,包括適配各種光源類型、渲染實時陰影以及集成到前向/延遲渲染管線中等。
光照模型可以是內置的Lambert和BlinnPhong,或者是自定義的光照模型。
表面函數的作用是接收輸入的UV或者附加數據,然後進行處理,最後將結構填充到輸出結構體SurfaceOutPut中。

表面着色器的輸入參數表

數據類型 參數 說明
float3 viewDir 視角方向
float4 COLOR 每個頂點的插值顏色
float4 screenPos 屏幕座標(使用.xy/.w來獲得屏幕2D座標)
float3 worldPos 世界座標
float3 worldRefl 世界座標系中的反射向量
float3 worldNormal 世界座標系中的法線向量
INTERNAL_DATA 當輸入結構包含worldRefl或worldNormal且表面函數會寫入輸出結構的Normal字段是需包含此聲明

表面着色器的輸出參數表

struct SurfaceOutput{
	    half3 Albedo;//反射光
	    half3 Normal;//法線
	    half3 Emission;//自發光
	    half Specular;//高光
	    half Gloss;//光澤度
	    half Alpha;//透明度
};

實例說明

Shader "Custom/surfShader"
	Properties{}
	SubShader{
		//當系統渲染不透明物體時 調用該shader
		Tags{"RenderType" = "Opaque"}
		//表面着色器代碼塊  不放在pass中,編譯後會分放至各個pass中
		CGPROGRAM
			//定義着色器類型爲surface(表面着色器),並使用光照模型Lambert
			#progma surface surf Lambert
			//定義輸入數據的結構體
			struct Input {
				float color :COLOR;
			}
			//定義輸出數據的結構體
			struct SurfaceOutput{
   				half3 Albedo;//反射光
   				half3 Normal;//法線
   				half3 Emission;//自發光
   				half Specular;//高光
   				half Gloss;//光澤度
   				half Alpha;//透明度
  			};
			//表面函數
			void surf(Input IN, inoutSurfaceOutput o){
				o.Albedo = 1;//輸出顏色
			}
		ENDCG
	}
	Fallback "Diffuse"//備選着色器
}

四,着色器效果集

該連接中包含很多着色器代碼實例,具體的代碼和詳細的註釋,不定時更新中
https://blog.csdn.net/lengyoumo/article/details/99676462

五,三大測試與剔除、透明混合

三大測試:深度測試、透明測試、模版測試
重點:三大測試與剔除都是決定是否顯示像素條件!混合是指有透明物體的情況下像素該如何疊加顯示
深度測試依據物體在鏡頭前的空間位置排序。
透明測試依據顏色透明度,也就是alpha值。
模版測試依據自定義的值,當同樣帶有模版值的元素疊加時觸發

剔除與三種測試渲染順序按先後排列。

5.0 Cull剔除

Cull 是剔除的意思。

命令 說明 實例
Off 繪製所有的面 Cull Off
Front 不繪製面向相機部分的面 Cull Front
Back 不繪製背對相機的面 Cull Back

5.1 透明測試 AlphaTest

當透明度到達指定值,就輸出像素,否則拋棄
語法:

指令 說明 實例
Greater 大於,只渲染大於該值的像素。 alphatest greater [_alphaValue] //類似於摳圖
Less 小於,只渲染小於該值的像素。 類似於反向摳圖
GEqual 大於等於
LEqual 小於等於
Equal 等於
NotEqual 不等於
Always 總是
Never 永不
Off 關閉 alphatest Off

例1 表面着色器

實例,只要聲明 alphatest greater [_alphaValue] 即可。
	Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _alphaValue("alphavalue",range(0,1))=0.3
    }
    SubShader {
        Pass{
	        alphatest greater [_alphaValue]
	        CGPROGRAM
				...............
				ENDCG
        	}
      }

例2 片段着色器

fixed4 frag(v2f i):SV_Target{
	fixed4 texColor = tex2D(_MainTex, i.uv);
	clip(texColor.a - _Cutoff);
	//等同於
	//if((texColor.a - _Cutoff)<0.0){
	//	discard;
	//}
}
5.1.2 透明度混合 Blend

混合命令

指令 說明 實例
Blend Off 關閉混合
Blend SrcFactor DstFactor 開啓混合,並設置混合因子,片元顏色胡i成因SrcFactor,而已經存在顏色緩存中的顏色會誠意DstFactor,然後把兩者相加後再存入顏色緩衝中
Blend SrcFactor DstFactor, SrcFactorA DstFactorA 上同,使用不同因子來混合透明通道
BlendOp BlendOperation 並非是把源顏色和目標顏色簡單相加後混合,而是使用BlendOperation對他們進行其他操作

混合因子

指令 說明 實例
One 因子值爲1
Zero 因子值爲0
SrcColor 因子爲源顏色值(當前片元),當用於混合rgb時,使用SrcColor的RGb分量作爲混合因子,當用於混合a的混合等式時,使用SrcColor的A分量作爲混合因子
SrcAlpha 因子爲源顏色的透明度,A通道
DstColor 因子爲目標顏色(已經存在顏色緩存中的顏色),當用於混合rgb時,使用DstColor的RGb分量作爲混合因子,當用於混合a的混合等式時,使用DstColor的A分量作爲混合因子
DstAlpha 因子爲源顏色的透明度,A通道
OneMinusSrcColor 因子爲 1 - 源顏色,其餘與SrcColor相同
OneMinusSrcAlpha 因子爲 1-源顏色的透明度值
OneMinusDstColor 因子爲 1- 目標顏色,其餘與DstColor相同
OneMinusDstAlpha 因子爲 1- 目標顏色透明度

混合操作
BlendOp

指令 說明 實例
Add 將混合後的源顏色和目標顏色相加
Sub 將混合後的源顏色減去混合後的目標顏色
RevSub 用混合後的目標顏色減去混合後的源顏色
Min 使用源顏色和目標i顏色中較小的值
Max 使用源顏色和目標顏色中較大的值

片段
正常:Blend SrcAlpha OneMunusSrcAlph
柔和相加 Blend OneMinusDstColor One
正片疊底:Blend DstColor Zero
兩倍相乘:Blend DstColor SrcColor
變暗:BlendOp Min
Blend One One
變量:BlendOp Max
Blend One One
濾色:Blend OneMinusDstColor One 等偶同於Blend One OneMinusSrcColor
線性減淡:Blend One One

5.2 模板測試 StencilTest

啥是模板測試,每個像素都有一個stencil值,在同一個像素上,所有shader的stencil都共享這一個值,當有其他帶有遮罩像素與其重合時就能獲取到該值,並根據自身的stencil值處理或。典型的應用就是遮罩顯示。你可以選擇每次重合都增加1,然後再指定某個物體,當值達到某個數量級再顯示。這樣的場景,比如,有個隱身的怪物,你只有使用聖水噴霧才能讓他現行,但必須噴3次纔行,這樣,空中就存在了3次疊加的霧,透過這個3層霧就能看到怪物了。但你偏一下角度,透過兩層wu就看不到。
Stencil完整語法:

stencil{
	Ref referenceValue //每個像素都有一個stencil值,在同一個像素上,所有shader的stencil都共享這一個值,當有其他帶有遮罩像素與其重合時就能獲取到該值,並根據自身的stencil值處理觸發小狗
	ReadMask  readMask  //讀遮罩
	WriteMask writeMask  //寫遮罩
	Comp comparisonFunction   //條件判斷  大於小於等觸發
	Pass stencilOperation    //滿足條件後,相應的處理辦法   是替換值還是增長值等
	Fail stencilOperation    //沒有通過模板測試怎麼辦
	ZFail stencilOperation    //通過了模板測試怎麼辦
}

模板語法

參數 說明 實例
Ref ref用來設定參考值(範圍0-255)。這個值用來與stencilbuffer比較
ReadMask ReadMask 從字面意思的理解就是讀遮罩,readMask將和referenceValue以及stencilBufferValue進行按位與(&)操作,readMask取值範圍也是0-255的整數,默認值爲255,二進制位11111111,即讀取的時候不對referenceValue和stencilBufferValue產生效果,讀取的還是原始值
WriteMask WriteMask是當寫入模板緩衝時進行掩碼操作(按位與【&】),writeMask取值範圍是0-255的整數,默認值也是255,即當修改stencilBufferValue值時,寫入的仍然是原始值。
Comp Comp是定義參考值(referenceValue)與緩衝值(stencilBufferValue)比較的操作函數,默認值:always
Pass Pass是定義當模板測試(和深度測試)通過時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep
Fail Fail是定義當模板測試(和深度測試)失敗時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep
ZFail ZFail是定義當模板測試通過而深度測試失敗時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep

模板對比

指令 說明 實例
Greater 大於,只渲染大於該值的像素。 alphatest greater [_alphaValue] //類似於摳圖
Less 小於,只渲染小於該值的像素。 類似於反向摳圖
GEqual 大於等於
LEqual 小於等於
Equal 等於
NotEqual 不等於
Always 總是
Never 永不
Off 關閉 alphatest Off

模板操作

指令 說明 實例
Keep 保留當前緩衝中的內容,即stencilBufferValue不變
Zero 將0寫入緩衝,即stencilBufferValue值變爲0。
Replace 將參考值寫入緩衝,即將referenceValue賦值給stencilBufferValue。
IncrSat stencilBufferValue加1,如果stencilBufferValue超過255了,那麼保留爲255,即不大於255。
DecrSat stencilBufferValue減1,如果stencilBufferValue超過爲0,那麼保留爲0,即不小於0。
Invert 將當前模板緩衝值(stencilBufferValue)按位取反
IncrWrap 當前緩衝的值加1,如果緩衝值超過255了,那麼變成0,(然後繼續自增)
DecrWrap 當前緩衝的值減1,如果緩衝值已經爲0,那麼變成255,(然後繼續自減) 。

實例:遮罩
將此shader付給遮罩物體

Shader "Custom/st1" {
	SubShader{
		Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1"}
			CGINCLUDE
				struct appdata {
					float4 vertex : POSITION;
				};
				struct v2f {
					float4 pos : SV_POSITION;
				};
				v2f vert(appdata v) {
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					return o;
				}
				half4 frag(v2f i) : SV_Target {
					return half4(1,1,0,1);
				}
			ENDCG
			Pass {
				ColorMask 0
				ZWrite Off
				Stencil
				{
					Ref 1
					Comp Always
					Pass Replace
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
				ENDCG
			}
	}
}

將此shader付給被遮罩物體

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "Custom/st2" {
	Properties{
	_MainTex("Base (RGB)", 2D) = "white" {}
	}
		SubShader{
			Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }
			LOD 100
			Pass {
				Stencil
				{
					Ref 2
					Comp Equal
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
					#pragma multi_compile_fog
					#include "UnityCG.cginc"
					struct appdata_t {
						float4 vertex : POSITION;
						float2 texcoord : TEXCOORD0;
					};
					struct v2f {
						float4 vertex : SV_POSITION;
						half2 texcoord : TEXCOORD0;
						UNITY_FOG_COORDS(1)
					};
					sampler2D _MainTex;
					float4 _MainTex_ST;
					v2f vert(appdata_t v)
					{
						v2f o;
						o.vertex = UnityObjectToClipPos(v.vertex);
						o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
						UNITY_TRANSFER_FOG(o,o.vertex);
						return o;
					}
					fixed4 frag(v2f i) : SV_Target
					{
						fixed4 col = tex2D(_MainTex, i.texcoord);
						UNITY_APPLY_FOG(i.fogCoord, col);
						UNITY_OPAQUE_ALPHA(col.a);
						return col;
					}
				ENDCG
			}
	}
}

即可完成

5.3 深度測試 DepthTest

根據深度值選擇通過測試。
Cull Back | Front | Off

ZWrite On | Off:用於控制是否將對象的像素寫入深度緩衝(默認開啓),如果需要繪製純色物體,便將此項打開。如需繪製半透明效果,則關閉深度緩衝。
開啓深度寫入:當兩個像素重合時,根據深度緩衝中的值對比,剔除掉離相機較遠的那個,留下最近的那個顯示。
關閉深度寫入:不剔除任何像素,按順序覆蓋像素。(半透明物體需要這個)

ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
用於控制深度測試如何執行, 缺省值是LEqual。如果要繪製的像素的Z值 小余等於深度緩衝區中的值,那麼就用新的像素顏色值替換。

Offset Factor,Units
利用Factor和Units來定義深度偏移
Factor參數表示Z縮放的最大斜率的值
Units參數表示可分辨的最小深度緩衝區的值
利用該句法,我們就可以強制使位於同一位置上的兩個集合體中的一個幾何體繪製在另一個的上層
以上幾個值可以行內寫。

懶人片段

	//頂點着色器正文
	v2f vert(a2v v) {
		v2f o;
		//獲取頂點的裁剪座標
		o.pos = UnityObjectToClipPos(v.vertex);//將模型頂點座標轉換爲裁剪座標
		//獲取紋理座標
		o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//貼圖與頂點對應的uv,必須配合下面的TRANSFER_SHADOW(o)
		//頂點法線 * 世界轉模型法線  獲取世界法線?
		o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
		//獲取世界頂點
		o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
		TRANSFER_SHADOW(o);
		return o;
	}		
	ColorMask 0   //屏蔽所有顏色
	fiexed4 frag(v2f i):color{
		//紋理尋址
		fixed4 colo = tex2D(_MainTex, i.texcoord)//給貼圖上色
		colo = _Color * col;
	}		
語法解釋:

SetTexture[_MainTex]{
Combine Primary * Texture
}

SeparateSpecular On

Blend SrcAlpha OneMinusSrcAlpha

該文章參考了下列文章:
https://www.jianshu.com/p/5be2801e226c
https://docs.unity3d.com/Manual/SL-Pass.html
https://blog.csdn.net/weixin_33973609/article/details/85751777
https://blog.csdn.net/pizi0475/article/details/6574700
https://blog.csdn.net/zx1091515459/article/details/79262053
https://blog.csdn.net/zyq20130118/article/details/52874639
https://blog.csdn.net/qq_38572472/article/details/79020122
https://www.cnblogs.com/Jason-c/p/8385946.html
https://blog.csdn.net/qq826364410/article/details/81744032 關於測試
喜歡看書的同學,重點推薦馮樂樂的shader入門教程,雖然說是入門教程,但寫的由淺入深閱讀曲線十分不錯。重點推薦。csdn還有她的博客請自搜。

新地址
https://github.com/QianMo/Awesome-Unity-Shader

https://blog.csdn.net/lyh916/category_6208767.html

https://blog.csdn.net/ynnmnm/article/details/69791337

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章