Unity3D UGUI特效之Image高斯模糊效果
程序员文章站
2023-11-17 14:39:40
这几天研究了下模糊特效,看了很多文章,其原理就是拿取图片或屏幕数据,然后将周围的元素和目标位置的颜色值进行一个融合计算,然后自己写了一个小小的测试程序。
这个模糊也可以分...
这几天研究了下模糊特效,看了很多文章,其原理就是拿取图片或屏幕数据,然后将周围的元素和目标位置的颜色值进行一个融合计算,然后自己写了一个小小的测试程序。
这个模糊也可以分成两种,一个是自身模糊,一个是从屏幕上取值进行模糊。第一个用于一些小的列表展示,比如未解锁时,是模糊的。第二个是凸显弹框效果的,将背景都模糊掉,自己将这个稍微加强了些可以指定模糊一个位置。
针对移动平台,使用高斯模糊,其实效率不是很高,如果要很好的效果,那么速度卡;如果要速度快,那么效果达不到要求。但是还是在这里记录下,兴许以后能用上。
先说第一个,挂在image下的模糊特效。
shader "custom/frontblur" { properties { [perrendererdata] _maintex ("sprite texture", 2d) = "white" {} _color ("tint", color) = (1,1,1,1) [hideininspector]_stencilcomp ("stencil comparison", float) = 8 [hideininspector]_stencil ("stencil id", float) = 0 [hideininspector]_stencilop ("stencil operation", float) = 0 [hideininspector]_stencilwritemask ("stencil write mask", float) = 255 [hideininspector]_stencilreadmask ("stencil read mask", float) = 255 [hideininspector]_colormask ("color mask", float) = 15 [toggle(unity_ui_alphaclip)] _useuialphaclip ("use alpha clip", float) = 0 _size ("size", range(0, 50)) = 5 } subshader { tags { "queue"="transparent" "ignoreprojector"="true" "rendertype"="transparent" "previewtype"="plane" "canusespriteatlas"="true" } stencil { ref [_stencil] comp [_stencilcomp] pass [_stencilop] readmask [_stencilreadmask] writemask [_stencilwritemask] } cull off lighting off zwrite off ztest [unity_guiztestmode] blend srcalpha oneminussrcalpha colormask [_colormask] pass { name "frontblurhor" cgprogram #pragma vertex vert #pragma fragment frag #pragma target 2.0 #include "unitycg.cginc" #include "unityui.cginc" #pragma multi_compile __ unity_ui_alphaclip struct appdata_t { float4 vertex : position; float4 color : color; float2 texcoord : texcoord0; unity_vertex_input_instance_id }; struct v2f { float4 vertex : sv_position; fixed4 color : color; float2 texcoord : texcoord0; float4 worldposition : texcoord1; unity_vertex_output_stereo }; fixed4 _color; fixed4 _texturesampleadd; float4 _cliprect; v2f vert(appdata_t in) { v2f out; unity_setup_instance_id(in); unity_initialize_vertex_output_stereo(out); out.worldposition = in.vertex; out.vertex = unityobjecttoclippos(out.worldposition); out.texcoord = in.texcoord; out.color = in.color * _color; return out; } sampler2d _maintex; float4 _maintex_texelsize; float _size; half4 grabpixel(v2f i, float weight, float kernelx){ if (_size <= 1 || weight == 0){ return tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size, i.texcoord.y)) * weight; }else{ half4 sum = half4(0,0,0,0); sum += tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size*0.2, i.texcoord.y))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size*0.4, i.texcoord.y))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size*0.6, i.texcoord.y))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size*0.8, i.texcoord.y))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x + _maintex_texelsize.x*kernelx*_size*1.0, i.texcoord.y))*0.2; return (sum + _texturesampleadd) * weight; } } half4 grabpixely(v2f i, float weight, float kernely){ if (_size <= 1 || weight == 0){ return tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size)) * weight; }else{ half4 sum = half4(0,0,0,0); sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.2))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.4))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.6))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.8))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*1.0))*0.2; return (sum + _texturesampleadd) * weight; } } fixed4 frag(v2f in) : sv_target { half4 sum = half4(0,0,0,0); // #define grabpixel(weight, kernelx) (tex2d(_maintex, half2(in.texcoord.x + _maintex_texelsize.x * kernelx*_size, in.texcoord.y)) + _texturesampleadd) * weight // sum += grabpixel(in, 0.05, -4.0); // sum += grabpixel(in, 0.09, -3.0); // sum += grabpixel(in, 0.12, -2.0); // sum += grabpixel(in, 0.15, -1.0); // sum += grabpixel(in, 0.18, 0.0); // sum += grabpixel(in, 0.15, +1.0); // sum += grabpixel(in, 0.12, +2.0); // sum += grabpixel(in, 0.09, +3.0); // sum += grabpixel(in, 0.05, +4.0); for(int i=0;i<9;i++){ sum += grabpixel(in, 1.0/9, i-4.0); } // half4 sumy = half4(0,0,0,0); // for(int i=0;i<15;i++){ // sumy += grabpixely(in, 1.0/15, i-7.0); // } // half4 sum = (sumx + sumy) * 0.5; // sum += grabpixel(in, 0.01, -9.0); // sum += grabpixel(in, 0.02, -8.0); // sum += grabpixel(in, 0.03, -7.0); // sum += grabpixel(in, 0.04, -6.0); // sum += grabpixel(in, 0.05, -5.0); // sum += grabpixel(in, 0.06, -4.0); // sum += grabpixel(in, 0.07, -3.0); // sum += grabpixel(in, 0.08, -2.0); // sum += grabpixel(in, 0.09, -1.0); // sum += grabpixel(in, 0.10, 0.0); // sum += grabpixel(in, 0.09, +1.0); // sum += grabpixel(in, 0.08, +2.0); // sum += grabpixel(in, 0.07, +3.0); // sum += grabpixel(in, 0.06, +4.0); // sum += grabpixel(in, 0.05, +5.0); // sum += grabpixel(in, 0.04, +6.0); // sum += grabpixel(in, 0.03, +7.0); // sum += grabpixel(in, 0.02, +8.0); // sum += grabpixel(in, 0.01, +9.0); sum = sum * in.color; sum.a *= unityget2dclipping(in.worldposition.xy, _cliprect); #ifdef unity_ui_alphaclip clip (sum.a - 0.001); #endif return sum; // float distance = _distance; // fixed4 color = (tex2d(_maintex, in.texcoord) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color /= 9; // color.a *= unityget2dclipping(in.worldposition.xy, _cliprect); // #ifdef unity_ui_alphaclip // clip (color.a - 0.001); // #endif // return color; } endcg } pass { name "frontblurver" cgprogram #pragma vertex vert #pragma fragment frag #pragma target 2.0 #include "unitycg.cginc" #include "unityui.cginc" #pragma multi_compile __ unity_ui_alphaclip struct appdata_t { float4 vertex : position; float4 color : color; float2 texcoord : texcoord0; unity_vertex_input_instance_id }; struct v2f { float4 vertex : sv_position; fixed4 color : color; float2 texcoord : texcoord0; float4 worldposition : texcoord1; unity_vertex_output_stereo }; fixed4 _color; fixed4 _texturesampleadd; float4 _cliprect; v2f vert(appdata_t in) { v2f out; unity_setup_instance_id(in); unity_initialize_vertex_output_stereo(out); out.worldposition = in.vertex; out.vertex = unityobjecttoclippos(out.worldposition); out.texcoord = in.texcoord; out.color = in.color * _color; return out; } sampler2d _maintex; float4 _maintex_texelsize; float _size; half4 grabpixel(v2f i, float weight, float kernely){ if (_size <= 1 || weight == 0){ return tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size)) * weight; }else{ half4 sum = half4(0,0,0,0); sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.2))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.4))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.6))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*0.8))*0.2; sum += tex2d(_maintex, half2(i.texcoord.x, i.texcoord.y + _maintex_texelsize.y*kernely*_size*1.0))*0.2; return (sum + _texturesampleadd) * weight; } } fixed4 frag(v2f in) : sv_target { half4 sum = half4(0,0,0,0); // #define grabpixel(weight, kernely) (tex2d(_maintex, half2(in.texcoord.x, in.texcoord.y + _maintex_texelsize.y * kernely*_size)) + _texturesampleadd) * weight // sum += grabpixel(in, 0.05, -4.0); // sum += grabpixel(in, 0.09, -3.0); // sum += grabpixel(in, 0.12, -2.0); // sum += grabpixel(in, 0.15, -1.0); // sum += grabpixel(in, 0.18, 0.0); // sum += grabpixel(in, 0.15, +1.0); // sum += grabpixel(in, 0.12, +2.0); // sum += grabpixel(in, 0.09, +3.0); // sum += grabpixel(in, 0.05, +4.0); for(int i=0;i<9;i++){ sum += grabpixel(in, 1.0/9, i-4.0); } // sum += grabpixel(in, 0.01, -9.0); // sum += grabpixel(in, 0.02, -8.0); // sum += grabpixel(in, 0.03, -7.0); // sum += grabpixel(in, 0.04, -6.0); // sum += grabpixel(in, 0.05, -5.0); // sum += grabpixel(in, 0.06, -4.0); // sum += grabpixel(in, 0.07, -3.0); // sum += grabpixel(in, 0.08, -2.0); // sum += grabpixel(in, 0.09, -1.0); // sum += grabpixel(in, 0.10, 0.0); // sum += grabpixel(in, 0.09, +1.0); // sum += grabpixel(in, 0.08, +2.0); // sum += grabpixel(in, 0.07, +3.0); // sum += grabpixel(in, 0.06, +4.0); // sum += grabpixel(in, 0.05, +5.0); // sum += grabpixel(in, 0.04, +6.0); // sum += grabpixel(in, 0.03, +7.0); // sum += grabpixel(in, 0.02, +8.0); // sum += grabpixel(in, 0.01, +9.0); sum = sum * in.color; sum.a *= unityget2dclipping(in.worldposition.xy, _cliprect); #ifdef unity_ui_alphaclip clip (sum.a - 0.001); #endif return sum; // float distance = _distance; // fixed4 color = (tex2d(_maintex, in.texcoord) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x + distance, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y - distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x - distance, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color += (tex2d(_maintex, half2(in.texcoord.x, in.texcoord.y + distance)) + _texturesampleadd) * in.color; // color /= 9; // color.a *= unityget2dclipping(in.worldposition.xy, _cliprect); // #ifdef unity_ui_alphaclip // clip (color.a - 0.001); // #endif // return color; } endcg } } }
里面分了两个pass来计算,这样算出的效果会好很多,然后里面试了跟多的计算,越多的分层,那么得到的效果也越高,也意味着更加的不流畅。将shader放到一个新建的材质球上,然后把材质拖到image组件的material属性栏上就可以了。
看看效果:
然后说第二个方式,它是将背景都给模糊的效果。
shader "custom/backblur" { properties { [perrendererdata] _maintex ("sprite texture", 2d) = "white" {} _color ("main color", color) = (1,1,1,1) _size ("size", range(0, 20)) = 1 } category { // we must be transparent, so other objects are drawn before this one. tags { "queue"="transparent" "ignoreprojector"="true" "rendertype"="transparent" "previewtype" = "plane" "canusespriteatlas" = "true" } subshader { // horizontal blur grabpass { tags { "lightmode" = "always" } } pass { tags { "lightmode" = "always" } name "backblurhor" cgprogram #pragma vertex vert #pragma fragment frag #pragma fragmentoption arb_precision_hint_fastest #include "unitycg.cginc" struct appdata_t { float4 vertex : position; float2 texcoord : texcoord0; float4 color : color; }; struct v2f { float4 vertex : position; float4 uvgrab : texcoord0; float4 color : color; }; v2f vert (appdata_t v) { v2f o; o.vertex = unityobjecttoclippos(v.vertex); #if unity_uv_starts_at_top float scale = -1.0; #else float scale = 1.0; #endif o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5; o.uvgrab.zw = o.vertex.zw; o.color = v.color; return o; } sampler2d _grabtexture; float4 _grabtexture_texelsize; float4 _maintex_texelsize; float _size; uniform float4 _color; // static float gaussiankernel[9] = { // 0.05, 0.09, 0.12, // 0.15, 0.18, 0.15, // 0.12, 0.09, 0.05 // }; // static float gaussiankernel[19] = { // 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, // 0.1, // 0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01, // }; // static float gaussiankerneld[19] = { // -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, // 0.0, // +1.0, +2.0, +3.0, +4.0, +5.0, +6.0, +7.0, +8.0, +9.0, // }; half4 grabpixel(v2f i, float weight, float kernelx){ if (i.uvgrab.x == 0 && i.uvgrab.y == 0){ kernelx = 0; } return tex2dproj(_grabtexture, unity_proj_coord(float4(i.uvgrab.x + _grabtexture_texelsize.x*kernelx*_size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight; } half4 frag( v2f i ) : color { half4 sum = half4(0,0,0,0); // #define grabpixel(weight, kernelx) tex2dproj(_grabtexture, unity_proj_coord(float4(i.uvgrab.x + _grabtexture_texelsize.x * kernelx*_size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight sum += grabpixel(i, 0.05, -4.0); sum += grabpixel(i, 0.09, -3.0); sum += grabpixel(i, 0.12, -2.0); sum += grabpixel(i, 0.15, -1.0); sum += grabpixel(i, 0.18, 0.0); sum += grabpixel(i, 0.15, +1.0); sum += grabpixel(i, 0.12, +2.0); sum += grabpixel(i, 0.09, +3.0); sum += grabpixel(i, 0.05, +4.0); // sum += grabpixel(i, 0.01, -9.0); // sum += grabpixel(i, 0.02, -8.0); // sum += grabpixel(i, 0.03, -7.0); // sum += grabpixel(i, 0.04, -6.0); // sum += grabpixel(i, 0.05, -5.0); // sum += grabpixel(i, 0.06, -4.0); // sum += grabpixel(i, 0.07, -3.0); // sum += grabpixel(i, 0.08, -2.0); // sum += grabpixel(i, 0.09, -1.0); // sum += grabpixel(i, 0.10, 0.0); // sum += grabpixel(i, 0.09, +1.0); // sum += grabpixel(i, 0.08, +2.0); // sum += grabpixel(i, 0.07, +3.0); // sum += grabpixel(i, 0.06, +4.0); // sum += grabpixel(i, 0.05, +5.0); // sum += grabpixel(i, 0.04, +6.0); // sum += grabpixel(i, 0.03, +7.0); // sum += grabpixel(i, 0.02, +8.0); // sum += grabpixel(i, 0.01, +9.0); float4 col5 = tex2dproj(_grabtexture, unity_proj_coord(i.uvgrab)); float decayfactor = 1.0f; if (i.uvgrab.x == 0 && i.uvgrab.y == 0){ decayfactor = 0; } sum = lerp(col5, sum, decayfactor) * i.color * _color; return sum; } endcg } // vertical blur grabpass { tags { "lightmode" = "always" } } pass { tags { "lightmode" = "always" } name "backblurver" cgprogram #pragma vertex vert #pragma fragment frag #pragma fragmentoption arb_precision_hint_fastest #include "unitycg.cginc" struct appdata_t { float4 vertex : position; float2 texcoord: texcoord0; float4 color : color; }; struct v2f { float4 vertex : position; float4 uvgrab : texcoord0; float4 color : color; }; v2f vert (appdata_t v) { v2f o; o.vertex = unityobjecttoclippos(v.vertex); #if unity_uv_starts_at_top float scale = -1.0; #else float scale = 1.0; #endif o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5; o.uvgrab.zw = o.vertex.zw; o.color = v.color; return o; } sampler2d _grabtexture; float4 _grabtexture_texelsize; float _size; uniform float4 _color; half4 grabpixel(v2f i, float weight, float kernely){ if (i.uvgrab.x == 0 && i.uvgrab.y == 0){ kernely = 0; } return tex2dproj( _grabtexture, unity_proj_coord(float4(i.uvgrab.x, i.uvgrab.y + _grabtexture_texelsize.y*kernely*_size, i.uvgrab.z, i.uvgrab.w))) * weight; } half4 frag( v2f i ) : color { half4 sum = half4(0,0,0,0); // #define grabpixel(weight,kernely) tex2dproj( _grabtexture, unity_proj_coord(float4(i.uvgrab.x, i.uvgrab.y + _grabtexture_texelsize.y * kernely*_size, i.uvgrab.z, i.uvgrab.w))) * weight sum += grabpixel(i, 0.05, -4.0); sum += grabpixel(i, 0.09, -3.0); sum += grabpixel(i, 0.12, -2.0); sum += grabpixel(i, 0.15, -1.0); sum += grabpixel(i, 0.18, 0.0); sum += grabpixel(i, 0.15, +1.0); sum += grabpixel(i, 0.12, +2.0); sum += grabpixel(i, 0.09, +3.0); sum += grabpixel(i, 0.05, +4.0); // sum += grabpixel(i, 0.01, -9.0); // sum += grabpixel(i, 0.02, -8.0); // sum += grabpixel(i, 0.03, -7.0); // sum += grabpixel(i, 0.04, -6.0); // sum += grabpixel(i, 0.05, -5.0); // sum += grabpixel(i, 0.06, -4.0); // sum += grabpixel(i, 0.07, -3.0); // sum += grabpixel(i, 0.08, -2.0); // sum += grabpixel(i, 0.09, -1.0); // sum += grabpixel(i, 0.10, 0.0); // sum += grabpixel(i, 0.09, +1.0); // sum += grabpixel(i, 0.08, +2.0); // sum += grabpixel(i, 0.07, +3.0); // sum += grabpixel(i, 0.06, +4.0); // sum += grabpixel(i, 0.05, +5.0); // sum += grabpixel(i, 0.04, +6.0); // sum += grabpixel(i, 0.03, +7.0); // sum += grabpixel(i, 0.02, +8.0); // sum += grabpixel(i, 0.01, +9.0); float4 col5 = tex2dproj(_grabtexture, unity_proj_coord(i.uvgrab)); float decayfactor = 1.0f; if (i.uvgrab.x == 0 && i.uvgrab.y == 0){ decayfactor = 0; } sum = lerp(col5, sum, decayfactor) * i.color * _color; return sum; } endcg } } } }
计算是一样的,不过这个相对来说要慢,毕竟是将整个屏幕那来计算的,肯定会慢很多。用法也一样,shader放到一个新建的材质球上,然后将材质球拖到一个image组件的material属性栏中即可,这里你可以调整image的宽高,这样可以指定模糊那一块区域了。
看效果:
然后我移动和调整宽高之后:
当然也可以调成整屏模糊:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Unity3D UGUI实现缩放循环拖动卡牌展示效果
下一篇: Unity3D实现扭动挤压浏览效果