Shader編程學習筆記(七)—— Surface Shader 1


Surface Shader

  本小結對Unity的Surface Shader做一個大概的了解。主要了解在Surface Shader當中比較重要的幾個部分,分別是:

  • SurfaceOutput
  • Input
  • lighing
  • shadow

  首先查看一下Unity的官方手冊中的Writing Surface Shaders,其中描述道:如果要編寫一個shader去和光進行交互是比較復雜的,因為光照會有不同的光照類型,不同的陰影選項和不同的渲染路徑(包括foward和deferred rendering等),因此shader需要找到處理這些復雜事物的方法。

  在使用Surface Shader時,它可以自動生成一些代碼,比直接去使用低階的頂點和像素着色器來說要容易許多。但是需要注意的是Surface Shader並不是一種定制的語言,也不是一種神奇的東西,它只不過自動生成了以前必須去手寫的代碼。Surface Shader還是使用Cg或HLSL語言編寫。在前面課程當中,已經初步解到,Surface Shader實際上就是對頂點和像素着色器的一種包裝,它讓我們不用去關注更多的頂點和片段程序的細節,能夠快速地得到想要的着色器。接下來試着編寫一些Surface Shader程序。

  創建一個默認的Surface Shader,如下:

 1 Shader "Lesson/SurfaceShader1" {
 2     Properties {
 3         _Color ("Color", Color) = (1,1,1,1)
 4         _MainTex ("Albedo (RGB)", 2D) = "white" {}
 5         _Glossiness ("Smoothness", Range(0,1)) = 0.5
 6         _Metallic ("Metallic", Range(0,1)) = 0.0
 7     }
 8     SubShader {
 9         Tags { "RenderType"="Opaque" }
10         LOD 200
11 
12         CGPROGRAM
13         // Physically based Standard lighting model, and enable shadows on all light types
14         #pragma surface surf Standard fullforwardshadows
15 
16         // Use shader model 3.0 target, to get nicer looking lighting
17         #pragma target 3.0
18 
19         sampler2D _MainTex;
20 
21         struct Input {
22             float2 uv_MainTex;
23         };
24 
25         half _Glossiness;
26         half _Metallic;
27         fixed4 _Color;
28 
29         void surf (Input IN, inout SurfaceOutputStandard o) {
30             // Albedo comes from a texture tinted by color
31             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
32             o.Albedo = c.rgb;
33             // Metallic and smoothness come from slider variables
34             o.Metallic = _Metallic;
35             o.Smoothness = _Glossiness;
36             o.Alpha = c.a;
37         }
38         ENDCG
39     }
40     FallBack "Diffuse"
41 }
View Code

  首先來了解一下這個Shader結構。這個Shader在Properties中有四個屬性:

  • _Color為顏色值。
  • _MainTex是主紋理。
  • _Glossiness是一個浮點值,用於計算高光的光澤度。
  • _Metallic也是一個浮點值,用於計算表現金屬的光澤度。 

  該shader有一個SubShader,但是,在這個SubShader中並沒有Pass通道。這里需要注意的是,在Surface Shader當中不需要去編寫Pass通道,原因是Surface Shader就是對Vertex & Fragment Shader的一種包裝,它能夠在自動生成着色器代碼,生成的過程不需要我們干預,Pass通道也能自動生成,因此,如果添加了Pass通道,就會出現編譯錯誤。最后,作為ShaderLab的基本結構,該默認的Surface Shader擁有一個FallBack,如果shader中的某一種特性不能夠被使用,那么會回滾到Diffuse。

  接下來重點了解一下SubShader擁有哪些內容。其中“Tags { "RenderType"="Opaque" }”描述的是渲染類型,“Opaque”表示不透明的物體;“LOD 200”是指層級細節;“CGPROGRAM”到“ENDCG”是一個代碼塊,表示其中使用Cg語法,要真正地學會Surface Shader編程,有必要先學會Cg語言,不過現在可以簡單地從Surface Shader的結構出發,基本了解一下Surface Shader的內容。

  首先“#pragma surface surf Standard fullforwardshadows”是Surface Shader當中比較重要的一部分。“pragma”是一個編譯指令,這個編譯指令有具體的格式,可以從Unity官方手冊中了解一下有關的內容,其格式為:“#pragma surface surfaceFunction lightModel [optionalparams]”。

  • 以“#”開頭,“surface”關鍵詞表示該shader以Surface Shader格式來編寫,Unity引擎在處理這個shader結構的時候,就會自動地進行編譯低階的代碼。
  • “surfaceFunction”是指surface的函數,在一定條件下可以隨便取名,在默認創建的Surface Shader中的"surf"就是函數名,下面也有對應的函數體。
  • “lightModel”描述的是光照模型,在默認創建的Surface Shader中使用的是“Standard”,那么這個光照模型實際上也是一個函數,我們可以在Unity(5.0以上)的安裝目錄上找到一個光照的代碼文件"UnityPBSLighting.cginc",其中的函數“LightingStandard”,其中“Lighting”后的名稱是我們真正使用的函數名。
  • “[optionalparams]”表示其他的一些選項,默認Surface Shader使用的是“fullforwardshadows”,從字面上理解是關於陰影的一些功能,查看Unity手冊可以了解到默認使用的“fullforwardshadows”表示它能夠在Forward渲染路徑下支持所有的陰影類型,默認的shader僅僅能支持一個方向光的陰影,如要在Forward渲染路徑下使用點光源或聚光燈產生的陰影就需要使用該指令。這里需要注意的是,在其上還有一個“addshadow”指令,它的主要功能就是生成一個陰影投射器,在現目前的代碼當中也可以直接使用“addshadow”。

  接下來在工程中實際使用一下這個shader。

  創建一個材質並使用該shader,然后在場景中創建一個Cube當做地面,在其上創建一個Sphere,並使用我們創建的材質,可以看到球體的檢視面板中已經擁有了shder當中編寫的四個屬性:“Color”是顏色,默認為白色;“Albedo (RGB)”是主紋理,這里先拖放一張貼圖;“Smoothness”是平滑度,描述的是高光的強度;“Metallic”表示的是金屬質感,調整這個系數可以修改金屬質感的強度金屬質感原理就是如果光照射非常光滑的金屬物體,有鏡面反射的部分光會很集中,形成高亮,沒有鏡面反射的地方就會很暗淡。效果如圖:

  以上就是對該shader的基本使用。

  接下來在該shader中,“#pragma target 3.0”表示我們將要對這個着色器使用硬件的“shader model 3.0”的能力,硬件的“shader model”是硬件一個用於着色處理的基礎的指令范圍和能力,值越高表示能使用越高級的功能,如果沒有使用“#pragma target 3.0”這句指令,默認使用的是“shader model 2.0”。

  “sampler2D”是一個二維紋理,這里表示該shader的主紋理參數。

 struct Input {
   float2 uv_MainTex;
 };

  之后的Input結構體,用於描述紋理的uv坐標,查看Unity文檔,在"Surface Shader input structure"目錄中,關於這個紋理坐標,必須以“uv”或“uv2”開頭,使用“uv”表示用第一套uv坐標集合,用“uv2”表示第二套uv坐標集合。因此,如果在Properties中使用類似"_MainTex"紋理屬性,就需要在SubShader中的一個輸入結構體當中必須以“uv”開頭的變量,否則就得不到該紋理采樣值。

  除了Input結構體之外,在CGPROGRAM要對Properties中的屬性做對應的聲明。兩者的類型不一樣,“2D”對應“sampler2D”,“Range”對應“half”,“Color”對應“fixed4”。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM