开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1963

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 758|回复: 18

[bxh883] Shader Playground:Unity UGUI模糊贴图纹理效果实现

[复制链接]  [移动端链接]
排名
901
昨日变化

4

主题

70

帖子

1306

积分

Rank: 9Rank: 9Rank: 9

UID
3876
好友
0
蛮牛币
2756
威望
0
注册时间
2013-9-14
在线时间
289 小时
最后登录
2017-11-20
发表于 2017-11-5 21:35:06 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 bxh883 于 2017-11-5 21:42 编辑

效果预览

这是一个简单的线性模糊的效果。不用RenderTexture。
一个shader,一个脚本,一个材质球就能快速实现。
实现思路
要达到这个效果,分两步实现,
  • 用Unity ShaderLab里的GrabPass来抓取屏幕像素
  • 重新计算并修改MainTeture的UV,达到只模糊RawImage的Rect范围内的图像。
GrabPass
下面是来自.4beta官方文档对GrabPass的描述:
GrabPass is a special passtype - it grabs the contents of the screen where the object is about to be drawn into a texture.
This texture can be used in subsequent passes to do advanced image based effects.
GrabPass可以把屏幕内容抓取到一个贴图纹理里,然后这个贴图纹理可以在之后的pass中使用。
他的用法不难,下面是官方给的的例子:
[AppleScript] 纯文本查看 复制代码
Shader "GrabPassInvert"
{
    SubShader
    {
        // Draw ourselves after all opaque geometry
        Tags { "Queue" = "Transparent" }

        // Grab the screen behind the object into _GrabTexture
        GrabPass { }

        // Render the object with the texture generated above, and invert the colors
        Pass
        {
            SetTexture [_GrabTexture] { combine one-texture }
        }
    }
}

实际这是一个Pass,可以抓取到屏幕内容。
直接只用GrabPass{}后,会把内容存储在默认的变量_GrabTexture中
如果想要将内容存放在另外的变量,可以用GrabPass{“TextureName”}
比如我们的变量是_MyGrabTexture这样官方的例子就变成了这样:
[AppleScript] 纯文本查看 复制代码
Shader "GrabPassInvert"
{
    SubShader
    {
        // Draw ourselves after all opaque geometry
        Tags { "Queue" = "Transparent" }

        // Grab the screen behind the object into _MyGrabTexture
        GrabPass { "_MyGrabTexture" }

        // Render the object with the texture generated above, and invert the colors
        Pass
        {
            SetTexture [_MyGrabTexture] { combine one-texture }
        }
    }
}
重新计算TextureUV
由于GrabPass抓取的是整个屏幕所有的内容,那我们可以通过改变纹理的UV就可以实现将屏幕对应区域的内容进行显示。
UV的坐标系原点屏幕左下
在UGUI中,RectTransform.rect.center的值是当前rect中心的点的坐标,但是他的坐标系的原点RectTransform的Pivot
因此我们要得到纹理的正确UV还需要计算出正确的坐标。
[C#] 纯文本查看 复制代码
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(RawImage))]
public class BlurTexture : MonoBehaviour {

        private RawImage texture;
        /// <summary>
        /// texture所在的Root Canvas
        /// </summary>
        public Canvas rootCanvas;

        private void Awake(){
                texture = GetComponent<RawImage>();                
        }

        private void Update()
        {
                var screenWidth = rootCanvas.pixelRect.xMax / rootCanvas.scaleFactor;
                var screenHeight = rootCanvas.pixelRect.yMax / rootCanvas.scaleFactor;

                //得到一个从屏幕中心点到texture左下角的点的向量
                var bottomLeft = texture.rectTransform.anchoredPosition + texture.rectTransform.rect.min;

                var normalWidth = texture.rectTransform.rect.width / screenWidth;
                var normalHeight = texture.rectTransform.rect.height  / screenHeight;

                //uv的xy起点为(0,0),我们在计算坐下角的点时是从屏幕中心点开始,因此要加上0.5
                texture.uvRect = new Rect(0.5f + bottomLeft.x / screenWidth, 0.5f + bottomLeft.y / screenHeight, normalWidth, normalHeight);
        }
}

简单模糊
这里我实现的是相对简单,但是效果欠佳的线性模糊

