|
標(biāo)準(zhǔn)著色器對(duì)應(yīng)材質(zhì)的編輯器外觀不同于一般的Shader,就是因?yàn)樵赟hader末尾書寫了如下的代碼:
//使用特定的自定義編輯器UI界面CustomEditor 'StandardShaderGUI'
標(biāo)準(zhǔn)著色器對(duì)應(yīng)材質(zhì)的編輯器外觀如下:
一般的著色器對(duì)應(yīng)材質(zhì)的編輯器外觀如下:
二、Unity5標(biāo)準(zhǔn)著色器源代碼剖析之一:架構(gòu)分析篇上文已經(jīng)提到過,標(biāo)準(zhǔn)著色器源代碼的剖析是一個(gè)小小的馬拉松,完全解析起來篇幅會(huì)很長,所以本系列文章將對(duì)剖析的過程進(jìn)行連載,此節(jié)為連載的第一部分。
在這里先貼出經(jīng)過淺墨詳細(xì)注釋的標(biāo)準(zhǔn)著色器標(biāo)準(zhǔn)版的源代碼,并對(duì)架構(gòu)進(jìn)行簡單的分析,而對(duì)每個(gè)通道的剖析在稍后的更新中會(huì)進(jìn)行。
//-----------------------------------------------【Shader說明】---------------------------------------------------// Unity5.2.1 Built-in Standard Shader// 2015年10月 Commented by 淺墨 // 更多內(nèi)容或交流,請?jiān)L問淺墨的博客: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' {} //遮擋強(qiáng)度 _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' {} //細(xì)節(jié)掩膜圖 _DetailMask('Detail Mask', 2D) = 'white' {} //細(xì)節(jié)紋理圖 _DetailAlbedoMap('Detail Albedo x2', 2D) = 'grey' {} //細(xì)節(jié)法線貼圖尺度 _DetailNormalMapScale('Scale', Float) = 1.0 //細(xì)節(jié)法線貼圖 _DetailNormalMap('Normal Map', 2D) = 'bump' {} //二級(jí)紋理的UV設(shè)置 [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相關(guān)的一個(gè)宏 #define UNITY_SETUP_BRDF_INPUT MetallicSetup //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG //------------------------------------【子著色器1】------------------------------------ // 此子著色器用于Shader Model 3.0 //---------------------------------------------------------------------------------------- SubShader { //渲染類型設(shè)置:不透明 Tags { 'RenderType'='Opaque' 'PerformanceChecks'='False' } //細(xì)節(jié)層次設(shè)為:300 LOD 300 //--------------------------------通道1------------------------------- // 正向基礎(chǔ)渲染通道(Base forward pass) // 處理方向光,自發(fā)光,光照貼圖等 ... Pass { //設(shè)置通道名稱 Name 'FORWARD' //于通道標(biāo)簽中設(shè)置光照模型為ForwardBase,正向渲染基礎(chǔ)通道 Tags { 'LightMode' = 'ForwardBase' } //混合操作:源混合乘以目標(biāo)混合 Blend [_SrcBlend] [_DstBlend] // 根據(jù)_ZWrite參數(shù),設(shè)置深度寫入模式開關(guān)與否 ZWrite [_ZWrite] //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):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 //--------著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎(chǔ)通道(用于正向渲染中,應(yīng)用環(huán)境光照、主方向光照和頂點(diǎn)/球面調(diào)和光照)所需的所有變體。 //這些變體用于處理不同的光照貼圖類型、主要方向光源的陰影選項(xiàng)的開關(guān)與否 #pragma multi_compile_fwdbase //編譯指令:編譯幾個(gè)不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertForwardBase #pragma fragment fragForwardBase //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } //--------------------------------通道2------------------------------- // 正向附加渲染通道(Additive forward pass) // 以每個(gè)光照一個(gè)通道的方式應(yīng)用附加的逐像素光照 Pass { //設(shè)置通道名稱 Name 'FORWARD_DELTA' //于通道標(biāo)簽中設(shè)置光照模型為ForwardAdd,正向渲染附加通道 Tags { 'LightMode' = 'ForwardAdd' } //混合操作:源混合乘以1 Blend [_SrcBlend] One //附加通道中的霧效應(yīng)該為黑色 Fog { Color (0,0,0,0) } //關(guān)閉深度寫入模式 ZWrite Off //設(shè)置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):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內(nèi)置的著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎(chǔ)通道所需的所有變體,但同時(shí)為上述通道的處理賦予了光照實(shí)時(shí)陰影的能力。 #pragma multi_compile_fwdadd_fullshadows //編譯指令:編譯幾個(gè)不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertForwardAdd #pragma fragment fragForwardAdd //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道3------------------------------- // 陰影渲染通道(Shadow Caster pass) // 將將物體的深度渲染到陰影貼圖或深度紋理中 Pass { //設(shè)置通道名稱 Name 'ShadowCaster' //于通道標(biāo)簽中設(shè)置光照模型為ShadowCaster。 //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。 Tags { 'LightMode' = 'ShadowCaster' } //開啟深入寫入模式 ZWrite On //設(shè)置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):Model 3.0 #pragma target 3.0 //編譯指令:不使用GLES渲染器編譯 #pragma exclude_renderers gles // ---------編譯指令:著色器編譯多樣化-------- #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON //--------著色器編譯多樣化快捷指令------------ //進(jìn)行陰影投射相關(guān)的多著色器變體的編譯 #pragma multi_compile_shadowcaster //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertShadowCaster #pragma fragment fragShadowCaster //包含輔助CG頭文件 #include 'UnityStandardShadow.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道4------------------------------- // 延遲渲染通道(Deferred Render Pass) Pass { //設(shè)置通道名稱 Name 'DEFERRED' //于通道標(biāo)簽中設(shè)置光照模型為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 //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertDeferred #pragma fragment fragDeferred //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道5------------------------------- //元通道(Meta Pass) //為全局光照(GI),光照貼圖等技術(shù)提取相關(guān)參數(shù),如(emission, albedo等參數(shù)值) //此通道并不在常規(guī)的渲染過程中使用 Pass { //設(shè)置通道名稱 Name 'META' //于通道標(biāo)簽中設(shè)置光照模型為Meta //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應(yīng)該是Unity官方的疏漏) Tags { 'LightMode'='Meta' } //關(guān)閉剔除操作 Cull Off //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(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' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } } //------------------------------------【子著色器2】----------------------------------- // 此子著色器用于Shader Model 2.0 //---------------------------------------------------------------------------------------- SubShader { //渲染類型設(shè)置:不透明 Tags { 'RenderType'='Opaque' 'PerformanceChecks'='False' } //細(xì)節(jié)層次設(shè)為:150 LOD 150 //--------------------------------通道1------------------------------- // 正向基礎(chǔ)渲染通道(Base forward pass) // 處理方向光,自發(fā)光,光照貼圖等 ... Pass { //設(shè)置通道名稱 Name 'FORWARD' //于通道標(biāo)簽中設(shè)置光照模型為ForwardBase,正向渲染基礎(chǔ)通道 Tags { 'LightMode' = 'ForwardBase' } //混合操作:源混合乘以目標(biāo)混合,即結(jié)果為兩者的混合 Blend [_SrcBlend] [_DstBlend] // 根據(jù)_ZWrite參數(shù),設(shè)置深度寫入模式開關(guān)與否 ZWrite [_ZWrite] //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):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 //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertForwardBase #pragma fragment fragForwardBase //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } //--------------------------------通道2------------------------------- // 正向附加渲染通道(Additive forward pass) // 以每個(gè)光照一個(gè)通道的方式應(yīng)用附加的逐像素光照 Pass { //設(shè)置通道名稱 Name 'FORWARD_DELTA' //于通道標(biāo)簽中設(shè)置光照模型為ForwardAdd,正向渲染附加通道 Tags { 'LightMode' = 'ForwardAdd' } //混合操作:源混合乘以1 Blend [_SrcBlend] One //附加通道中的霧效應(yīng)該為黑色 Fog { Color (0,0,0,0) } //關(guān)閉深度寫入模式 ZWrite Off //設(shè)置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):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內(nèi)置的著色器編譯多樣化快捷指令------------ //編譯指令:編譯正向渲染基礎(chǔ)通道所需的所有變體,但同時(shí)為上述通道的處理賦予了光照實(shí)時(shí)陰影的能力。 #pragma multi_compile_fwdadd_fullshadows //編譯指令:編譯幾個(gè)不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/) #pragma multi_compile_fog //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertForwardAdd #pragma fragment fragForwardAdd //包含輔助CG頭文件 #include 'UnityStandardCore.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道3------------------------------- // 陰影渲染通道(Shadow Caster pass) // 將將物體的深度渲染到陰影貼圖或深度紋理中 Pass { //設(shè)置通道名稱 Name 'ShadowCaster' //于通道標(biāo)簽中設(shè)置光照模型為ShadowCaster。 //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。 Tags { 'LightMode' = 'ShadowCaster' } //開啟深入寫入模式 ZWrite On //設(shè)置深度測試模式:小于等于 ZTest LEqual //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //著色器編譯目標(biāo):Model 2.0 #pragma target 2.0 //---------編譯指令:著色器編譯多樣化(shader_feature)-------- #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON //編譯指令:跳過某些變體的編譯 #pragma skip_variants SHADOWS_SOFT //快捷編譯指令:進(jìn)行陰影投射相關(guān)的多著色器變體的編譯 #pragma multi_compile_shadowcaster //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vertShadowCaster #pragma fragment fragShadowCaster //包含輔助CG頭文件 #include 'UnityStandardShadow.cginc' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } // --------------------------------通道4------------------------------- //元通道(Meta Pass) //為全局光照(GI),光照貼圖等技術(shù)提取相關(guān)參數(shù),如(emission, albedo等參數(shù)值) //此通道并不在常規(guī)的渲染過程中使用 Pass { //設(shè)置通道名稱 Name 'META' //于通道標(biāo)簽中設(shè)置光照模型為Meta //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應(yīng)該是Unity官方的疏漏) Tags { 'LightMode'='Meta' } //關(guān)閉剔除操作 Cull Off //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(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' //===========結(jié)束CG著色器語言編寫模塊=========== ENDCG } } //回退Shader為頂點(diǎn)光照Shader FallBack 'VertexLit' //使用特定的自定義編輯器UI界面 CustomEditor 'StandardShaderGUI'}
標(biāo)準(zhǔn)著色器的源代碼部分相對(duì)于著色器的體量來說,算是有點(diǎn)長的,加上注釋后有近500行。先稍微把它的架構(gòu)稍微理一下。 標(biāo)準(zhǔn)著色器由兩個(gè)SubShader組成。第一個(gè)SubShader用于處理Shader Model 3.0,有5個(gè)通道,第二個(gè)SubShader用于處理Shader Model 2.0, 有4個(gè)通道, 詳細(xì)的架構(gòu)如下圖: OK,標(biāo)準(zhǔn)著色器的架構(gòu)大致如上。今天就先講這么多,上面代碼的稍微有些看不懂沒關(guān)系,從下次更新開始,就將深入到每個(gè)Pass的頂點(diǎn)和片段著色器函數(shù)之中,逐行注釋與分析他們的指令細(xì)節(jié)。
而不難發(fā)現(xiàn),標(biāo)準(zhǔn)著色器代碼的第一個(gè)SubShader比第二個(gè)SubShader多出了一個(gè)延遲渲染通道(Deferred Render Pass),下面稍微提一下延遲渲染的基本概念。
三、關(guān)于延遲渲染(Deferred Render)看過《GPU Gems2》的朋友們應(yīng)該都有所了解,延遲渲染(Deferred Render,又稱Deferred Shading)是次時(shí)代引擎必備的渲染方式之一。 需要注意,Deferred Render和Deferred Shading有一點(diǎn)細(xì)微的差別。
Unity中默認(rèn)使用的是Deferred Shading。
而延遲渲染,一言以蔽之,就是將光照/渲染的計(jì)算延遲到第二步進(jìn)行,避免多次渲染同一個(gè)像素,從而減少多余的計(jì)算操作,以提高渲染效率的一種先進(jìn)的渲染方式。
延遲渲染最大的優(yōu)勢是可以實(shí)現(xiàn)同屏中數(shù)量眾多的動(dòng)態(tài)光源(十幾到幾十個(gè)),這在傳統(tǒng)的渲染管線中是很難實(shí)現(xiàn)的。
更多延遲渲染的細(xì)節(jié),這邊不細(xì)說,只是提供一些鏈接,以作進(jìn)一步了解延遲渲染的導(dǎo)論之用:
四、屏幕水幕特效的實(shí)現(xiàn)
在上一篇文章中有提到過,Unity中的屏幕特效通常分為兩部分來實(shí)現(xiàn):
下面依然是從這兩個(gè)方面對(duì)本次的特效進(jìn)行實(shí)現(xiàn)。
而在這之前,需要準(zhǔn)備好一張水滴(水滴太多了也就成了水幕了)的效果圖片(google“water drop”一下,稍微篩選一下就有了,最好是能找到或者自己加工成無縫銜接的),放置于我們特效的腳本實(shí)現(xiàn)文件目錄附加的一個(gè)Resources的文件夾中,那么我們在腳本中適當(dāng)?shù)牡胤綄懮弦痪洌?/span> Texture2 = Resources.Load('ScreenWaterDrop')as Texture2D;
就可以讀取到這張圖片了。 淺墨準(zhǔn)備的圖片如下(無水印本圖片的可以在淺墨的Github中找到,或者直接下文章末尾的項(xiàng)目工程)。 ScreenWaterDrop.png:
4.1 Shader實(shí)現(xiàn)部分
老規(guī)矩,先上詳細(xì)注釋的代碼。 //-----------------------------------------------【Shader腳本說明】---------------------------------------------------// 屏幕水幕特效的實(shí)現(xiàn)代碼-Shader腳本部分// 2015年10月 Created by 淺墨// 更多內(nèi)容或交流,請?jiān)L問淺墨的博客:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------Shader '淺墨Shader編程/Volume9/ScreenWaterDropEffect'{ //------------------------------------【屬性值】------------------------------------ Properties { //主紋理 _MainTex ('Base (RGB)', 2D) = 'white' {} //屏幕水滴的素材圖 _ScreenWaterDropTex ('Base (RGB)', 2D) = 'white' {} //當(dāng)前時(shí)間 _CurTime ('Time', Range(0.0, 1.0)) = 1.0 //X坐標(biāo)上的水滴尺寸 _SizeX ('SizeX', Range(0.0, 1.0)) = 1.0 //Y坐標(biāo)上的水滴尺寸 _SizeY ('SizeY', Range(0.0, 1.0)) = 1.0 //水滴的流動(dòng)速度 _DropSpeed ('Speed', Range(0.0, 10.0)) = 1.0 //溶解度 _Distortion ('_Distortion', Range(0.0, 1.0)) = 0.87 } //------------------------------------【唯一的子著色器】------------------------------------ SubShader { Pass { //設(shè)置深度測試模式:渲染所有像素.等同于關(guān)閉透明度測試(AlphaTest Off) ZTest Always //===========開啟CG著色器語言編寫模塊=========== CGPROGRAM //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱 #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest //編譯指令: 指定著色器編譯目標(biāo)為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; //頂點(diǎn)輸入結(jié)構(gòu) struct vertexInput { float4 vertex : POSITION;//頂點(diǎn)位置 float4 color : COLOR;//顏色值 float2 texcoord : TEXCOORD0;//一級(jí)紋理坐標(biāo) }; //頂點(diǎn)輸出結(jié)構(gòu) struct vertexOutput { half2 texcoord : TEXCOORD0;//一級(jí)紋理坐標(biāo) float4 vertex : SV_POSITION;//像素位置 fixed4 color : COLOR;//顏色值 }; //--------------------------------【頂點(diǎn)著色函數(shù)】----------------------------- // 輸入:頂點(diǎn)輸入結(jié)構(gòu)體 // 輸出:頂點(diǎn)輸出結(jié)構(gòu)體 //--------------------------------------------------------------------------------- vertexOutput vert(vertexInput Input) { //【1】聲明一個(gè)輸出結(jié)構(gòu)對(duì)象 vertexOutput Output; //【2】填充此輸出結(jié)構(gòu) //輸出的頂點(diǎn)位置為模型視圖投影矩陣乘以頂點(diǎn)位置,也就是將三維空間中的坐標(biāo)投影到了二維窗口 Output.vertex = mul(UNITY_MATRIX_MVP, Input.vertex); //輸出的紋理坐標(biāo)也就是輸入的紋理坐標(biāo) Output.texcoord = Input.texcoord; //輸出的顏色值也就是輸入的顏色值 Output.color = Input.color; //【3】返回此輸出結(jié)構(gòu)對(duì)象 return Output; } //--------------------------------【片段著色函數(shù)】----------------------------- // 輸入:頂點(diǎn)輸出結(jié)構(gòu)體 // 輸出:float4型的顏色值 //--------------------------------------------------------------------------------- fixed4 frag(vertexOutput Input) : COLOR { //【1】獲取頂點(diǎn)的坐標(biāo)值 float2 uv = Input.texcoord.xy; //【2】解決平臺(tái)差異的問題。校正方向,若和規(guī)定方向相反,則將速度反向并加1 #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0)="" _dropspeed="1" -="" _dropspeed;="" #endif="" 【3】設(shè)置三層水流效果,按照一定的規(guī)律在水滴紋理上分別進(jìn)行取樣="" 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的坐標(biāo)信息,在主紋理上進(jìn)行采樣="" float3="" finalcolor="tex2D(_MainTex," float2(finalraintex.x,="" finalraintex.y)).rgb;="" 【6】返回加上alpha分量的最終顏色值="" return="" fixed4(finalcolor,="" 1.0);="" }="" =="=========結(jié)束CG著色器語言編寫模塊===========" endcg="" }="">
屏幕特效Shader中真正有營養(yǎng)的核心代碼,一般都是位于像素著色器中。也就是這里的frag函數(shù)中,稍微聊一聊。
第一步,先從頂點(diǎn)著色器輸出結(jié)構(gòu)體中獲取頂點(diǎn)的坐標(biāo): //【1】獲取頂點(diǎn)的坐標(biāo)值float2 uv = Input.texcoord.xy; 第二步,因?yàn)樾枰患y理在屏幕中從上向下滾動(dòng),而不同平臺(tái)的原點(diǎn)位置是不同的,Direct3D原點(diǎn)在左上角,OpenGL原點(diǎn)在左下角。所以在這邊需要對(duì)情況進(jìn)行統(tǒng)一。 統(tǒng)一的方法里用到了UNITY_UV_STARTS_AT_TOP宏,它是Unity中內(nèi)置的宏,其值 取為1 或0 ; 在紋理 V 坐標(biāo)在“紋理頂部”為零的平臺(tái)上值取 1。如Direct3D;而OpenGL 平臺(tái)上取 0。 另外,這邊還用到了MainTex_TexelSize變量。 float2型的MainTex_TexelSize(其實(shí)是_TexelSize后綴,前面的名稱會(huì)根據(jù)定義紋理變量的改變而改變)也是Unity中內(nèi)置的一個(gè)變量,存放了紋理中單個(gè)像素的尺寸,也就是說,如果有一張2048 x 2048的紋理,那么x和y的取值都為1.0/2048.0。而且需要注意,當(dāng)該紋理被Direct3D的抗鋸齒操作垂直反轉(zhuǎn)過后,xxx_TexelSize的值將為負(fù)數(shù)。
所以,第二步的代碼就是如下: //【2】解決平臺(tái)差異的問題。校正方向,若和規(guī)定方向相反,則將速度反向并加1 #if UNITY_UV_STARTS_AT_TOP if(_MainTex_TexelSize.y < 0)="" _dropspeed="1" -="" _dropspeed;=""> 第三步,定義三層水流的紋理,按照不同的參數(shù)取值,進(jìn)行采樣: //【3】設(shè)置三層水流效果,按照一定的規(guī)律在水滴紋理上分別進(jìn)行取樣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; 第四步,整合一下三層水流效果的顏色信息,用一個(gè)float2型的變量存放下來: //【4】整合三層水流效果的顏色信息,存于finalRainTex中float2 finalRainTex = uv.xy - (rainTex1.xy - rainTex2.xy - rainTex3.xy) / 3;
第五步,自然是在屏幕所在的紋理_MainTex中進(jìn)行一次最終的采樣,算出最終結(jié)果顏色值,存放于float3型的finalColor中。 //【5】按照finalRainTex的坐標(biāo)信息,在主紋理上進(jìn)行采樣float3 finalColor = tex2D(_MainTex, float2(finalRainTex.x, finalRainTex.y)).rgb; 第六步,因?yàn)榉祷氐氖且粋€(gè)fixed4型的變量,rgba。所以需要給float3型的finalColor配上一個(gè)alpha分量,并返回: //【6】返回加上alpha分量的最終顏色值 return fixed4(finalColor, 1.0);
OK,關(guān)于此Shader的實(shí)現(xiàn)細(xì)節(jié),差不多就需要講到這些。下面再看一下C#腳本文件的實(shí)現(xiàn)。
4.2 C#腳本實(shí)現(xiàn)部分
C#腳本文件的實(shí)現(xiàn)并沒有什么好講的,唯一的地方,水滴紋理的載入,上面已經(jīng)提到過了,實(shí)現(xiàn)代碼如下: //載入素材圖 ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') asTexture2D; 下面就直接貼出詳細(xì)注釋的實(shí)現(xiàn)此特效的C#腳本:
//-----------------------------------------------【C#腳本說明】---------------------------------------------------// 屏幕水幕特效的實(shí)現(xiàn)代碼-C#腳本部分// 2015年10月 Created by 淺墨// 更多內(nèi)容或交流,請?jiān)L問淺墨的博客:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------using UnityEngine;using System.Collections;[ExecuteInEditMode][AddComponentMenu('淺墨Shader編程/Volume9/ScreenWaterDropEffect')]public class ScreenWaterDropEffect : MonoBehaviour { //-------------------變量聲明部分------------------- #region Variables //著色器和材質(zhì)實(shí)例 public Shader CurShader;//著色器實(shí)例 private Material CurMaterial;//當(dāng)前的材質(zhì) //時(shí)間變量和素材圖的定義 private float TimeX = 1.0f;//時(shí)間變量 private Texture2D ScreenWaterDropTex;//屏幕水滴的素材圖 //可以在編輯器中調(diào)整的參數(shù)值 [Range(5, 64), Tooltip('溶解度')] public float Distortion = 8.0f; [Range(0, 7), Tooltip('水滴在X坐標(biāo)上的尺寸')] public float SizeX = 1f; [Range(0, 7), Tooltip('水滴在Y坐標(biāo)上的尺寸')] public float SizeY = 0.5f; [Range(0, 10), Tooltip('水滴的流動(dòng)速度')] public float DropSpeed = 3.6f; //用于參數(shù)調(diào)節(jié)的中間變量 public static float ChangeDistortion; public static float ChangeSizeX; public static float ChangeSizeY; public static float ChangeDropSpeed; #endregion //-------------------------材質(zhì)的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ù)第一次被調(diào)用前被調(diào)用 //-------------------------------------------------------------------------------------------------------- void Start() { //依次賦值 ChangeDistortion = Distortion; ChangeSizeX = SizeX; ChangeSizeY = SizeY; ChangeDropSpeed = DropSpeed; //載入素材圖 ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') as Texture2D; //找到當(dāng)前的Shader文件 CurShader = Shader.Find('淺墨Shader編程/Volume9/ScreenWaterDropEffect'); //判斷是否支持屏幕特效 if (!SystemInfo.supportsImageEffects) { enabled = false; return; } } //-------------------------------------【OnRenderImage()函數(shù)】------------------------------------ // 說明:此函數(shù)在當(dāng)完成所有渲染圖片后被調(diào)用,用來渲染圖片后期效果 //-------------------------------------------------------------------------------------------------------- void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { //著色器實(shí)例不為空,就進(jìn)行參數(shù)設(shè)置 if (CurShader != null) { //時(shí)間的變化 TimeX += Time.deltaTime; //時(shí)間大于100,便置0,保證可以循環(huán) if (TimeX > 100) TimeX = 0; //設(shè)置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); //拷貝源紋理到目標(biāo)渲染紋理,加上我們的材質(zhì)效果 Graphics.Blit(sourceTexture, destTexture, material); } //著色器實(shí)例為空,直接拷貝屏幕上的效果。此情況下是沒有實(shí)現(xiàn)屏幕特效的 else { //直接拷貝源紋理到目標(biāo)渲染紋理 Graphics.Blit(sourceTexture, destTexture); } } //-----------------------------------------【OnValidate()函數(shù)】-------------------------------------- // 說明:此函數(shù)在編輯器中該腳本的某個(gè)值發(fā)生了改變后被調(diào)用 //-------------------------------------------------------------------------------------------------------- void OnValidate() { ChangeDistortion = Distortion; ChangeSizeX = SizeX; ChangeSizeY = SizeY; ChangeDropSpeed = DropSpeed; } //-----------------------------------------【Update()函數(shù)】------------------------------------------ // 說明:此函數(shù)在每一幀中都會(huì)被調(diào)用 //-------------------------------------------------------------------------------------------------------- void Update() { //若程序在運(yùn)行,進(jìn)行賦值 if (Application.isPlaying) { //賦值 Distortion = ChangeDistortion; SizeX = ChangeSizeX; SizeY = ChangeSizeY; DropSpeed = ChangeDropSpeed; } //找到對(duì)應(yīng)的Shader文件,和紋理素材#if UNITY_EDITOR if (Application.isPlaying != true) { CurShader = Shader.Find('淺墨Shader編程/Volume9/ScreenWaterDropEffect'); ScreenWaterDropTex = Resources.Load('ScreenWaterDrop') as Texture2D; }#endif } //-----------------------------------------【OnDisable()函數(shù)】--------------------------------------- // 說明:當(dāng)對(duì)象變?yōu)椴豢捎没蚍羌せ顮顟B(tài)時(shí)此函數(shù)便被調(diào)用 //-------------------------------------------------------------------------------------------------------- void OnDisable() { if (CurMaterial) { //立即銷毀材質(zhì)實(shí)例 DestroyImmediate(CurMaterial); } }} OK,水幕屏幕特效實(shí)現(xiàn)部分大致就是這樣,下面看一下運(yùn)行效果的對(duì)比。
五、最終的效果展示
貼幾張場景的效果圖和使用了屏幕特效后的效果圖。在試玩場景時(shí),除了類似CS/CF的FPS游戲控制系統(tǒng)以外,還可以使用鍵盤上的按鍵【F】,開啟或者屏幕特效。 本次的場景還是使用上次更新中放出的城鎮(zhèn),只是出生地點(diǎn)有所改變。為了有更多的時(shí)間專注于Shader書寫本身,以后的博文配套場景采取不定期大更新的形式(兩次、三次一換)。
城鎮(zhèn)野外(with 屏幕水幕特效): 城鎮(zhèn)野外(原始圖): 山坡上(with 屏幕水幕特效): 山坡上(原始圖): 城鎮(zhèn)中(with 屏幕水幕特效): 城鎮(zhèn)中(原始圖) 石橋上(with 屏幕水幕特效):
石橋上(原始圖):
本次的更新大致如此,感謝各位捧場,我們下周再見。
附: 本博文相關(guān)下載鏈接清單
【百度云】包含博文示例場景所有資源與源碼的unitypackage下載 另附:若遇到導(dǎo)入unitypackage過程中進(jìn)度條卡住的情況,不用慌,這是Unity5的一個(gè)bug。我也經(jīng)常在導(dǎo)入工程時(shí)遇到。其實(shí)這個(gè)時(shí)候已經(jīng)導(dǎo)入成功了,用資源管理器殺掉當(dāng)前這個(gè)Unity的進(jìn)程,再打開就行了。 |
|
|