在Unity5.x后, 已經支持了基於物理的光照模型,也就是常說的次時代引擎所必須具備的功能。
如果在Properties使用2D,CG里要用sampler2D,代表使用的是2維紋理 如果在Properties使用color, CG里要用fixed4 如果在Properties使用Range, CG里要用half,實際上描述的是一個float
struct Input 用於描述UV坐標的結構體。在 Input 中, 變量名必須是 uv_ 開始, 變量名必須是官方文檔中已經指定的名稱(也就是說不可以隨意設定)
CGPROGRAM ... ENDCG 代碼塊,表示從這一句下面開始直到EndCG,表示我們是使用了CG語言編寫的代碼
#pragma 編譯指令: #pargma 關鍵詞 函數名 光照模型 [其它選項]
函數名在cginc中,實際上會在前部加上 Lighting ,如 LightingStandard , 我們用的時候只取后部分 , 也就是 Standard
#pragma target 3.0 使用model 3.0 可以得到一個更好的光照效果, 默認是2.0
#pragma surface surf Standard fullforwardshadows 表示當前是一個 surface 着色器, 函數名是 surf, 使用 Standard 基於物理系統光照模式, 有一個完整的向前的陰影 (Standard 必須是Unity 5.x后才有)
#pragma surface surf Lambert addshadow 表示當前是一個 surfac 着色器, 函數名是 surf, 使用 Lambert 蘭伯特光照模型, addshadow 表示給物體添加一個陰影
示例代碼:
Shader "Sbin/sf" { 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 } // 在surfaceShader不需要有Pass通道,否則會報錯 SubShader { // 渲染類型,是一個不透明物體 //Tags { "RenderType"="Opaque" } Tags { "RenderType"="Opaque" "Queue" = "Transparent" } // 層級細節 LOD 200 // 代碼塊,表示從這一句下面開始直到EndCG,表示我們是使用了CG語言編寫的代碼 CGPROGRAM // #pragma 編譯指令 // 格式: // #pragma surface surfaceFunction lightModel [optionalparams] // #pargma 關鍵詞 函數名 光照模型 [其它選項] // Physically based Standard lighting model, and enable shadows on all light types //#pragma surface surf Standard fullforwardshadows //#pragma surface surf Lambert //#pragma surface surf Lambert alpha #pragma surface surf Lambert addshadow // 使用model 3.0 可以得到一個更好的光照效果, 默認是2.0 // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 // 如果在Properties使用2D,CG里要用sampler2D,代表使用的是2維紋理 // 如果在Properties使用color, CG里要用fixed4 // 如果在Properties使用Range, CG里要用half,實際上描述的是一個float sampler2D _MainTex; // 輸入結構體用於模述UV的坐標。 struct Input { // 變量必須是uv_開頭,_號后面的_MainTex自動對應Properties中的_MainTex和sampler2D // _MainTex 也是不能變的。 float2 uv_MainTex; }; // half _Glossiness; // half _Metallic; // fixed4 _Color; // in 參數是輸入的 // out 參數是輸出的 // inout 參數即是輸入,又是輸出 // SurfaceOutputStandard 可以使用基於物理的光照模型(次時代) //void surf (Input IN, inout SurfaceOutputStandard o) { void surf (Input IN, inout SurfaceOutput o) { // Albedo comes from a texture tinted by color // 從紋理中進行采樣 //fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; fixed4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; // 基本的漫反射 // Metallic and smoothness come from slider variables //o.Metallic = _Metallic; //o.Smoothness = _Glossiness; o.Alpha = c.a; // 透明度 } ENDCG } // FallBack 當我們的surfaceshader編譯后沒有一個陰影通道時,會自動添加一個陰影通道 //FallBack "Diffuse" }
在 SurfaceShader 中, 不可以有 Pass 通道, 否則會報錯。
以上內容只是筆記, 有錯誤請指正。
官方示例:
我們將開始用一個非常簡單的着色,並建立在。這里的一個着色,只設置表面顏色“白”。它使用內置的Lambert(擴散)照明模型。
Shader "Example/Diffuse Simple" { SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float4 color : COLOR; }; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = 1; } ENDCG } Fallback "Diffuse" }
Texture 使用紋理
An all-white object is quite boring, so let’s add a texture. We’ll add a Properties block to the shader, so we get a texture selector in our Material. Other changes are in bold below.
所有的白色物體都很無聊,所以讓我們添加一個紋理。我們將添加一個屬性塊到着色,所以我們得到一個紋理選擇器在我們的材料。其他變化是在大膽下面。
Shader "Example/Diffuse Texture" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; }; sampler2D _MainTex; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; } ENDCG } Fallback "Diffuse" }
Normal mapping 法線貼圖
Let’s add some normal mapping:
讓我們添加一些法線貼圖:
Shader "Example/Diffuse Bump" { Properties { _MainTex ("Texture", 2D) = "white" {} _BumpMap ("Bumpmap", 2D) = "bump" {} } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; float2 uv_BumpMap; }; sampler2D _MainTex; sampler2D _BumpMap; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); } ENDCG } Fallback "Diffuse" }
Rim Lighting 邊緣照明
Now, try to add some Rim Lighting to highlight the edges of an object. We’ll add some emissive light based on angle between surface normal and view direction. For that, we’ll use viewDir
built-in surface shader variable.
現在,嘗試添加一些邊緣照明,以突出對象的邊緣。我們將添加一些散射光基於表面法線和視圖方向的夾角。這樣,我們將使用viewdir內置表面着色器變量。
Shader "Example/Rim" { Properties { _MainTex ("Texture", 2D) = "white" {} _BumpMap ("Bumpmap", 2D) = "bump" {} _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0) _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0 } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; float2 uv_BumpMap; float3 viewDir; }; sampler2D _MainTex; sampler2D _BumpMap; float4 _RimColor; float _RimPower; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal)); o.Emission = _RimColor.rgb * pow (rim, _RimPower); } ENDCG } Fallback "Diffuse" }
更多資料參考 Unity 官方文檔: Unity/Editor/Data/Documentation/en/Manual/SL-SurfaceShaderExamples.html