[AppleScript] 纯文本查看 复制代码
Shader "ShaderPlayground/BlurTexture" {
        Properties{
                _MainTex("Base (RGB)", 2D) = "white" {}
                _BlurRadius("Raius", Range(0, 10)) = 0
        }
        SubShader{
                //UGUI的RenderQueue在Transparent
                Tags{ "Queue" = "Transparent"}

                GrabPass{}

                Pass{
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag

                        #include "UnityCG.cginc"

                        sampler2D _GrabTexture;
                        float2 _GrabTexture_TexelSize;
                        float _BlurRadius;

                        struct appdata {
                                float4 pos:POSITION;
                                float2 uv:TEXCOORD0;
                                float4 color:COLOR;
                        };

                        struct v2f {
                                float4 pos:SV_POSITION;
                                float2 uv:TEXCOORD0;
                                float2 uv1:TEXCOORD1;
                                float2 uv2:TEXCOORD2;
                                float2 uv3:TEXCOORD3;
                                float2 uv4:TEXCOORD4;
                                float4 color:COLOR;
                        };

                        v2f vert(appdata i) {
                                v2f o;
                                o.pos = mul(UNITY_MATRIX_MVP, i.pos);
                                o.uv = i.uv.xy;
#if UNITY_UV_STARTS_AT_TOP
                                if (_GrabTexture_TexelSize.y < 0)
                                        o.uv.y = 1 - o.uv.y;
#endif
                                o.uv1 = o.uv.xy + _BlurRadius * _GrabTexture_TexelSize * float2(1, 1);
                                o.uv2 = o.uv.xy + _BlurRadius * _GrabTexture_TexelSize * float2(-1, 1);
                                o.uv3 = o.uv.xy + _BlurRadius * _GrabTexture_TexelSize * float2(-1, -1);
                                o.uv4 = o.uv.xy + _BlurRadius * _GrabTexture_TexelSize * float2(1, -1);
                                o.color = i.color;
                                return o;
                        }

                        fixed4 frag(v2f i) : SV_Target{
                                fixed4 color = fixed4(0, 0, 0, 0);
                                color += tex2D(_GrabTexture, i.uv);
                                color += tex2D(_GrabTexture, i.uv1);
                                color += tex2D(_GrabTexture, i.uv2);
                                color += tex2D(_GrabTexture, i.uv3);
                                color += tex2D(_GrabTexture, i.uv4);
                                return color * 0.2 ;
                        }
                        ENDCG
                }
        }
}



