Shaderlab Notizen 1 Unity的基本Shader框架寫法&顏色、光照與材質

一、一些基本感念
1.1 Shader和Material的基本概念

Shader(著色器)實際上就是一小段程序,它負責將輸入的Mesh(網格)以指定的方式和輸入的貼圖或者顏色等組合作用,然后輸出。繪圖單元可以依據這個輸出來將圖像繪制到屏幕上。輸入的貼圖或者顏色等,加上對應的Shader,以及對Shader的特定的參數設置,將這些內容(Shader及輸入參數)打包存儲在一起,得到的就是一個Material(材質)。之后,我們便可以將材質賦予合適的renderer(渲染器)來進行渲染(輸出)了。
Shader只是一段規定好輸入(顏色,貼圖等)和輸出(渲染器能夠讀懂的點和顏色的對應關系)的程序。而Shader開發者要做的就是根據輸入,進行計算變換,產生輸出而已。

二、Unity中Shader的三種基本類型

計算機圖形學中的渲染管線一般可以分為兩種類型:

1.固定功能渲染管線(fixed-functionrendering pipelines)
2.可編程渲染管線(programmablerendering pipelines)

Unity中Shader分為三種基本類型:
1.固定功能著色器(Fixed Function Shader)
2.表面著色器(Surface Shader)
3.頂點著色器&片段著色器(Vertex Shader & Fragment Shader)

固定功能著色器便是我們所說的固定功能渲染管線(fixed-functionrendering pipelines)的具體表現,而表面著色器、頂點著色器以及片段著色器便屬于可編程渲染管線。

2.1 固定功能著色器
Unity為Shader的書寫自帶的一層殼

2.2 表面著色器
Unity自己發揚光大的一項使Shader的書寫門檻降低和更易用的技術

2.3 頂點著色器和片段著色器
頂點著色器:產生紋理坐標,顏色,點大小,霧坐標,然后把它們傳遞給裁剪階段。
片段著色器:進行紋理查找,決定什么時候執行紋理查找,是否進行紋理查找,及把什么作為紋理坐標

2.4 區分Shader類型
沒有嵌套CG語言,也就是代碼段中沒有CGPROGARAM和ENDCG關鍵字的,就是固定功能著色器。
嵌套了CG語言,代碼段中有surf函數的,就是表面著色器。
嵌套了CG語言,代碼段中有#pragma vertex name和 #pragma fragment frag聲明的,就是頂點著色器&片段著色器。

三、 Shader賦給Material的方法
1.拖拽
2.在Material的Inspector面板中選擇

四、Shader的基本框架
Unity中Shader整體的框架寫法可以用如下的形式來概括:
Shader "name" { [Properties] SubShaders[Fallback] }
ps:所有用于這個著色器的代碼必須放置在之后的大括號中:{ }(稱為“塊”)。該名字應該是短且描述性的文字。它并不需要和shader文件名相同。而想要把著色器加入到Unity的子菜單里,名字需要用斜線(/)。

Paste_Image.png

首先是一些屬性定義,用來指定這段代碼將有哪些輸入。接下來是一個或者多個的子著色器,在實際運行中,哪一個子著色器被使用是由運行的平臺所決定的。子著色器是代碼的主體,每一個子著色器中包含一個或者多個的Pass。在計算著色時,平臺先選擇最優先可以使用的著色器,然后依次運行其中的Pass,然后得到輸出的結果。最后指定一個Fallback,即備胎,用來處理所有SubShader都不能運行的情況。

ps:在實際進行表面著色器的開發時,我們就是直接在SubShader這個層次上寫代碼,系統會將把我們的代碼編譯成若干個合適的Pass。

ps:SubShader在UnityShader的代碼段中必須有且至少有一個,而properties和fallback對于追求簡單的Shader,是可以不寫出來的。而復雜一點的Shader,當然各種properties、fallback什么的肯定都有,甚至有多個SubShader,而每個SubShader中又有多個Pass。

五、Properties屬性相關
properties一般定義在著色器的起始部分,我們可以在Shader書寫的時候定義多種多樣的屬性,而使用Shader的時候可以直接在材質檢視面板(Material Inspector)里編輯這些屬性,取不同的值或者紋理。

ps:Properties塊內的語法都是單行的。每個屬性都是由內部名稱開始,后面括號中是顯示在檢視面板(Inspector)中的名字和該屬性的類型。等號后邊跟的是默認值。

Paste_Image.png

5.1 Properties屬性相關代碼列舉

Properties { Property [Property ...] }
定義屬性塊,其中可包含多個屬性,其定義如下:

name ("display name", Range (min, max)) =number
定義浮點數屬性,在檢視器中可通過一個標注最大最小值的滑條來修改。

name ("display name", Color) =(number,number,number,number)
定義顏色屬性

name ("display name", 2D) = "name" {options }
定義2D紋理屬性

name ("display name", Rect) = "name"{ options }
定義長方形(非2次方)紋理屬性

name ("display name", Cube) = "name"{ options }
定義立方貼圖紋理屬性

name ("display name", Float) = number
定義浮點數屬性

name ("display name", Vector) =(number,number,number,number)
定義一個四元素的容器(相當于Vector4)屬性

