找回密码
 注册帐号

扫一扫,访问微社区

士郎 Unity Shader之磨砂玻璃与水雾玻璃效果

17
回复
1166
查看
[ 复制链接 ]
排名
1
昨日变化

7841

主题

8399

帖子

3万

积分

Rank: 16

UID
1231
好友
186
蛮牛币
11068
威望
30
注册时间
2013-7-29
在线时间
4023 小时
最后登录
2019-6-18

活力之星原创精华达人突出贡献奖财富之证游戏蛮牛QQ群会员蛮牛妹VIP

2019-5-29 11:07:58 显示全部楼层 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
1.png




玻璃效果是游戏场景中常见的效果之一,除却普通的透明玻璃外,磨砂玻璃也是较为常见的效果。玻璃与场景中的其他物体也会有交互,例如,浴室中的玻璃、雨天的窗户会在水汽的作用下带有一定差别的雾效。本文以Unity Frosted Glass项目与开源库中相关项目为例,介绍磨砂玻璃的做法和在移动端运行的性能。


开源库链接:https://lab.uwa4d.com/lab/5b5613a3d7f10a201fd80bbb


模糊效果

磨砂玻璃的效果特点是模糊与半透明,该项目通过自定义的卷积实现来达到模糊效果。具体代码实现在FrostedGlass.shader中。
[AppleScript] 纯文本查看 复制代码
//vertex to fragment    
struct v2f {
  float4 pos : POSITION;
  float2 uv : TEXCOORD0;
  float4 uv01 : TEXCOORD1;
  float4 uv23 : TEXCOORD2;
  float4 uv45 : TEXCOORD3;
};

v2f vert (appdata_img v) {
  v2f o;
  o.pos = UnityObjectToClipPos(v.vertex);
  o.uv.xy = v.texcoord.xy;
  o.uv01 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1);
  o.uv23 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 2.0;
  o.uv45 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 3.0;
  return o;
}


(顶点着色器及相关数据结构SeparableGlassBlur.shader)

offsets是一个float4类型的定值,表示偏移量。通过顶点着色器的运算,输出的v2f结构体中,pos存储了该顶点从Object Space转换到相机裁剪空间中的齐次坐标。uv、uv01、uv23、uv45分别储存了该顶点、偏移量为offsets的两个顶点、偏移量为2*offsets的两个顶点、偏移量为3*offsets的两个顶点的uv坐标。
[AppleScript] 纯文本查看 复制代码
half4 frag (v2f i) : COLOR {
  half4 color = float4 (0,0,0,0);
  color += 0.40 * tex2D (_MainTex, i.uv);
  color += 0.15 * tex2D (_MainTex, i.uv01.xy);
  color += 0.15 * tex2D (_MainTex, i.uv01.zw);
  color += 0.10 * tex2D (_MainTex, i.uv23.xy);
  color += 0.10 * tex2D (_MainTex, i.uv23.zw);
  color += 0.05 * tex2D (_MainTex, i.uv45.xy);
  color += 0.05 * tex2D (_MainTex, i.uv45.zw);
  return color;
}


(片元着色器SeparableGlassBlur.shader)

该卷积核的一维权重分布如下表所示:

1.png

[AppleScript] 纯文本查看 复制代码
(进行滤波操作 CommandBufferBlur.cs)_CommandBuffer.SetGlobalVector("offsets", new Vector4(2.0f / sizes[i].x, 0, 0, 0));[/align]
[align=left]_CommandBuffer.Blit(blurredID, blurredID2, _Material);[/align]
[align=left]_CommandBuffer.SetGlobalVector("offsets", new Vector4(0, 2.0f / sizes[i].y, 0, 0));[/align]
[align=left]_CommandBuffer.Blit(blurredID2, blurredID, _Material);



对图像使用水平方向一维卷积核与竖直方向一维卷积核进行两次滤波得到最终的图像。等同于如下图所示的二维卷积核进行滤波:

1.png


1.png
(使用水平方向的一维卷积核对图像进行滤波CommandBufferBlur.cs)

1.png
(两次滤波后得到模糊效果)