Bingo
这样我们就能得到一个随意移动缩放的马赛克了!
后面我还想实现高斯模糊,动态模糊效果,还有移动端优化,让手机也能看到马赛克。
这是demo工程的地址ForkMeInGithub(https://github.com/aaBaO/DemoRepository)
有不对的地方欢迎大家指正和探讨~~
原文博客(https://aabao.github.io/UnityUGUI-Blur-Texture/)也希望大家多多讨论





回复

使用道具 举报

7日久生情
2636/5000
排名
5558
昨日变化
3

4

主题

2186

帖子

2636

积分

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

UID
209186
好友
4
蛮牛币
3155
威望
0
注册时间
2017-3-1
在线时间
252 小时
最后登录
2017-11-17
发表于 2017-11-6 09:10:12 | 显示全部楼层
谢谢分享

回复

使用道具 举报

2初来乍到
117/150
排名
13187
昨日变化
263

0

主题

24

帖子

117

积分

Rank: 2Rank: 2

UID
148615
好友
0
蛮牛币
249
威望
0
注册时间
2016-5-15
在线时间
47 小时
最后登录
2017-11-19
发表于 2017-11-6 09:14:49 | 显示全部楼层
谢谢分享

回复

使用道具 举报

5熟悉之中
639/1000
排名
4546
昨日变化

0

主题

241

帖子

639

积分

Rank: 5Rank: 5

UID
122160
好友
0
蛮牛币
1271
威望
0
注册时间
2015-9-10
在线时间
150 小时
最后登录
2017-11-17
发表于 2017-11-6 09:21:01 | 显示全部楼层
感谢分享

回复

使用道具 举报

6蛮牛粉丝
1491/1500
排名
1421
昨日变化

1

主题

457

帖子

1491

积分

Rank: 6Rank: 6Rank: 6

UID
56496
好友
0
蛮牛币
4354
威望
0
注册时间
2014-11-19
在线时间
329 小时
最后登录
2017-11-17
发表于 2017-11-6 09:48:09 | 显示全部楼层
高斯模糊,动态模糊效果,还有移动端优化

回复 支持 反对

使用道具 举报

5熟悉之中
763/1000
排名
3618
昨日变化
11

0

主题

204

帖子

763

积分

Rank: 5Rank: 5

UID
168312
好友
0
蛮牛币
1395
威望
0
注册时间
2016-9-13
在线时间
241 小时
最后登录
2017-11-19
发表于 2017-11-6 12:17:34 | 显示全部楼层
路过学习
[发帖际遇]: 1169895688 捡了钱没交公 蛮牛币 降了 1 . 幸运榜 / 衰神榜

回复

使用道具 举报

排名
18339
昨日变化
4

0

主题

59

帖子

94

积分

Rank: 2Rank: 2

UID
252416
好友
0
蛮牛币
37
威望
0
注册时间
2017-11-3
在线时间
15 小时
最后登录
2017-11-17
发表于 2017-11-6 13:28:31 | 显示全部楼层
学习到了

回复

使用道具 举报

0

主题

25

帖子

34

积分

Rank: 1

UID
111878
好友
0
蛮牛币
21
威望
0
注册时间
2015-7-3
在线时间
9 小时
最后登录
2017-11-6
发表于 2017-11-6 15:00:15 | 显示全部楼层
Grab Pass的性能是不是还不如Render Texture啊?
[发帖际遇]: 斯巴达 在网吧通宵,花了 3 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

排名
901
昨日变化

4

主题

70

帖子

1306

积分

Rank: 9Rank: 9Rank: 9

UID
3876
好友
0
蛮牛币
2756
威望
0
注册时间
2013-9-14
在线时间
289 小时
最后登录
2017-11-20
 楼主| 发表于 2017-11-6 16:29:41 | 显示全部楼层
斯巴达 发表于 2017-11-6 15:00
Grab Pass的性能是不是还不如Render Texture啊?

应该是比RenderTexture好的,要对比过才行。

回复 支持 反对

使用道具 举报

5熟悉之中
522/1000
排名
7829
昨日变化
3

1

主题

119

帖子

522

积分

Rank: 5Rank: 5

UID
56504
好友
0
蛮牛币
349
威望
0
注册时间
2014-11-19
在线时间
283 小时
最后登录
2017-11-18
发表于 2017-11-6 19:39:49 | 显示全部楼层
GrabPass性能应该不如RT吧。。  移动端基本上没法用这个玩意。。

回复 支持 反对

使用道具 举报

7日久生情
1664/5000
排名
1186
昨日变化
2

28

主题

253

帖子

1664

积分

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

UID
124569
好友
24
蛮牛币
8118
威望
0
注册时间
2015-10-4
在线时间
577 小时
最后登录
2017-11-18
发表于 2017-11-7 09:17:52 | 显示全部楼层
谢谢分享

回复

使用道具 举报

3偶尔光临
238/300
排名
12450
昨日变化
3

0

主题

118

帖子

238

积分

Rank: 3Rank: 3Rank: 3

UID
155121
好友
0
蛮牛币
103
威望
0
注册时间
2016-7-4
在线时间
68 小时
最后登录
2017-11-17
发表于 2017-11-8 18:51:35 | 显示全部楼层
{:86:}{:86:}

回复

使用道具 举报

2初来乍到
117/150
排名
13187
昨日变化
263

0

主题

24

帖子

117

积分

Rank: 2Rank: 2

UID
148615
好友
0
蛮牛币
249
威望
0
注册时间
2016-5-15
在线时间
47 小时
最后登录
2017-11-19
发表于 7 天前 | 显示全部楼层
谢谢分享

回复

使用道具 举报

3偶尔光临
291/300
排名
12929
昨日变化
252

8

主题

205

帖子

291

积分

Rank: 3Rank: 3Rank: 3

UID
249218
好友
2
蛮牛币
935
威望
0
注册时间
2017-10-17
在线时间
28 小时
最后登录
2017-11-19
发表于 6 天前 | 显示全部楼层
Shader Playground:Unity UGUI模糊贴图纹理效果实现

回复 支持 反对

使用道具 举报

3偶尔光临
157/300
排名
53168
昨日变化
21

0

主题

9

帖子

157

积分

Rank: 3Rank: 3Rank: 3

UID
64429
好友
0
蛮牛币
272
威望
0
注册时间
2014-12-29
在线时间
146 小时
最后登录
2017-11-16
发表于 5 天前 | 显示全部楼层
移动端基本不用考虑了,用GrabPass消耗太大。
比较经济实惠的方法是建立一个帧缓冲,用内存空间换时间,奇数帧将画面渲染到RenderTexture 1再blit到屏幕上偶数帧将画面渲染到RenderTexture 2上再blit到屏幕,利用上一帧渲染的结果(保存在了RenderTexture里面)来做模糊、扭曲效果。
[发帖际遇]: leosaac 发帖时在路边捡到 1 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

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

本版积分规则

快速回复 返回顶部 返回列表