小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

【淺墨Unity3D Shader編程】之九 深入理解Unity5中的Standard Shader...

 釋放_入微_成長 2016-09-22



標準著色器對應材質的編輯器外觀不同于一般的Shader,就是因為在Shader末尾書寫了如下的代碼: 

 

//使用特定的自定義編輯器UI界面CustomEditor 'StandardShaderGUI'


 

標準著色器對應材質的編輯器外觀如下:

 

 

 

一般的著色器對應材質的編輯器外觀如下:


 

 

 

 



二、Unity5標準著色器源代碼剖析之一:架構分析篇




上文已經提到過,標準著色器源代碼的剖析是一個小小的馬拉松,完全解析起來篇幅會很長,所以本系列文章將對剖析的過程進行連載,此節(jié)為連載的第一部分。

 

在這里先貼出經過淺墨詳細注釋的標準著色器標準版的源代碼,并對架構進行簡單的分析,而對每個通道的剖析在稍后的更新中會進行。

 

//-----------------------------------------------【Shader說明】---------------------------------------------------// Unity5.2.1 Built-in Standard Shader// 2015年10月 Commented by 淺墨 // 更多內容或交流,請訪問淺墨的博客:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------Shader 'Standard'{ //------------------------------------【屬性值】------------------------------------ Properties { //主顏色 _Color('Color', Color) = (1,1,1,1) //主紋理 _MainTex('Albedo', 2D) = 'white' {} //Alpha剔除值 _Cutoff('Alpha Cutoff', Range(0.0, 1.0)) = 0.5 //平滑、光澤度 _Glossiness('Smoothness', Range(0.0, 1.0)) = 0.5 //金屬性 [Gamma] _Metallic('Metallic', Range(0.0, 1.0)) = 0.0 //金屬光澤紋理圖 _MetallicGlossMap('Metallic', 2D) = 'white' {} //凹凸的尺度 _BumpScale('Scale', Float) = 1.0 //法線貼圖 _BumpMap('Normal Map', 2D) = 'bump' {} //高度縮放尺度 _Parallax ('Height Scale', Range (0.005, 0.08)) = 0.02 //高度紋理圖 _ParallaxMap ('Height Map', 2D) = 'black' {} //遮擋強度 _OcclusionStrength('Strength', Range(0.0, 1.0)) = 1.0 //遮擋紋理圖 _OcclusionMap('Occlusion', 2D) = 'white' {} //自發(fā)光顏色 _EmissionColor('Color', Color) = (0,0,0) //自發(fā)光紋理圖 _EmissionMap('Emission', 2D) = 'white' {} //細節(jié)掩膜圖 _DetailMask('Detail Mask', 2D) = 'white' {} //細節(jié)紋理圖 _DetailAlbedoMap('Detail Albedo x2', 2D) = 'grey' {} //細節(jié)法線貼圖尺度 _DetailNormalMapScale('Scale', Float) = 1.0 //細節(jié)法線貼圖 _DetailNormalMap('Normal Map', 2D) = 'bump' {} //二級紋理的UV設置 [Enum(UV0,0,UV1,1)] _UVSec ('UV Set for secondary textures', Float) = 0 //混合狀態(tài)的定義 [HideInInspector] _Mode ('__mode', Float) = 0.0 [HideInInspector] _SrcBlend ('__src', Float) = 1.0 [HideInInspector] _DstBlend ('__dst', Float) = 0.0 [HideInInspector] _ZWrite ('__zw', Float) = 1.0 } //===========開始CG著色器語言編寫模塊=========== CGINCLUDE //BRDF相關的一個宏 #define UNITY_SETUP_BRDF_INPUT MetallicSetup //===========結束CG著色器語言編寫模塊=========== ENDCG //------------------------------------【子著色器1】------------------------------------ // 此子著色器用于Shader Model 3.0 //---------------------------------------------------------------------------------------- SubShader { //渲染類型設置:不透明 Tags { 'RenderType'='Opaque' 'PerformanceChecks'='False' } //細節(jié)層次設為:300 LOD 300 //--------------------------------通道1------------------------------- // 正向基礎渲染通道(Base forward pass) // 處理方向光,自發(fā)光,光照貼圖等 ... Pass { //設置通道名稱 Name 'FORWARD' //于通道標簽中設置光照模型為ForwardBase,正向渲染基礎通道 Tags { 'LightMode' = 'ForwardBase' } //混合操作:源混合乘以目標混合 Blend [_SrcBlend] [_DstBlend] // 根據_ZWrite參數(shù),設置深度寫入模式開關與否 ZWrite [_ZWrite] //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 3.0 #pragma target 3.0 //編譯指令:不使用GLES渲染器編譯 #pragma exclude_renderers gles // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _NORMALMAP #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 #pragma shader_feature _PARALLAXMAP //--------著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎通道(用于正向渲染中,應用環(huán)境光照、主方向光照和頂點/球面調和光照)所需的所有變體。 //這些變體用于處理不同的光照貼圖類型、主要方向光源的陰影選項的開關與否 #pragma multi_compile_fwdbase //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertForwardBase #pragma fragment fragForwardBase //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } //--------------------------------通道2------------------------------- // 正向附加渲染通道(Additive forward pass) // 以每個光照一個通道的方式應用附加的逐像素光照 Pass { //設置通道名稱 Name 'FORWARD_DELTA' //于通道標簽中設置光照模型為ForwardAdd,正向渲染附加通道 Tags { 'LightMode' = 'ForwardAdd' } //混合操作:源混合乘以1 Blend [_SrcBlend] One //附加通道中的霧效應該為黑色 Fog { Color (0,0,0,0) } //關閉深度寫入模式 ZWrite Off //設置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 3.0 #pragma target 3.0 //編譯指令:不使用GLES渲染器編譯 #pragma exclude_renderers gles // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _NORMALMAP #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 #pragma shader_feature _PARALLAXMAP //--------使用Unity內置的著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎通道所需的所有變體,但同時為上述通道的處理賦予了光照實時陰影的能力。 #pragma multi_compile_fwdadd_fullshadows //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertForwardAdd #pragma fragment fragForwardAdd //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道3------------------------------- // 陰影渲染通道(Shadow Caster pass) // 將將物體的深度渲染到陰影貼圖或深度紋理中 Pass { //設置通道名稱 Name 'ShadowCaster' //于通道標簽中設置光照模型為ShadowCaster。 //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。 Tags { 'LightMode' = 'ShadowCaster' } //開啟深入寫入模式 ZWrite On //設置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 3.0 #pragma target 3.0 //編譯指令:不使用GLES渲染器編譯 #pragma exclude_renderers gles // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON //--------著色器編譯多樣化快捷指令------------ //進行陰影投射相關的多著色器變體的編譯 #pragma multi_compile_shadowcaster //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertShadowCaster #pragma fragment fragShadowCaster //包含輔助CG頭文件 #include 'UnityStandardShadow.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道4------------------------------- // 延遲渲染通道(Deferred Render Pass) Pass { //設置通道名稱 Name 'DEFERRED' //于通道標簽中設置光照模型為Deferred,延遲渲染通道 Tags { 'LightMode' = 'Deferred' } CGPROGRAM #pragma target 3.0 // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT #pragma exclude_renderers nomrt gles //---------編譯指令:著色器編譯多樣化(shader_feature)-------- #pragma shader_feature _NORMALMAP #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 #pragma shader_feature _PARALLAXMAP //---------編譯指令:著色器編譯多樣化(multi_compile)-------- #pragma multi_compile ___ UNITY_HDR_ON #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertDeferred #pragma fragment fragDeferred //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道5------------------------------- //元通道(Meta Pass) //為全局光照(GI),光照貼圖等技術提取相關參數(shù),如(emission, albedo等參數(shù)值) //此通道并不在常規(guī)的渲染過程中使用 Pass { //設置通道名稱 Name 'META' //于通道標簽中設置光照模型為Meta //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應該是Unity官方的疏漏) Tags { 'LightMode'='Meta' } //關閉剔除操作 Cull Off //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vert_meta #pragma fragment frag_meta //---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _EMISSION #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 //包含輔助CG頭文件 #include 'UnityStandardMeta.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } } //------------------------------------【子著色器2】----------------------------------- // 此子著色器用于Shader Model 2.0 //---------------------------------------------------------------------------------------- SubShader { //渲染類型設置:不透明 Tags { 'RenderType'='Opaque' 'PerformanceChecks'='False' } //細節(jié)層次設為:150 LOD 150 //--------------------------------通道1------------------------------- // 正向基礎渲染通道(Base forward pass) // 處理方向光,自發(fā)光,光照貼圖等 ... Pass { //設置通道名稱 Name 'FORWARD' //于通道標簽中設置光照模型為ForwardBase,正向渲染基礎通道 Tags { 'LightMode' = 'ForwardBase' } //混合操作:源混合乘以目標混合,即結果為兩者的混合 Blend [_SrcBlend] [_DstBlend] // 根據_ZWrite參數(shù),設置深度寫入模式開關與否 ZWrite [_ZWrite] //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 2.0 #pragma target 2.0 // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _NORMALMAP #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP //跳過如下變體的編譯,簡化編譯過程 #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE //--------著色器編譯多樣化快捷指令------------ #pragma multi_compile_fwdbase #pragma multi_compile_fog //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertForwardBase #pragma fragment fragForwardBase //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } //--------------------------------通道2------------------------------- // 正向附加渲染通道(Additive forward pass) // 以每個光照一個通道的方式應用附加的逐像素光照 Pass { //設置通道名稱 Name 'FORWARD_DELTA' //于通道標簽中設置光照模型為ForwardAdd,正向渲染附加通道 Tags { 'LightMode' = 'ForwardAdd' } //混合操作:源混合乘以1 Blend [_SrcBlend] One //附加通道中的霧效應該為黑色 Fog { Color (0,0,0,0) } //關閉深度寫入模式 ZWrite Off //設置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 2.0 #pragma target 2.0 // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _NORMALMAP #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 //跳過一些變體的編譯 // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP #pragma skip_variants SHADOWS_SOFT //--------使用Unity內置的著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎通道所需的所有變體,但同時為上述通道的處理賦予了光照實時陰影的能力。 #pragma multi_compile_fwdadd_fullshadows //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertForwardAdd #pragma fragment fragForwardAdd //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道3------------------------------- // 陰影渲染通道(Shadow Caster pass) // 將將物體的深度渲染到陰影貼圖或深度紋理中 Pass { //設置通道名稱 Name 'ShadowCaster' //于通道標簽中設置光照模型為ShadowCaster。 //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。 Tags { 'LightMode' = 'ShadowCaster' } //開啟深入寫入模式 ZWrite On //設置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標:Model 2.0 #pragma target 2.0 //---------編譯指令:著色器編譯多樣化(shader_feature)-------- #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON //編譯指令:跳過某些變體的編譯 #pragma skip_variants SHADOWS_SOFT //快捷編譯指令:進行陰影投射相關的多著色器變體的編譯 #pragma multi_compile_shadowcaster //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vertShadowCaster #pragma fragment fragShadowCaster //包含輔助CG頭文件 #include 'UnityStandardShadow.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道4------------------------------- //元通道(Meta Pass) //為全局光照(GI),光照貼圖等技術提取相關參數(shù),如(emission, albedo等參數(shù)值) //此通道并不在常規(guī)的渲染過程中使用 Pass { //設置通道名稱 Name 'META' //于通道標簽中設置光照模型為Meta //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應該是Unity官方的疏漏) Tags { 'LightMode'='Meta' } //關閉剔除操作 Cull Off //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vert_meta #pragma fragment frag_meta //---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _EMISSION #pragma shader_feature _METALLICGLOSSMAP #pragma shader_feature ___ _DETAIL_MULX2 //包含輔助CG頭文件 #include 'UnityStandardMeta.cginc' //===========結束CG著色器語言編寫模塊=========== ENDCG } } //回退Shader為頂點光照Shader FallBack 'VertexLit' //使用特定的自定義編輯器UI界面 CustomEditor 'StandardShaderGUI'}

 