5.2 一些細節
包含在著色器中的每一個屬性通過name索引(在Unity中, 通常使用下劃線來開始一個著色器屬性的名字)。屬性會將display name顯示在材質檢視器中,還可以通過在等符號后為每個屬性提供缺省值。
對于Range和Float類型的屬性只能是單精度值。
對于Color和Vector類型的屬性將包含4個由括號圍住的數描述。
對于紋理(2D, Rect, Cube) 缺省值既可以是一個空字符串也可以是某個內置的缺省紋理:"white", "black", "gray" or"bump"
隨后在著色器中,屬性值通過[name]來訪問。

5.3 紋理屬性選項
name ("display name", 2D) ="name" { options }

包含在紋理屬性的大括號中的選項Options是可選的。可能的選項有如下:
TexGen紋理生成類型。即紋理的自動生成紋理坐標時的模式,可以是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的其中之一;這些模式和OpenGL紋理生成模式相對應。注意如果使用自定義頂點程序,那么紋理生成將被忽略。
LightmapMode 光照貼圖模式。如果我們給出這個選項,紋理將能被渲染器的光線貼圖屬性所影響。紋理不能被使用在材質中,而是取自渲染器的設定。這個我們以后會講到。

六、光照、材質與顏色
燈光和材質參數常常被用來控制內置的頂點光照。而Unity中的頂點光照也就是Direct3D/OpenGL標準的按每頂點計算的光照模型—— 光照打開時,光照受材質塊,顏色材質和平行高光命令的影響。

6.1 用于通道Pass中的代碼

這些代碼一般是寫在Pass{ }中的,細節如下:
Color Color
設定對象的純色。顏色即可以是括號中的四值(RGBA),也可以是被方框包圍的顏色屬性名。

Material { Material Block }
材質塊被用于定義對象的材質屬性。

Lighting On | Off
開啟光照,也就是定義材質塊中的設定是否有效。想要有效的話必須使用Lighting On命令開啟光照,而顏色則通過Color命令直接給出。

SeparateSpecular On | Off
開啟獨立鏡面反射。這個命令會添加高光光照到著色器通道的末尾,因此貼圖對高光沒有影響。只在光照開啟時有效。

ColorMaterial AmbientAndDiffuse | Emission
使用每頂點的顏色替代材質中的顏色集。AmbientAndDiffuse 替代材質的陰影光和漫反射值;Emission 替代 材質中的光發射值。

6.2 材質塊Material Block相關代碼
使用的地方是在SubShader中的一個Pass{ }中新開一個Material{ }塊,在這個Material{ }塊中進行這些語句的書寫。這些代碼包含了包含材質如何和光線產生作用的一些設置。這些屬性默認為值都被設定為黑色(也就是說不產生作用),一般情況下可以被忽略。

Diffuse Color(R,G,B,A)
漫反射顏色構成。這是對象的基本顏色。

Ambient Color(R,G,B,A)
環境色顏色構成.這是當對象被RenderSettings.中設定的環境色所照射時對象所表現的顏色。

Specular Color(R,G,B,A)
對象反射高光的顏色。(R,G,B,A)四個分量分別代表紅綠藍和Alpha,取值為0到1之間。

Shininess Number
加亮時的光澤度,在0和1之間。0的時候你會發現更大的高亮也看起來像漫反射光照,1的時候你會獲得一個細微的亮斑。

Emission Color
自發光顏色,也就是當不被任何光照所照到時,對象的顏色。(R,G,B,A)四個分量分別代表紅綠藍和Alpha,取值為0到1之間。

打在對象上的完整光照顏色最終是:
FinalColor=Ambient * RenderSettings ambientsetting + (Light Color * Diffuse + Light Color Specular) + Emission
最終顏色=環境光反射顏色
渲染設置環境設置 (燈光顏色漫反射顏色+燈光顏色*鏡面反射顏色)+自發光

ps:方程式的燈光部分(也就是帶括號的部分)對所有打在對象上的光線都是重復使用的。而我們在寫Shader的時候常常會將漫反射和環境光光保持一致(所有內置Unity著色器都是如此)

舉個栗子:

Shader "demo/Shader"
{
    //properties
    Properties
    {
        _Color ("主顏色", Color) = (2,2,1,0)
        _SpecColor ("高光顏色", Color) = (2,2,2,1)
        _Emission ("自發光顏色", Color) = (0,0,0,0)
        _Shininess ("光澤度", Range (0.01, 1)) = 0.7
        _MainTex ("基本紋理", 2D) = "white" {}
    }

    //subshader
    SubShader
    {
        //pass
        Pass
        {
            //material
            Material
            {
                //可調節的漫反射光和環境光反射顏色

                Diffuse [_Color]
                Ambient [_Color]
                //光澤度

                Shininess [_Shininess]
                //高光顏色

                Specular [_SpecColor]
                //自發光顏色

                Emission [_Emission]
            }
            //開啟光照

            Lighting On
            //開啟獨立鏡面反射

            SeparateSpecular On
            //設置紋理并進行紋理混合

            SetTexture [_MainTex]
            {
                Combine texture * primary DOUBLE, texture * primary
            }
        }
    }
}

產物如下

Paste_Image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容