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

扫一扫,访问微社区

开发者专栏

关注:2177

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

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

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

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

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

8

主题

92

帖子

1383

积分

Rank: 9Rank: 9Rank: 9

UID
3876
好友
0
蛮牛币
2914
威望
0
注册时间
2013-9-14
在线时间
308 小时
最后登录
2018-4-24

专栏作家

发表于 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日久生情
3949/5000
排名
3505
昨日变化
13

5

主题

3107

帖子

3949

积分

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

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

回复

使用道具 举报

5熟悉之中
557/1000
排名
4574
昨日变化
2

0

主题

48

帖子

557

积分

Rank: 5Rank: 5

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

回复

使用道具 举报

5熟悉之中
964/1000
排名
3418
昨日变化
2

1

主题

367

帖子

964

积分

Rank: 5Rank: 5

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

回复

使用道具 举报

7日久生情
1817/5000
排名
1248
昨日变化
1

1

主题

565

帖子

1817

积分

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

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

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1008/1500
排名
2776
昨日变化
1

0

主题

217

帖子

1008

积分

Rank: 6Rank: 6Rank: 6

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

回复

使用道具 举报

4四处流浪
375/500
排名
6433
昨日变化
42

0

主题

105

帖子

375

积分

Rank: 4

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

回复

使用道具 举报

0

主题

26

帖子

35

积分

Rank: 1

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

回复 支持 反对

使用道具 举报

排名
972
昨日变化
2

8

主题

92

帖子

1383

积分

Rank: 9Rank: 9Rank: 9

UID
3876
好友
0
蛮牛币
2914
威望
0
注册时间
2013-9-14
在线时间
308 小时
最后登录
2018-4-24

专栏作家

 楼主| 发表于 2017-11-6 16:29:41 | 显示全部楼层
斯巴达 发表于 2017-11-6 15:00
Grab Pass的性能是不是还不如Render Texture啊?

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

回复 支持 反对

使用道具 举报

5熟悉之中
651/1000
排名
6935
昨日变化
5

1

主题

143

帖子

651

积分

Rank: 5Rank: 5

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

回复 支持 反对

使用道具 举报

7日久生情
2075/5000
排名
957
昨日变化
4

30

主题

386

帖子

2075

积分

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

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

回复

使用道具 举报

3偶尔光临
254/300
排名
12753
昨日变化
6

0

主题

122

帖子

254

积分

Rank: 3Rank: 3Rank: 3

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

回复

使用道具 举报

5熟悉之中
557/1000
排名
4574
昨日变化
2

0

主题

48

帖子

557

积分

Rank: 5Rank: 5

UID
148615
好友
0
蛮牛币
888
威望
0
注册时间
2016-5-15
在线时间
239 小时
最后登录
2018-4-5
发表于 2017-11-13 12:24:40 | 显示全部楼层
谢谢分享

回复

使用道具 举报

5熟悉之中
694/1000
排名
5402
昨日变化
47

19

主题

345

帖子

694

积分

Rank: 5Rank: 5

UID
249218
好友
3
蛮牛币
2498
威望
0
注册时间
2017-10-17
在线时间
100 小时
最后登录
2018-4-24
发表于 2017-11-14 08:32:08 | 显示全部楼层
Shader Playground:Unity UGUI模糊贴图纹理效果实现

回复 支持 反对

使用道具 举报

3偶尔光临
166/300
排名
57914
昨日变化
13

0

主题

11

帖子

166

积分

Rank: 3Rank: 3Rank: 3

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

回复 支持 1 反对 0

使用道具 举报

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

本版积分规则

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