標準著色器的源代碼部分相對于著色器的體量來說,算是有點長的,加上注釋后有近500行。先稍微把它的架構稍微理一下。

標準著色器由兩個SubShader組成。第一個SubShader用于處理Shader Model 3.0,有5個通道,第二個SubShader用于處理Shader Model 2.0, 有4個通道,

詳細的架構如下圖:

 


OK,標準著色器的架構大致如上。今天就先講這么多,上面代碼的稍微有些看不懂沒關系,從下次更新開始,就將深入到每個Pass的頂點和片段著色器函數(shù)之中,逐行注釋與分析他們的指令細節(jié)。

 

而不難發(fā)現(xiàn),標準著色器代碼的第一個SubShader比第二個SubShader多出了一個延遲渲染通道(Deferred Render Pass),下面稍微提一下延遲渲染的基本概念。

 

 

 



 

三、關于延遲渲染(Deferred Render)





看過《GPU Gems2》的朋友們應該都有所了解,延遲渲染(Deferred Render,又稱Deferred Shading)是次時代引擎必備的渲染方式之一。

需要注意,Deferred Render和Deferred Shading有一點細微的差別。

  • Deferred Shading:將所有的Shading全部轉到Deferred階段進行。
  • Deferred Render:只是有選擇地將Lighting轉到Deferred階段進行。

