Unity Shader 學習之旅

Unity Shader 學習之旅

紙上學來終覺淺,絕知此事要躬行

美麗的夢和美麗的詩同樣 都是可遇而不可求的——席慕蓉html

1、渲染流水線

 

示例圖
示例圖

enter description here

 

Tips:什麼是 GPU 加速計算?
編程

1.1Draw Call

CPU過Draw Call來g告訴GPU開始一個渲染過程。一個Draw Call會指向本次調用須要渲染的圖元列表。
通俗的講咱們能夠把CPU理解成一羣專家,他們有着超強和快速的計算能力,能解決各類各樣的問題。GPU則是許許多多個流水線上的工人,儘管它們只能作簡易單一的任務,可是成千上萬個工人一塊兒開動能夠迅速處理大量的工做。可是專家和這些工人協同工做的過程當中須要交接任務,此時交接的過程就是Draw Call調用的過程。專家告訴工人們這些東西大家須要把這些零件加工成什麼樣,交接溝通是須要代價,這也就是爲何Draw Call過多會影響幀率。瑣碎的零部件一點點的交接給工人是很浪費資源的,工人成千上萬個對於100個零部件加工和一萬個零部件加工耗費的代價是同樣的,這樣專家也忙不過來,這時專家忙的焦頭爛額,工人還在等待下一批零部件,零部件組裝成成品的過程就出現了卡頓。因此Draw Call優化的過程也就是儘量一次由專家給工人一大批須要統一操做組裝的零件(合併網格),和減小這些零件的類型(避免過多材質,儘量多的公用材質)。數組

2、最簡單的頂點片元着色器

2.1.頂點片元着色器基本結構

Unity Shader基本結構:Shader ,Properties,SubShder,Fallback等。數據結構