卷积核的选择有很多种,其中较为常用的有高斯模糊、kawase Blur,开源库中有相关的项目实现了相关效果,例如:Blur for Unity、Gaussian Blur、Super Blur。

高斯模糊

这些模糊方式,所采用的卷积核各不相同,有兴趣的读者可以进行相关试验。

捕捉屏幕纹理

实现模糊效果后,需要捕捉到玻璃后方的屏幕效果图片交予模糊效果着色器进行处理。在Unity Shader中有一种特殊的Pass:GrabPass,可以很方便地获取屏幕图像。但这种方式开销太大,并不适合在移动端运行。

该项目采取CommandBuffer来达到这一目的。可以节省开销、提高性能。
[AppleScript] 纯文本查看 复制代码
//创建名为“Blur screen”的CommandBuffer
_CommandBuffer = new CommandBuffer();
_CommandBuffer.name = "Blur screen";


int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
//新建一个临时RenderTexture
_CommandBuffer.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear, _TextureFormat);
//获取当前屏幕图像
_CommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);
int blurredID = Shader.PropertyToID("_Grab" + i + "_Temp1");
int blurredID2 = Shader.PropertyToID("_Grab" + i + "_Temp2");
_CommandBuffer.GetTemporaryRT(blurredID, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
_CommandBuffer.GetTemporaryRT(blurredID2, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
_CommandBuffer.Blit(screenCopyID, blurredID);
_CommandBuffer.ReleaseTemporaryRT(screenCopyID);


(获取屏幕图像CommandBufferBlur.cs)

但此时获取到的图像是一整张屏幕图象,而我们需要进行模糊处理的图像,只有玻璃模型背后的图像,这时我们需要在顶点着色器中对顶点进行处理。
[AppleScript] 纯文本查看 复制代码
v2f vert (appdata v)
{
  v2f o;
  o.vertex = UnityObjectToClipPos(v.vertex);
  //确保材质球中的缩放和偏移位置正确
  o.uvfrost = TRANSFORM_TEX(v.uv, _FrostTex);
  //获得该顶点在屏幕图象中正确的纹理坐标
  o.uvgrab = ComputeGrabScreenPos(o.vertex);
  return o;
}


Unity内置的ComputeGrabScreenPos函数,帮助我们完成了坐标转换,根据o.uvgrab在屏幕图像中采集到的图像信息,便是玻璃模型背后的屏幕图像:


[AppleScript] 纯文本查看 复制代码
half4 ref00=tex2Dproj(_GrabBlurTexture_0,i.uvgrab);


将CommandBuffer挂载到相机上,实现实时更新渲染。


[AppleScript] 纯文本查看 复制代码
_Camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);


1.png
(效果图)

水雾玻璃

在磨砂玻璃的基础上,进一步拓展其他的特殊效果。

浴室中的玻璃、雨天的窗户会在水汽的作用下带有一定差别的雾效。这种效果的特点除却模糊与半透明外,还会有模糊程度的差别。
[AppleScript] 纯文本查看 复制代码
Vector2[] sizes = {
  new Vector2(Screen.width, Screen.height),
  new Vector2(Screen.width / 2, Screen.height / 2),
  new Vector2(Screen.width / 4, Screen.height / 4),
  new Vector2(Screen.width / 8, Screen.height / 8),
};


(定义不同大小的偏移量CommandBufferBlur.cs)

定义不同大小的偏移量,通过SeparableGlassBlur.shader的运算,得到四张模糊程度不同的屏幕图像,由0~3模糊程度加深:
[AppleScript] 纯文本查看 复制代码
sampler2D _GrabBlurTexture_0;
        sampler2D _GrabBlurTexture_1;
        sampler2D _GrabBlurTexture_2;
        sampler2D _GrabBlurTexture_3;


制定采样规则从这四张模糊程度不同的屏幕图像中进行采集,为了让过渡圆滑,使用lerp函数进行插值。加载一张效果灰度图(_FrostTex),确定雾效差别的强度(_FrostIntensity):
[AppleScript] 纯文本查看 复制代码
fixed4 frag (v2f i) : SV_Target
{
  float surfSmooth = 1 - tex2D(_FrostTex, i.uvfrost)* _FrostIntensity;
  //如果x 值小于 a,则返回a;如果 x 值大于 b,返回b;否则,返回 x
  surfSmooth = clamp(0, 1, surfSmooth);
  half4 refraction;
  //二维纹理投影映射
  half4 ref00 = tex2Dproj(_GrabBlurTexture_0, i.uvgrab);
  half4 ref01 = tex2Dproj(_GrabBlurTexture_1, i.uvgrab);
  half4 ref02 = tex2Dproj(_GrabBlurTexture_2, i.uvgrab);
  half4 ref03 = tex2Dproj(_GrabBlurTexture_3, i.uvgrab);
  //进行平滑过渡
  float step00 = smoothstep(0.75, 1.00, surfSmooth);
  float step01 = smoothstep(0.5, 0.75, surfSmooth);
  float step02 = smoothstep(0.05, 0.5, surfSmooth);
  refraction = lerp(lerp(lerp(ref03, ref02, step02), ref01, step01), ref00, step00);               
  return refraction;
}


(片元着色器FrostedGlass.shader)

项目中以_FrostTex图像中r值作为采样依据。根据1-r值*_FrostIntensity得到的数值(surfSmooth)为权重,分别从上述四张模糊程度不同的屏幕图像中进行采集,最后得到该顶点最终的颜色。

以下图作为效果图,验证不同的surfSmooth大小,渲染得到不同的模糊程度:

1.jpg
(从左至右R值依次为:0,0.25,0.5,0.75,1)

1.png
(效果图)

由此可以模拟出不同的水雾玻璃效果:

1.png
(有点脏的雾玻璃)

1.png
(覆盖着一层小水珠)

性能测试(使用UWA GOT Online工具测评)

选择低端机型红米4x进行测试(不开启多线程渲染):

使用水雾玻璃效果:

1.png

FPS均值为26帧:

1.png

Camera.Render函数耗时11ms左右开销不大:

1.png

可以看到CPU等待GPU渲染完成时间较长,当前渲染压力在GPU端:

1.png

可见实时抓取屏幕图片并进行渲染操作在移动端开销还是巨大的。该效果生成四张模糊效果图片,每张图片的生成通过了两次SeparableGlassBlur.shader的计算。最终每个顶点在FrostedGlass.shader中进行运算。GPU计算量过大。

只使用磨砂玻璃效果时,红米4xFPS均值为42帧左右。

1.png

此时只生成一张模糊效果图片,该图片的生成通过了两次SeparableGlassBlur.shader的计算。相比较而言GPU端计算大幅减少,CPU等待时间缩短,性能提升明显。


故而开发者在实现此效果时,需要在性能与效果之间平衡,尽可能减少计算量,例如可以使用3x3的卷积核,而不是5x5的,可以在采样之前做判断,减少采样次数。

来源:UWA
回复

使用道具 举报

7日久生情
2808/5000
排名
2230
昨日变化

1

主题

1809

帖子

2808

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
119154
好友
0
蛮牛币
3029
威望
0
注册时间
2015-8-21
在线时间
368 小时
最后登录
2019-6-18
2019-5-29 13:14:42 显示全部楼层
谢谢楼主大大。
回复

使用道具 举报

排名
48132
昨日变化

0

主题

43

帖子

61

积分

Rank: 2Rank: 2

UID
116528
好友
0
蛮牛币
19
威望
0
注册时间
2015-8-4
在线时间
14 小时
最后登录
2019-6-12
2019-5-29 14:21:17 显示全部楼层
感谢楼主分享哈,学些学习!
回复 支持 反对

使用道具 举报

7日久生情
2288/5000
排名
1393
昨日变化

0

主题

709

帖子

2288

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
135463
好友
0
蛮牛币
35
威望
0
注册时间
2016-1-23
在线时间
690 小时
最后登录
2019-6-18
2019-5-29 14:53:39 显示全部楼层
发条橙更符合规范化风格很过分
回复 支持 反对

使用道具 举报

4四处流浪
385/500
排名
10343
昨日变化

0

主题

184

帖子

385

积分

Rank: 4

UID
248391
好友
0
蛮牛币
256
威望
0
注册时间
2017-10-12
在线时间
91 小时
最后登录
2019-6-18
2019-5-29 14:56:00 显示全部楼层
可以可以,不觉名利
回复 支持 反对

使用道具 举报

4四处流浪
313/500
排名
11818
昨日变化

0

主题

118

帖子

313

积分

Rank: 4

UID
269725
好友
0
蛮牛币
398
威望
0
注册时间
2018-2-27
在线时间
113 小时
最后登录
2019-6-18
2019-5-29 15:38:57 显示全部楼层
感谢楼主大大分享
回复 支持 反对

使用道具 举报

7日久生情
1843/5000
排名
4092
昨日变化

0

主题

1163

帖子

1843

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蛮牛币
1701
威望
0
注册时间
2017-11-16
在线时间
318 小时
最后登录
2019-6-17
2019-5-30 08:17:57 显示全部楼层
66666666666666666666666666666666
回复 支持 反对

使用道具 举报

4四处流浪
462/500
排名
7018
昨日变化

3

主题

102

帖子

462

积分

Rank: 4

UID
293049
好友
1
蛮牛币
2007
威望
0
注册时间
2018-8-9
在线时间
169 小时
最后登录
2019-6-18
2019-5-30 08:24:14 显示全部楼层
哇哦,真的很棒!希望窝能早日全部看懂,只能看懂一部分
回复 支持 反对

使用道具 举报

4四处流浪
304/500
排名
8822
昨日变化

0

主题

36

帖子

304

积分

Rank: 4

UID
307305
好友
0
蛮牛币
461
威望
0
注册时间
2018-12-6
在线时间
134 小时
最后登录
2019-6-18
2019-5-30 08:25:03 显示全部楼层
谢谢分享
回复

使用道具 举报

5熟悉之中
822/1000
排名
10817
昨日变化

3

主题

587

帖子

822

积分

Rank: 5Rank: 5

UID
310426
好友
0
蛮牛币
918
威望
0
注册时间
2019-1-2
在线时间
136 小时
最后登录
2019-6-18
2019-5-30 09:04:49 显示全部楼层
Unity Shader之磨砂玻璃与水雾玻璃效果
回复 支持 反对

使用道具 举报

5熟悉之中
531/1000
排名
13273
昨日变化

2

主题

161

帖子

531

积分

Rank: 5Rank: 5

UID
16650
好友
0
蛮牛币
1086
威望
0
注册时间
2014-3-6
在线时间
274 小时
最后登录
2019-6-6
2019-5-30 17:05:35 显示全部楼层
谢谢楼主分享.
回复

使用道具 举报

5熟悉之中
822/1000
排名
10817
昨日变化

3

主题

587

帖子

822

积分

Rank: 5Rank: 5

UID
310426
好友
0
蛮牛币
918
威望
0
注册时间
2019-1-2
在线时间
136 小时
最后登录
2019-6-18
2019-5-31 08:50:51 显示全部楼层
Unity Shader之磨砂玻璃与水雾玻璃效果
回复 支持 反对

使用道具 举报

7日久生情
1843/5000
排名
4092
昨日变化

0

主题

1163

帖子

1843

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蛮牛币
1701
威望
0
注册时间
2017-11-16
在线时间
318 小时
最后登录
2019-6-17
2019-5-31 13:34:59 显示全部楼层
666666666666666666666666666666
回复 支持 反对

使用道具 举报

0

主题

7

帖子

7

积分

Rank: 1

UID
323611
好友
0
蛮牛币
3
威望
0
注册时间
2019-5-31
在线时间
0 小时
最后登录
2019-5-31
2019-5-31 16:55:21 显示全部楼层
学习学习
回复

使用道具 举报

6蛮牛粉丝
1095/1500
排名
2066
昨日变化

0

主题

229

帖子

1095

积分

Rank: 6Rank: 6Rank: 6

UID
26073
好友
1
蛮牛币
4144
威望
0
注册时间
2014-5-21
在线时间
198 小时
最后登录
2019-6-18
2019-5-31 17:05:32 显示全部楼层
这得多厉害的人才搞得懂这些东西
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则