Unity中默認使用的是Deferred Shading。

 

而延遲渲染,一言以蔽之,就是將光照/渲染的計算延遲到第二步進行,避免多次渲染同一個像素,從而減少多余的計算操作,以提高渲染效率的一種先進的渲染方式。

 

延遲渲染最大的優(yōu)勢是可以實現(xiàn)同屏中數(shù)量眾多的動態(tài)光源(十幾到幾十個),這在傳統(tǒng)的渲染管線中是很難實現(xiàn)的。

 

更多延遲渲染的細節(jié),這邊不細說,只是提供一些鏈接,以作進一步了解延遲渲染的導論之用:


 

 

 

 


四、屏幕水幕特效的實現(xiàn)

 

 


在上一篇文章中有提到過,Unity中的屏幕特效通常分為兩部分來實現(xiàn):

 

  • Shader實現(xiàn)部分
  • 腳本實現(xiàn)部分

 

下面依然是從這兩個方面對本次的特效進行實現(xiàn)。

 

而在這之前,需要準備好一張水滴(水滴太多了也就成了水幕了)的效果圖片(google“water drop”一下,稍微篩選一下就有了,最好是能找到或者自己加工成無縫銜接的),放置于我們特效的腳本實現(xiàn)文件目錄附加的一個Resources的文件夾中,那么我們在腳本中適當?shù)牡胤綄懮弦痪洌?/span>

