Unity3D:模糊 UI 画布的背景
Posted
技术标签:
【中文标题】Unity3D:模糊 UI 画布的背景【英文标题】:Unity3D : Blur the background of a UI canvas 【发布时间】:2015-03-13 10:49:19 【问题描述】:我正在尝试在 Unity3D 中为我的游戏的 UI 窗口的背景创建模糊效果。
我现在能想到的最好的例子之一是风暴英雄,注意升级面板的背景如何模糊它背后的东西:
有什么方法可以在 Unity3D 中使用最近添加的 Canvas 重现相同的效果? 我知道有一种方法可以通过使用相机来做到这一点,但我对整个事情并不是很熟悉,尤其是在使用新的 UI 系统时。
谢谢。
【问题讨论】:
模糊背景可能会占用大量 CPU。您有时可以通过将背景的静态模糊版本放在顶部来做一个技巧 事实上,我认为这就是您的示例中所做的。你可以看到数字 2 没有模糊 @Ewan 请参阅 this 和 this。这不是静态模糊。此外,与游戏中的屏幕截图不同,在菜单中位于对话后面时,动画也会变得模糊。 在这种情况下,第二个摄像头带有模糊着色器 【参考方案1】:这是一个非常适合我的着色器脚本。
来源:https://forum.unity3d.com/threads/solved-dynamic-blurred-background-on-ui.345083/#post-2853442
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unlit/FrostedGlass"
Properties
_Radius("Radius", Range(1, 255)) = 1
Category
Tags "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque"
SubShader
GrabPass
Tags "LightMode" = "Always"
Pass
Tags "LightMode" = "Always"
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;
;
struct v2f
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
;
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;
return o;
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
half4 sum = half4(0,0,0,0);
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum += GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 0.1f; range <= _Radius; range += 0.1f)
sum += GRABXYPIXEL(range, range);
sum += GRABXYPIXEL(range, -range);
sum += GRABXYPIXEL(-range, range);
sum += GRABXYPIXEL(-range, -range);
measurments += 4;
return sum / measurments;
ENDCG
GrabPass
Tags "LightMode" = "Always"
Pass
Tags "LightMode" = "Always"
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;
;
struct v2f
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
;
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;
return o;
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
half4 sum = half4(0,0,0,0);
float radius = 1.41421356237 * _Radius;
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum += GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 1.41421356237f; range <= radius * 1.41; range += 1.41421356237f)
sum += GRABXYPIXEL(range, 0);
sum += GRABXYPIXEL(-range, 0);
sum += GRABXYPIXEL(0, range);
sum += GRABXYPIXEL(0, -range);
measurments += 4;
return sum / measurments;
ENDCG
【讨论】:
有什么简单的理由可以解释为什么这个着色器会自行环回?即背景模糊逐帧反馈给自身,导致每一帧都更加模糊(这本身是一种简洁的效果,但并不是我真正想要的) 尝试在iPhone 8+上使用,全屏图像模糊,值15。它很快让手机发热。下面的shader就没有这个问题了。 据我了解,此着色器 (A) 和下方 (B) 之间的差异非常显着。 A 具有 O(r^2) 复杂度并且更接近真实模糊(大 r 会导致性能问题)。 B 的复杂度为 O(r),而且更简单。我们根据我们的要求调整了 B 着色器,它很轻并且工作正常。请记住,您的要求可能会有所不同。【参考方案2】:我稍微修改了这个。添加了tint color和UI兼容性。虽然在 UI 上使用时是可能的,但会使之前的 UI 不可见。
// Based on cician's shader from https://forum.unity3d.com/threads/simple-optimized-blur-shader.185327/#post-1267642
Shader "Custom/MaskedUIBlur"
Properties
_Size ("Blur", Range(0, 30)) = 1
[HideInInspector] _MainTex ("Masking Texture", 2D) = "white"
_AdditiveColor ("Additive Tint color", Color) = (0, 0, 0, 0)
_MultiplyColor ("Multiply Tint color", Color) = (1, 1, 1, 1)
Category
// We must be transparent, so other objects are drawn before this one.
Tags "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Opaque"
SubShader
// Horizontal blur
GrabPass
"_HBlur"
/*
ZTest Off
Blend SrcAlpha OneMinusSrcAlpha
*/
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
Pass
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;
;
struct v2f
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvmain : TEXCOORD1;
;
sampler2D _MainTex;
float4 _MainTex_ST;
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.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
sampler2D _HBlur;
float4 _HBlur_TexelSize;
float _Size;
float4 _AdditiveColor;
float4 _MultiplyColor;
half4 frag( v2f i ) : COLOR
half4 sum = half4(0,0,0,0);
#define GRABPIXEL(weight,kernelx) tex2Dproj( _HBlur, UNITY_PROJ_COORD(float4(i.uvgrab.x + _HBlur_TexelSize.x * kernelx * _Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight
sum += GRABPIXEL(0.05, -4.0);
sum += GRABPIXEL(0.09, -3.0);
sum += GRABPIXEL(0.12, -2.0);
sum += GRABPIXEL(0.15, -1.0);
sum += GRABPIXEL(0.18, 0.0);
sum += GRABPIXEL(0.15, +1.0);
sum += GRABPIXEL(0.12, +2.0);
sum += GRABPIXEL(0.09, +3.0);
sum += GRABPIXEL(0.05, +4.0);
half4 result = half4(sum.r * _MultiplyColor.r + _AdditiveColor.r,
sum.g * _MultiplyColor.g + _AdditiveColor.g,
sum.b * _MultiplyColor.b + _AdditiveColor.b,
tex2D(_MainTex, i.uvmain).a);
return result;
ENDCG
// Vertical blur
GrabPass
"_VBlur"
Pass
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;
;
struct v2f
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvmain : TEXCOORD1;
;
sampler2D _MainTex;
float4 _MainTex_ST;
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.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
sampler2D _VBlur;
float4 _VBlur_TexelSize;
float _Size;
float4 _AdditiveColor;
float4 _MultiplyColor;
half4 frag( v2f i ) : COLOR
half4 sum = half4(0,0,0,0);
#define GRABPIXEL(weight,kernely) tex2Dproj( _VBlur, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _VBlur_TexelSize.y * kernely * _Size, i.uvgrab.z, i.uvgrab.w))) * weight
sum += GRABPIXEL(0.05, -4.0);
sum += GRABPIXEL(0.09, -3.0);
sum += GRABPIXEL(0.12, -2.0);
sum += GRABPIXEL(0.15, -1.0);
sum += GRABPIXEL(0.18, 0.0);
sum += GRABPIXEL(0.15, +1.0);
sum += GRABPIXEL(0.12, +2.0);
sum += GRABPIXEL(0.09, +3.0);
sum += GRABPIXEL(0.05, +4.0);
half4 result = half4(sum.r * _MultiplyColor.r + _AdditiveColor.r,
sum.g * _MultiplyColor.g + _AdditiveColor.g,
sum.b * _MultiplyColor.b + _AdditiveColor.b,
tex2D(_MainTex, i.uvmain).a);
return result;
ENDCG
【讨论】:
这对我很有用(但是,选择的答案版本没有)。谢谢! 效果很好,谢谢!我需要将模糊的背景设为灰度而不是彩色,因此我修改了着色器,为 gist.github.com/jhocking/9de4197daf84698a60e51c67695d2be3 添加了一个切换开关 我们如何将它与 URP 一起使用? 在统一 2020.3 中会导致“材料没有 _Stencil 属性”以上是关于Unity3D:模糊 UI 画布的背景的主要内容,如果未能解决你的问题,请参考以下文章