unity之背景高斯模糊
1 local RenderTexture = CS.UnityEngine.RenderTexture
2 local Rect =CS.UnityEngine.Rect
3 local Screen =CS.UnityEngine.Screen
4 local Texture2D = CS.UnityEngine.Texture2D
5 local TextureFormat = CS.UnityEngine.TextureFormat
6 local GaussianBlurBg = {}
7
8 --主要思路:从屏幕读取像素 保存在texture2d中
9 --核心API:texture2d:ReadPixels(renderWidth, renderHeight, TextureFormat.RGB24, false, true)
10
11 ---输出图片
12 GaussianBlurBg.ExportTexture = function()
13 local cameraArr = GaussianBlurBg.GetCurrCamera()
14 local renderWidth,renderHeight = GaussianBlurBg.DrawingSize()
15 return GaussianBlurBg.ScreenCapture(cameraArr,renderWidth,renderHeight)
16 end
17
18 --获取相机组
19 GaussianBlurBg.GetCurrCamera = function()
20 local cameraArr = {}
21 local UIMgrIns = UIManager:Instance()
22 table.insert(cameraArr, UIMgrIns.UICamera)
23 table.insert(cameraArr, UIMgrIns.MainCamera)
24 return cameraArr
25 end
26
27 --算出渲染大小
28 GaussianBlurBg.DrawingSize = function()
29 --高宽比
30 local proportion = (Screen.height * 1.0 / Screen.width)
31 --乘以0.1 是为了更小
32 local renderWidth = math.min(100,math.ceil(Screen.width * 0.1))
33 --乘以高宽比是为了与原比例一致
34 local renderHeight = math.ceil(renderWidth * proportion)
35 return renderWidth,renderHeight
36 end
37
38 --屏幕读取像素渲染到一张图片上
39 GaussianBlurBg.ScreenCapture = function(cameraArr,renderWidth,renderHeight)
40 if cameraArr == nil or #cameraArr == nil then return nil end
41 local camerList,cameraMap,oldTargetTexture = {},{},{}
42 for _, v in pairs(cameraArr) do
43 if not IsNull(v) and cameraMap[v] == nil then
44 cameraMap[v] = v
45 table.insert(camerList, v)
46 end
47 end
48 if #camerList <= 0 then return nil end
49 if type(renderWidth) ~= "number" or renderWidth <= 0 then renderWidth = 100 end
50 if type(renderHeight) ~= "number" or renderHeight <= 0 then renderHeight = 100 end
51 local renderTex = RenderTexture.GetTemporary(renderWidth, renderHeight, 0)
52 --缓存原先的渲染相机及渲染目标
53 for _, came in pairs(camerList) do
54 if not IsNull(came) and came.gameObject.activeSelf then
55 table.insert(oldTargetTexture, { came = came, targetTexture = came.targetTexture })
56 came.targetTexture = renderTex
57 came:Render()
58 end
59 end
60 RenderTexture.active = renderTex
61 local _tex = Texture2D(renderWidth, renderHeight, TextureFormat.RGB24, false, true)
62 _tex:ReadPixels(Rect(0, 0, renderWidth, renderHeight), 0, 0)
63 _tex:Apply(false, false)
64 --要还原 否则丢失渲染目标
65 for _, v in pairs(oldTargetTexture) do
66 if not IsNull(v.came) then
67 v.came.targetTexture = v.targetTexture
68 end
69 end
70 RenderTexture.active = nil
71 RenderTexture.ReleaseTemporary(renderTex)
72 return _tex
73 end
74
75 exports.GaussianBlurBg = GaussianBlurBg
76 return GaussianBlurBg
模糊 shader
1 Shader "Effect/ImageBlur"
2 {
3 Properties
4 {
5 _MainTex("Texture", 2D) = "white" {}
6 //ugui mask
7 [HideInInspector]_StencilComp("Stencil Comparison", Float) = 8
8 [HideInInspector]_Stencil("Stencil ID", Float) = 0
9 [HideInInspector]_StencilOp("Stencil Operation", Float) = 0
10 [HideInInspector]_StencilWriteMask("Stencil Write Mask", Float) = 255
11 [HideInInspector]_StencilReadMask("Stencil Read Mask", Float) = 255
12 [HideInInspector]_ColorMask("Color Mask", Float) = 15
13 //================================================================================
14 _BlurSize("Blur Size", Float) = 2
15 _Brightness("Brightness", Float) = 1 //调整亮度
16 _Saturation("Saturation", Float) = 1 //调整饱和度
17 _Contrast("Contrast", Float) = 1 //调整对比度
18 }
19
20 CGINCLUDE
21
22 #include "UnityCG.cginc"
23
24 sampler2D _MainTex;
25 uniform half4 _MainTex_TexelSize;
26 uniform float _BlurSize;
27 half _Brightness;
28 half _Saturation;
29 half _Contrast;
30
31 static const half weight[4] = { 0.0205, 0.0855, 0.232, 0.324 };
32 static const half4 coordOffset = half4(1.0h, 1.0h, -1.0h, -1.0h);
33
34 struct appdata_t
35 {
36 float4 vertex : POSITION;
37 float4 color : COLOR;
38 float2 texcoord : TEXCOORD0;
39 };
40
41 struct v2f_blurSGX
42 {
43 float4 pos:SV_POSITION;
44 half2 uv:TEXCOORD0;
45 float4 color : COLOR;
46 half4 blurFactor:TEXCOORD1;
47 };
48
49 v2f_blurSGX vert_BlurHorizontal(appdata_t v)
50 {
51 v2f_blurSGX o;
52 o.pos = UnityObjectToClipPos(v.vertex);
53 o.uv = v.texcoord.xy;
54 o.blurFactor.xy = _MainTex_TexelSize.xy * 2 * _BlurSize;
55 o.color = v.color;
56 return o;
57 }
58
59
60 fixed4 Tex2DBlurring(sampler2D tex, half2 texcood, half2 blur)
61 {
62 //快速模糊
63 //const int KERNEL_SIZE = 3;
64 //const float KERNEL_[3] = { 0.4566, 1.0, 0.4566 };
65
66 //中等模糊
67 //const int KERNEL_SIZE = 5;
68 //const float KERNEL_[5] = { 0.2486, 0.7046, 1.0, 0.7046, 0.2486 };
69
70 //高级模糊
71 const int KERNEL_SIZE = 7;
72 const float KERNEL_[7] = { 0.1719, 0.4566, 0.8204, 1.0, 0.8204, 0.4566, 0.1719 };
73 float4 o = 0;
74 float sum = 0;
75 float2 shift = 0;
76 for (int x = 0; x < KERNEL_SIZE; x++)
77 {
78 shift.x = blur.x * (float(x) - KERNEL_SIZE / 2);
79 for (int y = 0; y < KERNEL_SIZE; y++)
80 {
81 shift.y = blur.y * (float(y) - KERNEL_SIZE / 2);
82 float2 uv = texcood + shift;
83 float weight = KERNEL_[x] * KERNEL_[y];
84 sum += weight;
85 uv.x = clamp(uv.x, 0.02, 0.98);
86 uv.y = clamp(uv.y, 0.02, 0.98);
87 o += tex2D(tex, uv) * weight;
88 }
89 }
90 fixed4 renderTex = (o / sum);
91 //brigtness亮度直接乘以一个系数,也就是RGB整体缩放,调整亮度
92 fixed3 finalColor = renderTex * _Brightness;
93 //saturation饱和度:首先根据公式计算同等亮度情况下饱和度最低的值:
94 fixed gray = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
95 fixed3 grayColor = fixed3(gray, gray, gray);
96 //根据Saturation在饱和度最低的图像和原图之间差值
97 finalColor = lerp(grayColor, finalColor, _Saturation);
98 //contrast对比度:首先计算对比度最低的值
99 fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
100 //根据Contrast在对比度最低的图像和原图之间差值
101 finalColor = lerp(avgColor, finalColor, _Contrast);
102 //返回结果,alpha通道不变
103 return fixed4(finalColor, renderTex.a);
104 }
105
106 fixed4 frag_Blur(v2f_blurSGX i) :SV_Target
107 {
108 fixed4 color = Tex2DBlurring(_MainTex,i.uv,i.blurFactor.xy);
109 color.a = i.color.a;
110 return color;
111 }
112
113
114 ENDCG
115
116 SubShader
117 {
118 //ugui mask No culling or depth
119 Cull Off ZWrite Off
120 Stencil
121 {
122 Ref[_Stencil]
123 Comp[_StencilComp]
124 Pass[_StencilOp]
125 ReadMask[_StencilReadMask]
126 WriteMask[_StencilWriteMask]
127 }
128
129 Fog{ Mode Off }
130 Blend SrcAlpha OneMinusSrcAlpha
131 ColorMask[_ColorMask]
132
133 Pass
134 {
135 CGPROGRAM
136 #pragma vertex vert_BlurHorizontal
137 #pragma fragment frag_Blur
138 ENDCG
139 }
140 }
141 }
用法:
1.创建一个材质球 ,把 ImageBlur.shader 挂上
2.加一个Raw Image 组件,GaussianBlurBg.ExportTexture 获取的值 赋值给 Raw Image的 texture 属性
效果:
总结知识点:
1.CS.UnityEngine.RenderTexture.GetTemporary:系统api 获取临时渲染纹理
public static RenderTexture GetTemporary(int width, int height, int depthBuffer);
参数width、height 不能小于等于0
2.Camera.targetTexture 给摄像机设置渲染图片
3.Camera:Render() 手动渲染摄像机
4.Texture2D
5.Texture2D:ReadPixels // ReadPixels 从屏幕读取像素保存到纹理数据中
6.Texture2D:Apply() 对上述更改的应用
public void Apply([DefaultValue("true")] bool updateMipmaps, [DefaultValue("false")] bool makeNoLongerReadable);
7.Rendertexture的分配和销毁上有一个地方需要注意:
如果频繁的要new一个rt出来,不要直接new,而是使用RenderTexture提供的GetTemporary和ReleaseTemporary,
它将在内部维护一个池,反复重用一些大小格式一样的rt资源,因为让GPU为你分配一个新的texture其实是要耗时间的。