Texture2 = Resources.Load('ScreenWaterDrop')as Texture2D;

 

就可以讀取到這張圖片了。

淺墨準備的圖片如下(無水印本圖片的可以在淺墨的Github中找到,或者直接下文章末尾的項目工程)。

ScreenWaterDrop.png:


 

 


 

4.1 Shader實現(xiàn)部分

 


老規(guī)矩,先上詳細注釋的代碼。

//-----------------------------------------------【Shader腳本說明】---------------------------------------------------// 屏幕水幕特效的實現(xiàn)代碼-Shader腳本部分// 2015年10月 Created by 淺墨// 更多內容或交流,請訪問淺墨的博客:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------Shader '淺墨Shader編程/Volume9/ScreenWaterDropEffect'{ //------------------------------------【屬性值】------------------------------------ Properties { //主紋理 _MainTex ('Base (RGB)', 2D) = 'white' {} //屏幕水滴的素材圖 _ScreenWaterDropTex ('Base (RGB)', 2D) = 'white' {} //當前時間 _CurTime ('Time', Range(0.0, 1.0)) = 1.0 //X坐標上的水滴尺寸 _SizeX ('SizeX', Range(0.0, 1.0)) = 1.0 //Y坐標上的水滴尺寸 _SizeY ('SizeY', Range(0.0, 1.0)) = 1.0 //水滴的流動速度 _DropSpeed ('Speed', Range(0.0, 10.0)) = 1.0 //溶解度 _Distortion ('_Distortion', Range(0.0, 1.0)) = 0.87 } //------------------------------------【唯一的子著色器】------------------------------------ SubShader { Pass { //設置深度測試模式:渲染所有像素.等同于關閉透明度測試(AlphaTest Off) ZTest Always //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱 #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest //編譯指令: 指定著色器編譯目標為Shader Model 3.0 #pragma target 3.0 //包含輔助CG頭文件 #include 'UnityCG.cginc' //外部變量的聲明 uniform sampler2D _MainTex; uniform sampler2D _ScreenWaterDropTex; uniform float _CurTime; uniform float _DropSpeed; uniform float _SizeX; uniform float _SizeY; uniform float _Distortion; uniform float2 _MainTex_TexelSize; //頂點輸入結構 struct vertexInput { float4 vertex : POSITION;//頂點位置 float4 color : COLOR;//顏色值 float2 texcoord : TEXCOORD0;//一級紋理坐標 }; //頂點輸出結構 struct vertexOutput { half2 texcoord : TEXCOORD0;//一級紋理坐標 float4 vertex : SV_POSITION;//像素位置 fixed4 color : COLOR;//顏色值 }; //--------------------------------【頂點著色函數(shù)】----------------------------- // 輸入:頂點輸入結構體 // 輸出:頂點輸出結構體 //--------------------------------------------------------------------------------- vertexOutput vert(vertexInput Input) { //【1】聲明一個輸出結構對象 vertexOutput Output; //【2】填充此輸出結構 //輸出的頂點位置為模型視圖投影矩陣乘以頂點位置,也就是將三維空間中的坐標投影到了二維窗口 Output.vertex = mul(UNITY_MATRIX_MVP, Input.vertex); //輸出的紋理坐標也就是輸入的紋理坐標 Output.texcoord = Input.texcoord; //輸出的顏色值也就是輸入的顏色值 Output.color = Input.color; //【3】返回此輸出結構對象 return Output; } //--------------------------------【片段著色函數(shù)】----------------------------- // 輸入:頂點輸出結構體 // 輸出:float4型的顏色值 //--------------------------------------------------------------------------------- fixed4 frag(vertexOutput Input) : COLOR { //【1】獲取頂點的坐標值 float2 uv = Input.texcoord.xy; //【2】解決平臺差異的問題。校正方向,若和規(guī)定方向相反,則將速度反向并加1 #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0)="" _dropspeed="1" -="" _dropspeed;="" #endif="" 【3】設置三層水流效果,按照一定的規(guī)律在水滴紋理上分別進行取樣="" float3="" raintex1="tex2D(_ScreenWaterDropTex," float2(uv.x="" *="" 1.15*="" _sizex,="" (uv.y*="" _sizey="" *1.1)="" +="" _curtime*="" _dropspeed="" *0.15)).rgb="" _distortion;="" float3="" raintex2="tex2D(_ScreenWaterDropTex," float2(uv.x="" *="" 1.25*="" _sizex="" -="" 0.1,="" (uv.y="" *_sizey="" *="" 1.2)="" +="" _curtime="" *_dropspeed="" *="" 0.2)).rgb="" _distortion;="" float3="" raintex3="tex2D(_ScreenWaterDropTex," float2(uv.x*="" _sizex="" *0.9,="" (uv.y="" *_sizey="" *="" 1.25)="" +="" _curtime="" *="" _dropspeed*="" 0.032)).rgb="" _distortion;="" 【4】整合三層水流效果的顏色信息,存于finalraintex中="" float2="" finalraintex="uv.xy" -="" (raintex1.xy="" -="" raintex2.xy="" -="" raintex3.xy)="" 3;="" 【5】按照finalraintex的坐標信息,在主紋理上進行采樣="" float3="" finalcolor="tex2D(_MainTex," float2(finalraintex.x,="" finalraintex.y)).rgb;="" 【6】返回加上alpha分量的最終顏色值="" return="" fixed4(finalcolor,="" 1.0);="" }="" =="=========結束CG著色器語言編寫模塊===========" endcg="" }="">


 