2.1.1結構

  1.  
  2. Shader "ShaderName"{ 
  3. Properties{ 
  4. //屬性,暴露在inspector面板上 
  5.  
  6. SubShader{ 
  7. //針對顯卡A的SubShader 
  8. Pass{ 
  9. //設置渲染狀態和標籤 
  10.  
  11. CGPROGRAM 
  12. //該代碼的編譯指令,如: 
  13. #pragma vertex vert 
  14. #pragma fragment frag 
  15.  
  16. //CG代碼 
  17.  
  18.  
  19. ENDCG 
  20. //其餘設置 
  21.  
  22. SubShader{ 
  23. //針對顯卡B的SubShader 
  24.  
  25. //上述SubShader都失敗後調用回調的Unity Shader 
  26. Fallback "VertexLit" 

2.1.2一個簡單的示例

  1. Shader "UnityShaderBoook/SimplerShader"{ 
  2.  
  3. //Properties並不是必須,此shader中不聲明任何材質屬性 
  4. SubShader{ 
  5.  
  6. Pass{  
  7.  
  8. CGPROGRAM 
  9. //編譯命令,指定頂點/片元着色器處理函數 
  10. #pragma vertex vert 
  11. #pragma fragment frag 
  12.  
  13. //頂點着色器代碼,逐個頂點執行 
  14. //使用POSITION語義指定函數的輸入參數v爲頂點的位置信息 
  15. //SV_POSITION語義指明函數的返回值爲頂點着色器輸出的是裁剪空間中的位置 
  16. //UnityObjectToClipPos則是Unity內置的模型-觀察-投影矩陣,幫咱們完成操做(mul(UNITY_MATRIX_MVP,*)' 現已更新爲'UnityObjectToClipPos(*)') 
  17. float4 vert(float4 v:POSITION):SV_POSITION{ 
  18. return UnityObjectToClipPos(v); 
  19.  
  20. //片元着色器,逐個面片執行 
  21. //此片元着色器沒有任何輸入參數 
  22. //SV_TARGET語義指定函數輸出顏色存儲一個渲染目標上 
  23. //這裏僅僅簡單的返回表示白色的fixed4的變量 
  24. fixed4 frag():SV_TARGET{ 
  25. return fixed4(1.0,1.0,1.0,1.0); 
  26.  
  27. ENDCG 
  28.  
  29.  

當咱們把使用該shader的材質賦給場景物體時,物體僅僅表現出單純的白色。咱們在shader中沒有賦予它更豐富的內容,如法線,紋理等,因此他不會表現出任何深度,陰影等,固然也不會受到光照的影響。app

注意:編程語言

  1. POSITIONSV_POSITION都是CG/HLSL中的語義,他們是不可省略的,這些語義用來告訴系統輸入值和輸出值的含義。POSTION告訴Unity這裏將模型的頂點數據傳入到v參數,而SV_POSITION則告訴Unity頂點着色器輸出的是裁剪空間中的頂點座標。
  2. UnityObjectToClipPos(v) 是mul(UNITY_MATRIX_MVP,v)更新後的函數,他是Unity內置函數,用來幫咱們進行頂點座標從模型空間轉換到裁剪空間的轉換。
  3. SV_TARGETHLSL中的系統語義,它輸出的是一個float4類型的變量,它等同於告訴渲染器,把用戶的輸出顏色存儲到一個渲染目標中,有時也使用COLOR代替,考慮到平臺的通用性最好使用SV_TARGET
  4. 模型空間:模型空間咱們能夠理解爲模型自身的局部座標,一個模型上的頂點位置信息,都是依託自身的局部座標的,但當咱們把它放到場景中的時候,就須要咱們轉換這些信息來使用。
  5. 裁剪空間:能夠簡單的理解爲Unity中攝像機視椎體包圍的空間,不在其空間內的信息將會被剔除,保留的信息後續會被投影到屏幕上被看到。

2.2.頂點着色器與片元着色器之間通訊

片元着色器是沒法直接獲取陳模型的頂點信息的,這時就須要咱們經過使用結構體做爲媒介,有頂點着色器向片元着色器傳遞一些數據,如:模型法線,紋理座標等。ide

2.2.1示例

  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 
  2.  
  3. Shader "UnityShaderBoook/vert2frag"{ 
  4. Properties { 
  5. _Color ("Color Tint", Color) = (1, 1, 1, 1
  6. //Properties並不是必須,此shader中不聲明任何材質屬性 
  7. SubShader{ 
  8.  
  9.  
  10. Pass{  
  11.  
  12. CGPROGRAM 
  13. //編譯命令,指定頂點/片元着色器處理函數 
  14. #pragma vertex vert 
  15. #pragma fragment frag 
  16.  
  17. uniform fixed4 _Color; 
  18. //結構體用於指定向頂點着色器傳遞的信息 
  19. struct a2v{ 
  20. float4 vertex:POSITION;//模型的頂點座標 
  21. float4 normal:NORMAL;//模型的法線信息 
  22. float4 texcoord:TEXCOORD0;//模型的第一套紋理 
  23. }; 
  24.  
  25. //結構體指定了頂點着色器向片元着色器傳出的信息 
  26. struct v2f{ 
  27. float4 pos:SV_POSITION;//裁剪空間中的座標信息 
  28. fixed3 color:COLOR0;//COLOR0語義可用來存儲顏色信息 
  29. }; 
  30.  
  31. v2f vert(a2v v) { 
  32. v2f o; 
  33. o.pos = UnityObjectToClipPos(v.vertex); 
  34. o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5); 
  35. return o; 
  36.  
  37.  
  38. //接收傳入的信息 
  39. fixed4 frag(v2f i):SV_TARGET{ 
  40. fixed3 c = i.color; 
  41. c *= _Color.rgb; 
  42. return fixed4(c, 1.0); 
  43.  
  44. ENDCG 
  45.  
  46.  

注意: 頂點着色器是逐個頂點調用的,片元着色器是逐片元調用的。片元着色器中的輸入實際是吧頂點着色器的輸出插值後獲得的結果。函數

2.3.Unity內置文件及變量

2.3.1 名詞解釋

ShaderLab是unity本身封裝調用CG/HLSL/GLSL的接口。能夠理解爲C#與C,一個方便咱們使用,一個更加接近底層。
語義是CG/HLSL這些底層提供的用於限定參數含義的字符串。而unity爲了方便的對模型的數據進行傳輸,對一些語義進行了特別規定。如:頂點着色器中用TEXCOORD0來描述texcoord,unity會自動識別出TEXCOORD0的語義,並把模型的第一套紋理座標信息填充到texcoord中。學習

2.3.2 Unity支持的經常使用語義

從應用階段傳遞模型數據到頂點着色器優化

語義 描述
POSITION 模型空間中的頂點位置,一般是float4類型
NORMAL 頂點法線,一般是float3類型
TANGENT 頂點切線,一般是float4類型
TEXCOORDn 如TEXCOORD0、TEXCOORD1該頂點的紋理座標,TEXCOORD0表示第一組紋理座標,依此類推,一般是float2或float4類型
COLOR 頂點顏色,一般是fixed4或float4類型

注意:
其中TEXCOORDn中n的數目是和Shader Model有關的,例如通常在Shader Model 2(即Unity默認編譯到的Shader Model版本)和Shader Model 3中,n等於8,而在Shader Model 4和Shader Mode 5中,n等於16。一般狀況下,一個模型的紋理座標組數通常不超過2,即咱們每每只使用TEXCOORD0和TEXCOORD1。在Unity內置的數據結構體appdata_full中,它最多使用了6個座標紋理組。
從頂點着色器傳遞數據給片元着色器

語義 描述
SV_POSITION 裁剪空間中的頂點座標,結構體中必須包含一個用該語義修飾的變量。等同於DirectX9中的POSITION,但最好使用SV_POSITION
COLOR0 一般用於輸出第一組頂點顏色,但不是必須的
COLOR1 一般用於輸出第二組頂點顏色,但不是必須的
TEXCOORD0~TEXCOORD7 一般用於輸出紋理座標,但不是必須的

注意
上面的語義中,除了SV_POSITION是有特別含義外,其餘語義對變量的含義沒有明確要求,也就是說,咱們能夠存儲任意值到這些語義描述變量中。一般,若是咱們須要把一些自定義的數據從頂點着色器傳遞給片元着色器,通常選用TEXCOORD0等。
從片元着色器輸出時Unity支持的語義

語義 描述
SV_Target 輸出值將會存儲到渲染目標(render target)中。等同於DirectX9中的COLOR語義,但最好使用SV_Target

注意
一個語義可使用的寄存器只能處理4個浮點值(float)。所以咱們想要定義矩陣類型,如float3×4,float4×4等變量是就須要使用更多的空間。一種方法是,把這些變量拆分紅多個變量,例如對於float4×4的矩陣類型,咱們能夠拆分紅四個float類型的變量,每一個變量存儲矩陣中的一行數據。

3、Unity中三種shader類型

3.1固定管線着色器

3.1.1簡介

固定功能着色器爲固定功能渲染管線的具體表現。實現較爲簡單,可是功能單一,效果較差。Unity5.2及之後備拋棄,全部的固定管線着色器都會別Unity編譯成對應的頂點片元着色器。

3.1.2效果

 

固定功能
固定功能

 

3.1.3示例代碼

  1. Shader "ShaderCookbook/固定功能着色器" 
  2. //-------------------[屬性]-------------------------- 
  3. Properties 
  4. _Color("主顏色",Color)=(1,1,1,0
  5. _SpecColor("高光顏色",Color)=(1,1,1,1
  6. _Emission("自發光顏色",Color)=(0,0,0,0
  7. _Shininess("光澤度",Range(0.01,1))=0.7 
  8. _MainTex("基本紋理",2D)="white"{} 
  9. _SecTex("副紋理",2D)="white"{} 
  10. //------------------[子着色器]----------------------- 
  11. SubShader 
  12. Tags{"Queue"="Transparent"} 
  13. //-------------------[通道]-------------------------- 
  14. Pass 
  15. Blend SrcAlpha OneMinusSrcAlpha 
  16. //-------------------[材質]-------------------------- 
  17. Material 
  18. //漫反射光 
  19. Diffuse[_Color] 
  20. //環境光 
  21. Ambient[_Color] 
  22. //光澤度 
  23. Shininess[_Shininess] 
  24. //高光顏色 
  25. Specular[_SpecColor] 
  26. //自發光暗色 
  27. Emission[_Emission] 
  28.  
  29. //開啓光照 
  30. Lighting On 
  31. //開啓獨立鏡面反射 
  32. SeparateSpecular On 
  33. //設置紋理並進行紋理混合 
  34. SetTexture[_MainTex] 
  35. Combine texture* primary DOUBLE,texture * primary 
  36.  
  37. SetTexture[_SecTex]{ 
  38. Combine texture * previous double,texture * previous 

3.2表面着色器

表面着色器介紹

3.2.1簡介

Unity包裝過一層的着色器類型,須要較少的代碼量就能達到很好的效果,但因爲Unity背後會作不少工做,渲染的代價比較大。

3.2.2效果

 

表面着色器
表面着色器

 

3.2.1示例代碼

  1. Shader "ShaderCookbook/簡單表面着色器" 
  2. //-------------------------------【屬性】-----------------------------------------  
  3. Properties 
  4. {  
  5. _MainTex ("【紋理】Texture", 2D) = "white" {}  
  6. _BumpMap ("【凹凸紋理】Bumpmap", 2D) = "bump" {}  
  7. _RimColor ("【邊緣顏色】Rim Color", Color) = (0.17,0.36,0.81,0.0)  
  8. _RimPower ("【邊緣顏色強度】Rim Power", Range(0.6,9.0)) = 1.0 
  9. }  
  10. //----------------------------【開始一個子着色器】---------------------------  
  11. SubShader 
  12. {  
  13. //渲染類型爲Opaque,不透明  
  14. Tags { "RenderType" = "Opaque"}  
  15. Blend SrcAlpha OneMinusSrcAlpha 
  16. //-------------------開始CG着色器編程語言段-----------------  
  17. CGPROGRAM 
  18. //使用蘭伯特光照模式  
  19. #pragma surface surf Lambert  
  20. //輸入結構  
  21. struct Input 
  22. {  
  23. float2 uv_MainTex;//紋理貼圖  
  24. float2 uv_BumpMap;//法線貼圖  
  25. float3 viewDir;//觀察方向  
  26. };  
  27. //變量聲明  
  28. sampler2D _MainTex;//主紋理  
  29. sampler2D _BumpMap;//凹凸紋理  
  30. float4 _RimColor;//邊緣顏色  
  31. float _RimPower;//邊緣顏色強度  
  32. //表面着色函數的編寫  
  33. void surf (Input IN, inout SurfaceOutput o)  
  34. {  
  35. //表面反射顏色爲紋理顏色  
  36. o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  37. //表面法線爲凹凸紋理的顏色  
  38. o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
  39. //邊緣顏色  
  40. half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  
  41. //邊緣顏色強度  
  42. o.Emission = _RimColor.rgb * pow (rim, _RimPower);  
  43. }  
  44. //-------------------結束CG着色器編程語言段------------------  
  45. ENDCG 
  46. }  
  47. //普通漫反射  
  48. Fallback "Diffuse" 
  49.  

3.3頂點片元着色器

3.3.1 簡介

更爲複雜,但也更爲靈活,能夠完成不少複雜的效果,可是須要咱們控制渲染的實現細節。

3.3.2效果

 

頂點片元着色器
頂點片元着色器

 

3.3.3示例代碼:

  1. shader "ShaderCookbook/簡單頂點片元着色器"{ 
  2.  
  3. //-------------------------------【屬性】-------------------------------------- 
  4. Properties 
  5. _Color ("Color", Color) = (1.0,1.0,1.0,1.0
  6. _MainTex("MainTex",2D)="white"{} 
  7. _SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0
  8. _Shininess ("Shininess", Float) = 10 
  9. //--------------------------------【子着色器】-------------------------------- 
  10. SubShader 
  11. //-----------子着色器標籤---------- 
  12. Tags { "LightMode" = "ForwardBase" } 
  13. //----------------通道--------------- 
  14. Pass 
  15. //-------------------開始CG着色器編程語言段-----------------  
  16. CGPROGRAM 
  17. #pragma vertex vert 
  18. #pragma fragment frag 
  19. #include "UnityCG.cginc" 
  20. //---------------聲明變量-------------- 
  21. float4 _Color; 
  22. sampler2D _MainTex; 
  23. float4 _MainTex_ST; 
  24. float4 _SpecColor; 
  25. float _Shininess; 
  26. //--------------定義變量-------------- 
  27. float4 _LightColor0; 
  28. //--------------頂點輸入結構體------------- 
  29. struct vertexInput  
  30. float4 vertex : POSITION; 
  31. float3 normal : NORMAL; 
  32. float4 texcoord : TEXCOORD0; 
  33. }; 
  34. //--------------頂點輸出結構體------------- 
  35. struct vertexOutput  
  36. float4 pos : SV_POSITION; 
  37. float4 col : COLOR; 
  38. float2 uv :TEXCOORD0; 
  39. }; 
  40. //--------------頂點函數-------------- 
  41. vertexOutput vert(vertexInput v) 
  42. vertexOutput o; 
  43. //獲取紋理信息 
  44. o.uv= v.texcoord * _MainTex_ST.xy + _MainTex_ST.zw;; 
  45.  
  46. //一些方向 
  47. float3 normalDirection = normalize( mul( float4(v.normal, 0.0), unity_WorldToObject ).xyz ); 
  48. float3 viewDirection = normalize( float3( float4( _WorldSpaceCameraPos.xyz, 1.0) - mul(unity_ObjectToWorld, v.vertex).xyz ) ); 
  49. float3 lightDirection; 
  50. float atten = 1.0
  51. //光照 
  52. lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
  53. float3 diffuseReflection = atten * _LightColor0.xyz * max( 0.0, dot( normalDirection, lightDirection ) ); 
  54. float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb * max( 0.0, dot( normalDirection, lightDirection ) ) * pow( max( 0.0, dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess ); 
  55. float3 lightFinal = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT; 
  56. //計算結果 
  57. o.col = float4(lightFinal * _Color.rgb, 1.0);//顏色 
  58. o.pos = UnityObjectToClipPos(v.vertex);//位置 
  59. return o; 
  60. //--------------片斷函數--------------- 
  61. float4 frag(vertexOutput i) : COLOR 
  62. fixed4 tex = tex2D(_MainTex,i.uv); 
  63. i.col*=tex; 
  64. return i.col; 
  65. //-------------------結束CG着色器編程語言段------------------ 
  66. ENDCG 
  67. Fallback "Diffuse" 
  68.  

3.3.4 效果

在世界座標系中頂點座標超過限定值則不顯示,相似切面效果

 

切面
切面

 

3.3.5 示例代碼

  1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' 
  2.  
  3. Shader "ShaderCookbook/VertexWorldPos" { 
  4. //------------------------屬性-------------------------- 
  5. Properties { 
  6. _Color ("Color", Color) = (1,1,1,1
  7. _MainTex ("Albedo (RGB)", 2D) = "white" {} 
  8. _YLimit("YLimit", float)= 0.0 
  9.  
  10.  
  11. //------------------------子shader-------------------------- 
  12. SubShader { 
  13.  
  14. //開啓透明度混合 之一 設置渲染類型和序列 
  15. Tags { "RenderType"="AlphaTest" "IgnoreProjector"="True" "Queue"="Transparent"} 
  16.  
  17. Pass{ 
  18. Tags{"LightMode"="ForwardBase"} 
  19. //開啓透明度混合 之二 關閉深度寫入 
  20. ZWrite off 
  21. //開啓透明度混合 之三 設置混合參數 
  22. Blend SrcAlpha OneMinusSrcAlpha 
  23. //關閉剔除,顯示雙面 
  24. Cull off 
  25.  
  26. //------------------------開啓CG-------------------------- 
  27. CGPROGRAM 
  28. #pragma vertex vert 
  29. #pragma fragment frag 
  30.  
  31. sampler2D _MainTex; 
  32. float4 _MainTex_ST; 
  33. fixed4 _Color; 
  34. float _YLimit; 
  35.  
  36. struct a2v{ 
  37. float4 vertex:POSITION; 
  38. float4 texcoord:TEXCOORD0; 
  39. }; 
  40.  
  41. struct v2f{ 
  42. float4 pos:SV_POSITION; 
  43. float4 uv:TEXCOORD; 
  44. float3 worldPos:TEXCOORD1; 
  45. }; 
  46.  
  47. v2f vert(a2v i){ 
  48. v2f v; 
  49. v.pos=UnityObjectToClipPos(i.vertex); 
  50. v.uv.xy=i.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw; 
  51. //獲取頂點的世界座標 
  52. v.worldPos=mul(unity_ObjectToWorld,i.vertex); 
  53.  
  54. return v; 
  55.  
  56. fixed4 frag(v2f v):SV_TARGET{ 
  57. fixed4 Col=_Color*tex2D(_MainTex,v.uv.xy); 
  58. //丟棄的未符合的像素 
  59. if(v.worldPos.y>_YLimit) 
  60. discard
  61.  
  62. return Col; 
  63. //------------------------關閉CG-------------------------- 
  64. ENDCG 
  65.  
  66. //------------------------棄子-------------------------- 
  67. FallBack "Diffuse" 
  68.  

3.3.6 效果

這裏咱們再次使用頂點片元着色器造一個黑洞同樣的效果。物體靠近黑洞時會被黑洞吸引拉扯,逐漸縮成一點,在另外一端則會逐漸變大出現。

 

enter description here
BlankHole

 

3.3.7 示例代碼

  1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' 
  2.  
  3. Shader "ShaderCookbook/黑洞" { 
  4. //------------------------屬性-------------------------- 
  5. Properties { 
  6. _Color ("Color", Color) = (1,1,1,1
  7. _MainTex ("Albedo (RGB)", 2D) = "white" {} 
  8. _YLimit("YLimit", float)= 0.0 
  9. _Length("Length",float)=1 
  10.  
  11.  
  12. //------------------------子shader-------------------------- 
  13. SubShader { 
  14.  
  15.  
  16. Pass{ 
  17. Tags{"LightMode"="ForwardBase"} 
  18.  
  19. //------------------------開啓CG-------------------------- 
  20. CGPROGRAM 
  21. #pragma vertex vert 
  22. #pragma fragment frag 
  23.  
  24. sampler2D _MainTex; 
  25. float4 _MainTex_ST; 
  26. fixed4 _Color; 
  27. float _YLimit; 
  28. float _Length; 
  29.  
  30. struct a2v{ 
  31. float4 vertex:POSITION; 
  32. float4 texcoord:TEXCOORD0; 
  33. }; 
  34.  
  35. struct v2f{ 
  36. float4 pos:SV_POSITION; 
  37. float4 uv:TEXCOORD; 
  38. float3 worldPos:TEXCOORD1; 
  39. }; 
  40.  
  41. v2f vert(a2v i){ 
  42. v2f v; 
  43. //獲取模型頂點座標在世界座標下的位置 
  44. v.worldPos=mul(unity_ObjectToWorld,i.vertex); 
  45.  
  46. //若是其距離咱們設定的臨界值_YLimit小於_Length長度,咱們將會按比例縮放其X,Z軸的頂點位置 
  47. if(distance(v.worldPos.y,_YLimit)<_Length) 
  48. float s=(distance(v.worldPos.y,_YLimit)/_Length); 
  49. i.vertex.xz*=s; 
  50.  
  51. //將修改後的頂點座標轉換爲裁剪座標 
  52. v.pos=UnityObjectToClipPos(i.vertex); 
  53. //獲取圖形的UI 
  54. v.uv.xy=i.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw; 
  55. return v; 
  56.  
  57. fixed4 frag(v2f v):SV_TARGET{ 
  58. fixed4 Col=_Color*tex2D(_MainTex,v.uv.xy); 
  59. return Col; 
  60. //------------------------關閉CG-------------------------- 
  61. ENDCG 
  62.  
  63. //------------------------棄子-------------------------- 
  64. FallBack "Diffuse" 
  65.  

開簾頓覺春風暖 滿紙淋漓白雲聲——楊玉香

X Shader實例

X.1.1 熱度圖

X.1.1.1 效果

運行結果:

 

漸變顏色效果
漸變顏色效果

 

 

梯度顏色效果
梯度顏色效果

熱度圖紋理:

 

 

漸變ramp圖片
漸變ramp圖片

 

 

梯度顏色效果
梯度顏色效果

 

X.1.1.2 示例代碼

  1.  
  2. Shader "Ellioman/Heatmap" 
  3. //-----------------------屬性-------------------- 
  4. Properties 
  5. _HeatTex("Texture", 2D) = "white" {} 
  6.  
  7. //----------------------子shader----------------- 
  8. SubShader 
  9. //設置爲透明格式 
  10. Tags{ "Queue" = "Transparent" } 
  11.  
  12. //設置Blend類型 
  13. Blend SrcAlpha OneMinusSrcAlpha  
  14.  
  15. //----------------------通道---------------------- 
  16. Pass 
  17. //-------------------開始CG------------- 
  18. CGPROGRAM 
  19. #pragma vertex vert 
  20. #pragma fragment frag 
  21.  
  22.  
  23. struct vertInput 
  24. float4 pos : POSITION; 
  25. }; 
  26.  
  27. struct vertOutput 
  28. float4 pos : POSITION; 
  29. fixed3 worldPos : TEXCOORD1; 
  30. }; 
  31.  
  32. //自定義變量 
  33. uniform int _Points_Length = 0
  34.  
  35. //cg中只能聲明肯定長度的數組 
  36. uniform float3 _Points[100]; // (x, y, z) = 位置 
  37. uniform float2 _Properties[100]; // x = 半徑, y = 強度 
  38. sampler2D _HeatTex; 
  39.  
  40. vertOutput vert(vertInput input) 
  41. vertOutput o; 
  42. o.pos = UnityObjectToClipPos(input.pos); 
  43. o.worldPos = mul(unity_ObjectToWorld, input.pos).xyz; 
  44. return o; 
  45.  
  46. half4 frag(vertOutput output) : COLOR 
  47. half h = 0
  48. for (int i = 0; i < _Points_Length; i++) 
  49. // 計算每個分佈點位置與當前像素的距離 
  50. half di = distance(output.worldPos, _Points[i].xyz); 
  51.  
  52. half ri = _Properties[i].x; 
  53.  
  54. //拋棄超過半徑分佈點的影響,距離output.worldPos越近,其值越高 
  55. half hi = 1 - saturate(di / ri); 
  56. //疊加又分佈點位置_Points[i].xyz與output.worldPos之間的距離及x半徑和y強度值獲得的值 
  57. h += hi * _Properties[i].y; 
  58.  
  59.  
  60. h = saturate(h);//限定範圍至[0,1] 
  61.  
  62. //經過ramp圖,相似toonshader的方式得到階梯式的顏色效果 
  63. half4 col = tex2D(_HeatTex, fixed2(h, 0.5)); 
  64. return col; 
  65. //-------------------開始CG------------- 
  66. ENDCG 
  67. Fallback "Diffuse" 

X.1.1.3 分析

首先,咱們須要將ramp圖片的wrapMode格式設爲Clamp。
Texture.wrapMode 循環模式:

  1. TextureWrapMode.Clamp:設置紋理充滿拉伸使用
  2. TextureWrapMode.Repeat:紋理重複平鋪使用

若是採用Repeat,那麼等於U>=1的狀況就會用紋理圖在右邊在平鋪一張圖。

咱們使用了相似使用ramp紋理製做toon卡通風格shader效果的方式,來用uv中的u指得到顏色的強度。
uv
這裏在對blend混合命令作一個筆記:
Blend SrcAlpha OneMinusSrcAlpha // 傳統透明度
Blend One OneMinusSrcAlpha // 預乘透明度
Blend One One // 疊加
Blend OneMinusDstColor One // 柔和疊加
Blend DstColor Zero // 相乘——正片疊底

那海和天空之間星星消失的地方
連時間也沒有確切的命運——楊煉

X.1.2 山崖

X.1.2.1 效果

這裏主要實現了山崖上草地覆蓋面積,高度還有山石高光,平滑度,法線強度的控制。

X1.2.2 示例代碼

  1. Shader "Unlit/Cliff" 
  2. //---------------參數--------------------------- 
  3. Properties 
  4. _MainTex ("Texture", 2D) = "white" {} 
  5. _MainNormal("MainNormal",2D)="white"{} 
  6. _GrassTex ("GrassTex", 2D) = "white" {} 
  7. _GrassNormal ("GrassNormal", 2D) = "white" {} 
  8.  
  9. _Smooth("smooth",Range(0,1))=1 
  10. _Gloss("Gloss",Range(0,128))=96 
  11.  
  12. _Height("Height",float)=0.5 
  13.  
  14. _Offset("Offset",float)=0.5 
  15. _BumpScale("bumpscale",float)=0.5 
  16.  
  17. //-------------subshader--------------------------- 
  18. SubShader 
  19. Tags { "LightMode"="ForwardBase" } 
  20. LOD 100 
  21.  
  22. Pass 
  23. CGPROGRAM 
  24. #pragma vertex vert 
  25. #pragma fragment frag 
  26.  
  27. #include "UnityCG.cginc" 
  28. #include "Lighting.cginc" 
  29.  
  30.  
  31. //-----------傳遞數據用的結構體--------------------------- 
  32. struct appdata 
  33. float4 vertex : POSITION; 
  34. float4 uv : TEXCOORD0; 
  35. float3 normal:NORMAL; 
  36. float4 tangent:TANGENT; 
  37. }; 
  38.  
  39. struct v2f 
  40. float4 uv : TEXCOORD0; 
  41. float4 vertex : SV_POSITION; 
  42. float3 lightDir:TEXCOORD1; 
  43. float3 worldPos:TEXCOORD2; 
  44. float3 tanView:TEXCOORD3; 
  45. }; 
  46.  
  47. //----------傳遞參數數據--------------------------- 
  48. sampler2D _MainTex; 
  49. float4 _MainTex_ST; 
  50. sampler2D _GrassTex; 
  51. float4 _GrassTex_ST; 
  52. sampler2D _MainNormal; 
  53. sampler2D _GrassNormal; 
  54.  
  55. float _Offset; 
  56. float _BumpScale; 
  57. float _Height; 
  58. float _Gloss; 
  59. float _Smooth; 
  60.  
  61. v2f vert (appdata v) 
  62. v2f o; 
  63. o.vertex = UnityObjectToClipPos(v.vertex); 
  64. o.uv.xy = TRANSFORM_TEX(v.uv.xy, _MainTex); 
  65. o.uv.zw = TRANSFORM_TEX(v.uv.zw, _MainTex); 
  66.  
  67. //----------unity宏定義,用於獲得從模型空間矩陣到切線空間矩陣rotation----- 
  68. TANGENT_SPACE_ROTATION; 
  69.  
  70. //------------經過上一步獲得rotation用於將模型空間下的光照法線轉換到法線貼圖對應的空間中去,這裏的法線貼圖位於切線空間---- 
  71. o.worldPos=UnityObjectToWorldDir(v.vertex); 
  72. //------------須要藉助法線貼圖計算光照,這裏計算出須要用到符合法線貼圖空間的光照方向和視角方向 
  73. o.lightDir=normalize(mul(rotation,ObjSpaceLightDir(v.vertex)).xyz); 
  74. o.tanView=normalize(mul(rotation,ObjSpaceViewDir(v.vertex))); 
  75. return o; 
  76.  
  77. fixed4 frag (v2f i) : SV_Target 
  78. float3 halfDir=normalize(i.tanView+i.lightDir); 
  79.  
  80. fixed4 col = tex2D(_MainTex, i.uv.xy); 
  81. fixed4 grass=tex2D(_GrassTex,i.uv.zw); 
  82.  
  83. float3 colNormal=UnpackNormal(tex2D(_MainNormal,i.uv.xy))*_BumpScale; 
  84. float3 GrassNormal=UnpackNormal(tex2D(_GrassNormal,i.uv.zw))*_BumpScale; 
  85.  
  86. colNormal.z=sqrt(1.0-saturate(dot(colNormal.xy,colNormal.xy))); 
  87. GrassNormal.z=sqrt(1.0-saturate(dot(GrassNormal.xy,GrassNormal.xy))); 
  88.  
  89.  
  90. float angleY=1-saturate(dot(UnityObjectToWorldDir(colNormal),float3(0,1,0) )+_Offset); 
  91.  
  92. angleY-=i.worldPos.y>_Height?0:i.worldPos.y-_Height; 
  93.  
  94. fixed4 finalColor=lerp(grass,col,angleY); 
  95.  
  96. //---------------lambert光照--------------------------- 
  97. float3 diffuse=finalColor*max(0.0,dot(i.lightDir,colNormal))*_LightColor0.xyz; 
  98. //---------------Blin-phong光照--------------------------- 
  99. float3 specular= _LightColor0.rgb * pow(saturate(dot(halfDir, colNormal)), _Gloss)*_Smooth; 
  100.  
  101. return fixed4(diffuse+specular+UNITY_LIGHTMODEL_AMBIENT.xyz*finalColor,1); 
  102. ENDCG 
  103. }//end pass 
  104. }//end subshader 
  105.  
  106. Fallback "Diffuse"//陰影 
相關文章
相關標籤/搜索