U3D_Shader程式設計(第一篇:快速入門篇)
《U3D_Shader程式設計》
##《U3D_Shader程式設計》釋出說明:
++++Shader一個高大上的領域,不管怎麼樣,我來了。
++++立鑽哥哥從2018年開始正式對Shader進行戰略佈局。
++++《U3D_Shader程式設計》將從零開始,循序漸進探索,還是先探索一段時間吧,後期根據需要再推出一個精品博文,這篇就算一個雜談吧。
##《U3D_Shader程式設計》目錄:
#第一篇:快速入門篇
#第二篇:基礎夯實篇
#第三篇:基礎進階篇
#第四篇:中級挑戰篇
#第五篇:高階成魔篇
#第一篇:快速入門篇
#第一篇:快速入門篇
++++第一章:Shader著色器
++++第二章:Surface/Vertex Shader
++++第三章:Shader案例
##第一章:Shader著色器
++第一章:Shader著色器
++++1.1、什麼是Shader
++++1.2、什麼是渲染管線
++++1.3、Shader和材質,貼圖的關係
++++1.4、三大主流的高階程式語言
++++1.5、Unity Shader的組織形式
++++1.6、固定管線Shader
++1.1、什麼是Shader
++++Shader,中文翻譯即著色器,是一種較為短小的程式片段,用於告訴圖形硬體如何計算和輸出影象。(過去由組合語言編寫,現在可以使用高階語言來編寫。)
++++Shader就是可程式設計圖形管線的演算法片段。
++++Shader主要分為兩類:
++1.2、什麼是渲染管線
++++渲染管線也稱為渲染流水線,是顯示晶片內部處理圖形訊號相互獨立的並行處理單元。(一個流水線是一系列可以並行和按照固定順序進行的階段。)(每個階段都從它的前一階段接收輸入,然後把輸出發給隨後的階段。)
++++渲染管線包括:應用程式階段(Application State)、幾何階段(Geometry Stage)、光柵化階段(Rasterizer Stage)、後期緩衝(Back Buffer)等階段。
++++應用程式階段(Application State):
--準備場景資料:將資料(攝像機位置、視錐體、場景中的模型、光源等)載入到視訊記憶體中;
--粗粒度剔除(culling);
--設定模型的渲染狀態:指定材質(漫反射顏色、高光顏色)、指定紋理、指定Shader(指定頂點著色器(Vertex Shader)、指定片元著色器(Fragment Shader))、指定光源屬性。
--呼叫DrawCall:發起方CPU、接收方GPU、命令緩衝區(Command Buffer,可放入改變渲染狀態、DrawCall在內的多種命令。)
=>>>>輸出渲染圖元(rendering primitives):進入下一階段(幾何階段(Geometry Stage))
++++幾何階段(Geometry Stage):
--頂點著色器(Vertex Shader):完全可程式設計,通常用於實現頂點的空間變換、頂點著色等功能。
----座標變換:對頂點座標進行某種變換(可模擬水面、布料等);把頂點座標從模型空間轉換到齊次裁剪空間,接著通常再由硬體做透視除法後,最終得到歸一化的裝置座標(NDC:Normalized Device Coordinates)。
----逐頂點光照。
----輸出後續階段所需的數,如紋理座標。
--曲面細分著色器(tessellation Shader):用於細分圖元。
--幾何著色器(geometry Shader):執行逐圖元(perPrimitive)的著色操作或產生更多圖元。
--裁剪(Clipping):將攝像機視野外的頂點裁剪掉,並剔除某些三角圖元的面片。
--螢幕對映(Screen Mapping):把每個圖元的座標轉換到螢幕座標中。(只將x和y座標縮放到螢幕座標系(Screen Coordinates),z值保留,螢幕座標系和z座標一起構成了視窗座標系(Window Coordinates))
=>>>>輸出螢幕空間的頂點資訊:進入下一階段(光柵化階段(Rasterizer Stage))
++++光柵化階段(Rasterizer Stage):
--三角形設定(Triangle Setup):計算光柵化一個三角網格所需的資訊。
--三角形遍歷(Triangle Traversal):檢查每個畫素是否被一個三角網格覆蓋,如果被覆蓋的話,就生成一個片元(fragment)。(一個片元並不是畫素,而是包含了很多狀態的集合。)
--片元著色器(Fragment Shader):用於實現逐片元(Per-Fragment)的著色操作。(紋理取樣)
--逐片元操作(Per-Fragment Operations,OpenGL的說法)或稱輸出合併階段(Output-Merger,DirectX的說法)
----模板測試(Stencil Test):該片元的模板值(使用讀取掩碼在模板緩衝區(Stencil Buffer)中讀取)、參考值(reference value:使用讀取掩碼)。(使用開發者指定的比較函式決定是否捨棄該片元:不管通過與否都能修改模板緩衝區的值)
----深度測試(Depth Test):該片元深度值、深度緩衝區的深度值。(使用開發者指定的比較函式決定是否通過:通過才有資格修改深度緩衝區的值。(通過開啟/關閉深度寫入實現))
----混合(Blend):源顏色(片元著色器得到的顏色)、模板顏色(顏色緩衝區中的顏色)。(使用混合函式進行混合操作)
=>>>>輸出圖形:進入下一階段(後置緩衝(Back Buffer))
++++後置緩衝(Back Buffer):使用雙重緩衝(Double Buffering)策略避免看到正在進行光柵化的圖元。(渲染完成後通過一個swap交換操作將前置緩衝(Front Buffer)和後置緩衝中的內容交換。)
++1.3、Shader和材質,貼圖的關係
++++Shader是圖形可程式設計方案的程式片段。Shader實際上就是一小段程式,它負責將輸入的頂點資料以指定的方式和輸入的貼圖或者顏色等組合起來,然後輸出。(繪圖單元可以根據這個輸出來將影象繪製到螢幕上。)
++++渲染管線是一種計算機從資料到最終圖形成像的描述。輸入的貼圖或顏色等,加上對應的Shader,以及對Shader的特定的引數設定,將這些內容打包儲存到一起得到的就是一個Material(材質)。(之後我們便可以將材質賦予三維物體來進行渲染(輸出)了。)
++++材質是商品,Shader是方法,貼圖是材料。(材質好比引擎最終使用的商品,Shader好比是生產這種商品的加工方法,而貼圖就是原材料。)
++1.4、三大主流的高階程式語言(GLSL、HLSL、Cg)
++++目前Shader Language有三種語言:GLSL(基於OpenGL的OpenGL Shading Language)、HLSL(基於DirectX的High Level Shading Language)、Cg語言(NVIDIA公司的C for Graphic)。
++++OpenGL(Open Graphics Library):定義了一個跨程式語言、跨平臺的程式設計介面規範的專業的圖形程式介面。(它用於三維影象(二維亦可),是一個功能強大,呼叫方便的底層圖形庫。)(頂點陣列的特性:提高頂點位置、法線、顏色、色彩指數、紋理座標、多形邊緣標識的傳輸速度。)(OpenGLShading Language:用於著色物件、頂點著色以及片段著色技術的擴充套件功能。)
++++DirectX(Direct eXtension,簡稱DX):是由微軟公司建立的多媒體程式設計介面。(由C++程式語言實現,遵循COM。)
++++Cg語言(C for Graphics):是為GPU程式設計設計的高階著色器語言。(由NVIDIA公司開發。)(Cg極力保留C語言的大部分語義,並讓開發者從硬體細節中解脫出來,Cg同時也有一個高階語言的其他好處,如程式碼的易重用性,可讀性得到提高,編譯器程式碼優化等。)
++1.5、Unity Shader的組織形式(ShaderLab基本結構)
++++Unity中的Shader稱之為ShaderLab,語法結構:
Shader “name”{
[Properties] //可選(在Inspector面板上顯示)
SubShaders //必選(Shader的核心程式碼)
[Fallback] //可選(預設Shader)
}
++++【Properties】:屬性定義,用來定義著色器中使用的貼圖資源或者數值引數等,這些屬性會在Inspector檢視的材質介面中顯示,可以方便的進行設定和修改。
++++【SubShader】:子著色器,一個著色器中包含有一個或者多個子著色器,Unity會從上到下遍歷子著色器,找到第一個能被使用者裝置支援的子著色器,並使用該著色器渲染,如果都不能使用,則使用備用著色器。
++++【Fallback】:備用著色器,是對硬體要求最低的著色器。
++++ShaderLab基本結構:
Shader“MyShader”{
Properties{
_MyTexture(“My Texture”, 2D) = “white”{ };
//這裡還可以寫其他屬性,如顏色等。
}
SubShader{
//立鑽哥哥:這裡才是真正的Shader程式碼
//--表面著色器(SurfaceShader)
//--頂點片段著色器(Vertex and Fragment Shader)
//--固定管線著色器(Fixed Function Shader)
}
SubShader{
//立鑽哥哥:這裡可以寫簡化版的Shader
//當由於裝置效能不夠,上面的SubShader無法執行時,就會執行這個Shader
}
}
++++內建Shader:
--Unlit:不發光(這只是一個紋理,不被任何光照影響。)
--VertexLit:頂點光照。
--Diffuse:漫反射。
--Normal mapped:法線貼圖。(比漫反射更昂貴:增加了一個或多個紋理(法線貼圖)和幾個著色器結構。)
--Specular:高光。(這增加了特殊的高光計算。)
--Normal Mapped Specular:高光法線貼圖。(這比高光更昂貴一點。)
--Parallax Normal mapped:視差法線貼圖。(這增加了視差法線貼圖計算。)
--Parallax Normal Mapped Specular:視差高光法線貼圖。(這增加了視差法線貼圖和鏡面高光計算。)
++1.6、固定管線Shader
++++固定管線Shader:propeties、material、lighting、set texture、Alpha通道。
++++properties:
Properties{
//立鑽哥哥:定義屬性(將顯示在inspector中)
_Color(“Main Color”, color) = (1,1,1,1) //顏色
_Ambient(“Ambient”, color)=(0.3,0.3,0.3,0.3) //環境光
_Specular(“Specular”, color)=(1,1,1,1) //高光
_Shininess(“Shininess”, range(0,8))=4 //預設為4,高光部分的範圍大小
_Emission(“Emission”, color)=(1,1,1,1) //自發光
_Maintex(“MainTex”,2d)=”” //第一張紋理圖
_Secondtex(“Secondtex”,2d)=”” //第二張紋理圖
}
++++material:
material{
//使用屬性
diffuse[_Color]
ambient[_Ambient]
specular[_Specular]
shininess[_Shininess]
emission[_Emission]
}
++++lighting:
--lighting on
--separatespecular on
++++set texture:
//設定紋理圖片
settexture[_Maintex]{
//合併貼圖與之前設定好的顏色/高光等資訊
//double表示高亮度提高2倍
//primary表示material裡面的資訊
combine texture * primary double
}
++++Alpha通道:
_Constant(“ConstantColor”, color)=(1,1,1,0.3)
SubShader{
//渲染佇列
Tags{“Queue” = “Transparent”}
Pass{
//Alpha通道處理
Blend SrcAlpha OneMinusSrcAlpha
//previous之前的
settexture[_Secondtex]{
constantColor[_Constant]
//合併第二張貼圖與之前設定的所有資訊
combine texture * previous double, texture
//,後面加texture表示使用貼圖本身的alpha資訊
}
}
}
++Shader簡單示例:
Shader “YlzShaderDemo/shader1”{
Properties{
//立鑽哥哥:定義屬性,將顯示在inspector中
_Color(“Main Color”, color)=(1,1,1,1) //顏色
_Ambient(“Ambient”, color)=(0.3,0.3,0.3,0.3) //環境光
_Specular(“Specular”, color)=(1,1,1,1) //高光
_Shininess(“Shininess”, range(0,8))=4 //預設為4(高光部分的範圍大小)
_Emission(“Emission”, color)=(1,1,1,1) //自發光
_Constant(“ConstantColor”, color)=(1,1,1,0.3)
_Maintex(“MainTex”,2d)=”” //第一張紋理圖
_Secondtex(“Secondtex”,2d)=”” //第二張紋理圖
}
SubShader{
Tags{“Queue” =“Transparent”} //渲染佇列
Pass{
Blend SrcAlpha OneMinusSrcAlpha //Alpha通道處理
material{
//使用屬性
diffuse[_Color]
ambient[_Ambient]
specular[_Specular]
shininess[_Shininess]
emission[_Emission]
}
lighting on
spearatespecular on
//設定紋理圖片
settexture[_Maintex]{
//合併貼圖與之前設定好的顏色/高光等資訊
//double表示亮度提高2倍
//primary表示material裡面的資訊
combine texture * primary double
}
//previous之前的
settexture[_Secondtex]{
constantColor[_Constant]
//合併第二張貼圖與之前設定的所有資訊
combine texture * previous double, texture
//,後面加texture表示使用貼圖本身的alpha資訊
}
}
}
}
##第二章:Surface/Vertex Shader
++第二章:Surface/Vertex Shader
++++2.1、Surface Shader表面著色器
++++2.2、Vertex&Fragment Shader頂點&片段著色器
++2.1、Surface Shader表面著色器
++++在使用Surface Shader時,它可以自動生成一些程式碼,比直接去使用低階的頂點和畫素著色器來說要容易很多。(但是Surface Shader並不是一種定製的語言,它只不過自動生成了以前必須去手寫的程式碼。)
++++Surface Shader還是使用Cg或HLSL語言編寫。(Surface Shader實際上就是對頂點和畫素著色器的一種包裝,它讓我們不用去關注更多的頂點和片段程式的細節,能夠快速地得到想要的著色器。)
++++建立一個Surface Shader:【Create】=>【Shader】=>【Standard Surface Shader】
++++\Assets\Shader\NewYanlzSurfaceShader.shader
//立鑽哥哥:新建表面著色器程式碼參考
Shader “Custom/NewYanlzSurfaceShader”{
Properties{
_Color(“Color”, Color) = (1,1,1,1) //顏色值
_MainTex(“Albedo(RGB)”, 2D) = “white”{} //主紋理
_Glossiness(“Smoothness”, Range(0,1)) = 0.5 //浮點值,用於計算高光的光澤度
_Metallic(“Metallic”, Range(0,1)) = 0.0 //浮點值,用於計算表現金屬的光澤度
}
SubShader{
Tags{ “RenderType”=”Opaque”} //渲染型別(Opaque:不透明物體)
LOD 200 //層次細節
CGPROGRAM //程式碼塊開始
//pragma指令格式:#pragam surface surfaceFunction lightModel [optionalparams]
#pragmasurface surf Standard fullforwardshadows //編譯指令
#pragmatarget 3.0//使用硬體的能力
sampler2D_MainTex;
struct Input{
float2 uv_MainTex;
}
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf(Input IN, inout SurfaceOutputStandard o){
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG //程式碼塊結束
}
FallBack “Diffuse”
}
++++Surface Shader的屬性:
--_Color:顏色值。
--_MainTex:主紋理。
--_Glossiness:一個浮點值,用於計算高光的光澤度。
--_Metallic:一個浮點值,用於計算表現金屬的光澤度。
++++SubShader:該shader有一個SubShader,但是,這個SubShader中並沒有Pass通道。(在Surface Shader當中不需要去編寫Pass通道,是因為Surface Shader就是對Vertex & Fragment Shader的一種包裝,它能夠自動生成著色器程式碼,生成的過程不要我們干預,Pass通道也能自動生成。)(添加了Pass通道,就會出現編譯錯誤。)
++++作為ShaderLab的基本結構,該預設的Surface Shader擁有一個FallBack,如果shader中的某一種特性不能夠使用,那麼會回滾到Diffuse(漫反射)。
++++【Tags{“RenderType”=”Opaque”}】:描述的是渲染型別。(Opaque:表示不透明的物體。)
++++【LOD 200】:是指層次細節。
++++【CGPROGRAM 到 <