上面三種Shader在unity中都能夠使用一種ShaderLab 的語法來進行編寫Shader。基本的ShaderLab的基本結構如下
Shader “ name” =
{
[Properties]
[SubShader]
[FallBack]
}
Properties : 屬性,他定義了一些引用變量,可以在 Unity簡視面板上進行查看,設置。
SubShader :一個shader可以有多個Subshader,在執行的時候,只會執行一個圖形硬件支持的SubShader,判斷順序從第一種以此往後邊進行怕斷,判斷到哪一個subshader當前能夠執行,就執行那一個。
FallBack:當上述所有的SubShader圖形硬件都不能夠執行的話就會執行FallBack。
2.Unity官方自帶的Shader類型流程圖
3.FiexdFunction shader 片段,主要的命令及其規則
4,來奉上FixedFunction Shader 的代碼片段
Properties{
_Color("Main Color",color) = (1,1,1,1) //漫反射的顏色
_Ambient("Ambient Color",color) = (0.3,0.3,0.3,0.3)
_Specuar("Specular Color",color) = (1,1,1,1) //高光的強度
_Shininess("Shininess",Range(0,8)) = 4 //高光的強度
_Emission("Emission",color) = (1,0,0,1) // 自發光的顏色
_MainTexture("Main Texture",2D) = "white"{}
_SecondTexture("Main Texture",2D) = "white"{}
_Constant("ConstantColor",color) = (1,1,1,1)
}
Subshader{
Tags { "Queue" = "Transparent" }
pass{
//進行混合渲染
Blend SrcAlpha OneMinusDstColor
material
{
diffuse[_Color]
ambient[_Ambient]
specular[_Specuar]
shininess[_Shininess]
emission[_Emission]
}
lighting on
separatespecular on
settexture[_MainTexture]
{
combine texture * primary double //混合之前的顏色
}
// primary 總是當前紋理 和頂點光照後的顏色進行混合
// previous 當前的紋路 和之前所以的紋理 和定點顏色進行混合
settexture[_SecondTexture]
{
constantcolor [_Constant]
combine texture * previous double ,texture * constant //混合之前的顏色 後面加 texture 只是通過貼圖的alpha 來作爲 透明通道
}
}
}
}
關鍵點的函數
基於alpha測試階段的流程
4,SurfaceShader,他實際上是對VertexShader 和fragment Shader的一種包裝,他其實目的是不讓我們更多的來關注實現的細節,但是我就是喜歡知道各種實現的細節,知道其原理。Surface Shader 沒有Pass通道,他能夠幫我自動生成底層能夠執行的代碼,也包括他能夠幫我們生成底層的pass通道。他的基本的結果如下
Shader “menu/name”{
Propertyes{ }
Subshader{
Tags {}
LOD xx
CGPROGRAM
#pragma xx
//主內容
ENDCG
}
FallBack "Diffuse"
}
Pragma:編譯指令,例如如下代碼
#pragma surface surf Standard fullforwardshadows
surface 是指定義了一個方法叫做surf,surf這個方法是你在下邊自己定義的,用來進行fragment各種計算的Standrad爲光照模型,起具體的請參考,UnityPBSLighting.cginc文件裏面的如下函數
inline half4 LightingStandard (SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
{
s.Normal = normalize(s.Normal);
half oneMinusReflectivity;
half3 specColor;
s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);
// shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
// this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha
half outputAlpha;
s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);
half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
c.rgb += UNITY_BRDF_GI (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi);
c.a = outputAlpha;
return c;
}
fullforwardshadows 描述的是一些其它的選項 這裏指的是陰影選項,具體的請去參考unity官方文檔。具體的surfaceShader代碼如下
Shader "ShaderDemo/SurfaceShader" {
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" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard removeshadow
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
}
需要注意的是紋理採樣的時候必須要以uv小寫開頭的名稱,如 uv_MainTex,否則紋理採樣將不成功。我們來看surf函數,這個函數是無返回的,說明他並不是以返回值的形勢來輸出的,Input 目前最重要是他能夠包裝我們的紋理值。第二個參數爲 inout, 他代表這個參數即是輸入又是輸入,默認的是輸入類型,SurfaceOutputStandard請參考unity3D文檔,例如早起的版本SurfaceOutput
struct SurfaceOutput
{
fixed3 Albedo; // diffuse color
fixed3 Normal; // tangent space normal, if written
fixed3 Emission;
half Specular; // specular power in 0..1 range
fixed Gloss; // specular intensity
fixed Alpha; // alpha for transparencies
};
早起版本沒有基於Standard物理光照只有基於Lambert光照模型,他的原型如下
inline fixed4 LightingLambert (SurfaceOutput s, UnityGI gi)
{
fixed4 c;
c = UnityLambertLight (s, gi.light);
#if defined(DIRLIGHTMAP_SEPARATE)
#ifdef LIGHTMAP_ON
c += UnityLambertLight (s, gi.light2);
#endif
#ifdef DYNAMICLIGHTMAP_ON
c += UnityLambertLight (s, gi.light3);
#endif
#endif
#ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT
c.rgb += s.Albedo * gi.indirect.diffuse;
#endif
return c;
}
基於Lambert的渲染模型Shader如下
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue" = "Transparent"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert addshadow
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
void surf (Input IN, inout SurfaceOutput o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.g;
}
ENDCG
}
// FallBack "Diffuse"
}
需要注意的是,設置物體透明的時候不能給用Blend,因爲他沒有pass通道,我們直接可以在pragma 編譯指令後面來設置alpha通道,具體的參數可以參考unity3d文檔如下
基於fragment vertex shader的基本結構如下
Shader "ShaderDemo/VertexFragmentShader" {
SubShader{
pass
{
CGPROGRAM
#pragma vertex vertexMain
#pragma fragment fragMain
void vertexMain(in float2 objects : POSITION,out float4 pos:POSITION,out fixed4 col:COLOR)
{
pos = float4(objects,0,1);
col = pos;
}
void fragMain( inout float4 col:COLOR)
{
}
ENDCG
}
}
}