屏幕特效Shader中真正有營養(yǎng)的核心代碼,一般都是位于像素著色器中。也就是這里的frag函數(shù)中,稍微聊一聊。

 

第一步,先從頂點著色器輸出結構體中獲取頂點的坐標:

//【1】獲取頂點的坐標值float2 uv = Input.texcoord.xy;


第二步,因為需要水幕紋理在屏幕中從上向下滾動,而不同平臺的原點位置是不同的,Direct3D原點在左上角,OpenGL原點在左下角。所以在這邊需要對情況進行統(tǒng)一。

統(tǒng)一的方法里用到了UNITY_UV_STARTS_AT_TOP宏,它是Unity中內置的宏,其值 取為1 或0 ; 在紋理 V 坐標在“紋理頂部”為零的平臺上值取 1。如Direct3D;而OpenGL 平臺上取 0。

另外,這邊還用到了MainTex_TexelSize變量。

float2型的MainTex_TexelSize(其實是_TexelSize后綴,前面的名稱會根據定義紋理變量的改變而改變)也是Unity中內置的一個變量,存放了紋理中單個像素的尺寸,也就是說,如果有一張2048 x 2048的紋理,那么x和y的取值都為1.0/2048.0。而且需要注意,當該紋理被Direct3D的抗鋸齒操作垂直反轉過后,xxx_TexelSize的值將為負數(shù)。

 

所以,第二步的代碼就是如下:

//【2】解決平臺差異的問題。校正方向,若和規(guī)定方向相反,則將速度反向并加1 #if UNITY_UV_STARTS_AT_TOP if(_MainTex_TexelSize.y < 0)="" _dropspeed="1" -="" _dropspeed;="">

 

第三步,定義三層水流的紋理,按照不同的參數(shù)取值,進行采樣:

//【3】設置三層水流效果,按照一定的規(guī)律在水滴紋理上分別進行取樣float3 rainTex1 = tex2D(_ScreenWaterDropTex, float2(uv.x * 1.15* _SizeX, (uv.y* _SizeY*1.1) + _CurTime* _DropSpeed *0.15)).rgb / _Distortion;float3 rainTex2 = tex2D(_ScreenWaterDropTex, float2(uv.x * 1.25* _SizeX - 0.1, (uv.y*_SizeY * 1.2) + _CurTime *_DropSpeed * 0.2)).rgb / _Distortion;float3 rainTex3 = tex2D(_ScreenWaterDropTex, float2(uv.x* _SizeX *0.9, (uv.y *_SizeY *1.25) + _CurTime * _DropSpeed* 0.032)).rgb / _Distortion;


第四步,整合一下三層水流效果的顏色信息,用一個float2型的變量存放下來:

//【4】整合三層水流效果的顏色信息,存于finalRainTex中float2 finalRainTex = uv.xy - (rainTex1.xy - rainTex2.xy - rainTex3.xy) / 3;


 

第五步,自然是在屏幕所在的紋理_MainTex中進行一次最終的采樣,算出最終結果顏色值,存放于float3型的finalColor中。

//【5】按照finalRainTex的坐標信息,在主紋理上進行采樣float3 finalColor = tex2D(_MainTex, float2(finalRainTex.x, finalRainTex.y)).rgb;


第六步,因為返回的是一個fixed4型的變量,rgba。所以需要給float3型的finalColor配上一個alpha分量,并返回:

//【6】返回加上alpha分量的最終顏色值

return fixed4(finalColor, 1.0);

 

OK,關于此Shader的實現(xiàn)細節(jié),差不多就需要講到這些。下面再看一下C#腳本文件的實現(xiàn)。

 


 

4.2 C#腳本實現(xiàn)部分

 


C#腳本文件的實現(xiàn)并沒有什么好講的,唯一的地方,水滴紋理的載入,上面已經提到過了,實現(xiàn)代碼如下:

//載入素材圖 ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') asTexture2D;

 

下面就直接貼出詳細注釋的實現(xiàn)此特效的C#腳本:

 

//-----------------------------------------------【C#腳本說明】---------------------------------------------------// 屏幕水幕特效的實現(xiàn)代碼-C#腳本部分// 2015年10月 Created by 淺墨// 更多內容或交流,請訪問淺墨的博客:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------using UnityEngine;using System.Collections;[ExecuteInEditMode][AddComponentMenu('淺墨Shader編程/Volume9/ScreenWaterDropEffect')]public class ScreenWaterDropEffect : MonoBehaviour { //-------------------變量聲明部分------------------- #region Variables //著色器和材質實例 public Shader CurShader;//著色器實例 private Material CurMaterial;//當前的材質 //時間變量和素材圖的定義 private float TimeX = 1.0f;//時間變量 private Texture2D ScreenWaterDropTex;//屏幕水滴的素材圖 //可以在編輯器中調整的參數(shù)值 [Range(5, 64), Tooltip('溶解度')] public float Distortion = 8.0f; [Range(0, 7), Tooltip('水滴在X坐標上的尺寸')] public float SizeX = 1f; [Range(0, 7), Tooltip('水滴在Y坐標上的尺寸')] public float SizeY = 0.5f; [Range(0, 10), Tooltip('水滴的流動速度')] public float DropSpeed = 3.6f; //用于參數(shù)調節(jié)的中間變量 public static float ChangeDistortion; public static float ChangeSizeX; public static float ChangeSizeY; public static float ChangeDropSpeed; #endregion //-------------------------材質的get&set---------------------------- #region MaterialGetAndSet Material material { get { if (CurMaterial == null) { CurMaterial = new Material(CurShader); CurMaterial.hideFlags = HideFlags.HideAndDontSave; } return CurMaterial; } } #endregion //-----------------------------------------【Start()函數(shù)】--------------------------------------------- // 說明:此函數(shù)僅在Update函數(shù)第一次被調用前被調用 //-------------------------------------------------------------------------------------------------------- void Start() { //依次賦值 ChangeDistortion = Distortion; ChangeSizeX = SizeX; ChangeSizeY = SizeY; ChangeDropSpeed = DropSpeed; //載入素材圖 ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') as Texture2D; //找到當前的Shader文件 CurShader = Shader.Find('淺墨Shader編程/Volume9/ScreenWaterDropEffect'); //判斷是否支持屏幕特效 if (!SystemInfo.supportsImageEffects) { enabled = false; return; } } //-------------------------------------【OnRenderImage()函數(shù)】------------------------------------ // 說明:此函數(shù)在當完成所有渲染圖片后被調用,用來渲染圖片后期效果 //-------------------------------------------------------------------------------------------------------- void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { //著色器實例不為空,就進行參數(shù)設置 if (CurShader != null) { //時間的變化 TimeX += Time.deltaTime; //時間大于100,便置0,保證可以循環(huán) if (TimeX > 100) TimeX = 0; //設置Shader中其他的外部變量 material.SetFloat('_CurTime', TimeX); material.SetFloat('_Distortion', Distortion); material.SetFloat('_SizeX', SizeX); material.SetFloat('_SizeY', SizeY); material.SetFloat('_DropSpeed', DropSpeed); material.SetTexture('_ScreenWaterDropTex', ScreenWaterDropTex); //拷貝源紋理到目標渲染紋理,加上我們的材質效果 Graphics.Blit(sourceTexture, destTexture, material); } //著色器實例為空,直接拷貝屏幕上的效果。此情況下是沒有實現(xiàn)屏幕特效的 else { //直接拷貝源紋理到目標渲染紋理 Graphics.Blit(sourceTexture, destTexture); } } //-----------------------------------------【OnValidate()函數(shù)】-------------------------------------- // 說明:此函數(shù)在編輯器中該腳本的某個值發(fā)生了改變后被調用 //-------------------------------------------------------------------------------------------------------- void OnValidate() { ChangeDistortion = Distortion; ChangeSizeX = SizeX; ChangeSizeY = SizeY; ChangeDropSpeed = DropSpeed; } //-----------------------------------------【Update()函數(shù)】------------------------------------------ // 說明:此函數(shù)在每一幀中都會被調用 //-------------------------------------------------------------------------------------------------------- void Update() { //若程序在運行,進行賦值 if (Application.isPlaying) { //賦值 Distortion = ChangeDistortion; SizeX = ChangeSizeX; SizeY = ChangeSizeY; DropSpeed = ChangeDropSpeed; } //找到對應的Shader文件,和紋理素材#if UNITY_EDITOR if (Application.isPlaying != true) { CurShader = Shader.Find('淺墨Shader編程/Volume9/ScreenWaterDropEffect'); ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') as Texture2D; }#endif } //-----------------------------------------【OnDisable()函數(shù)】--------------------------------------- // 說明:當對象變?yōu)椴豢捎没蚍羌せ顮顟B(tài)時此函數(shù)便被調用 //-------------------------------------------------------------------------------------------------------- void OnDisable() { if (CurMaterial) { //立即銷毀材質實例 DestroyImmediate(CurMaterial); } }}


OK,水幕屏幕特效實現(xiàn)部分大致就是這樣,下面看一下運行效果的對比。

 

 


 

五、最終的效果展示

 

 


貼幾張場景的效果圖和使用了屏幕特效后的效果圖。在試玩場景時,除了類似CS/CF的FPS游戲控制系統(tǒng)以外,還可以使用鍵盤上的按鍵【F】,開啟或者屏幕特效。

本次的場景還是使用上次更新中放出的城鎮(zhèn),只是出生地點有所改變。為了有更多的時間專注于Shader書寫本身,以后的博文配套場景采取不定期大更新的形式(兩次、三次一換)。


 

城鎮(zhèn)野外(with 屏幕水幕特效):



城鎮(zhèn)野外(原始圖):



山坡上(with 屏幕水幕特效):



山坡上(原始圖):



城鎮(zhèn)中(with 屏幕水幕特效):



城鎮(zhèn)中(原始圖)



石橋上(with 屏幕水幕特效):



石橋上(原始圖):

 

 

 

本次的更新大致如此,感謝各位捧場,我們下周再見。

 

 

附: 本博文相關下載鏈接清單

 

【百度云】博文示例場景exe下載

【百度云】包含博文示例場景所有資源與源碼的unitypackage下載

【Github】本文全部Shader源代碼



另附:若遇到導入unitypackage過程中進度條卡住的情況,不用慌,這是Unity5的一個bug。我也經常在導入工程時遇到。其實這個時候已經導入成功了,用資源管理器殺掉當前這個Unity的進程,再打開就行了。

 


    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多