[Unity] UI 뒷 배경 뿌옇게(Blur, 블러) 처리하기
UI 창이 오픈되면 뒷 배경을 잘 보이지 않게 하기 위해 흐리게 하는 경우가 많다. 이를 블러(Blur)처리라고 하는데 유저가 조금 더 UI 화면에 집중할 수 있도록 도와준다. 다양한 방법을 사용해서 블러를 만들 수 있지만 2가지 방법을 포스팅해본다.
이미지 투명도(알파)를 사용하여 배경 흐리기
별도의 색상있는 이미지의 알파값을 조절하여 뒷 배경을 잘 안보이게 만든다. 블러 처리라고 보기는 어렵지만 보다 간단하게 배경이 잘 안보이도록 할 수 있다.
먼저 배경 전체를 가릴 수 있을 크기의 Panel을 추가한다.
Panel은 생성과 동시에 Source Image, Color가 정해져있다. 흰색에 알파값은 100, 가장 오른쪽 사진이 추가된 사진이다.
새롭게 추가한 Panel을 온오프할 UI의 아래에 추가한다. UI를 제작할 때 Panel을 가장 위에 두어도 된다.
사실 배경 역할이기 때문에 가장 상위에서 먼저 그려지는 것이 맞다.
우리에게 필요한 것은 Color의 Alpha값이다. 이미지의 알파는 투명도를 조절할 때 사용된다. 숫자가 클수록(최대 255 또는 1.0f) 불투명해진다. 0이면 완전히 투명하여 보이지 않는다.
알파값을 적절하게 조절하며 배경의 뿌연 정도를 변경한다. 90 정도가 좋은 것 같다.
RGB 값을 조절하여 흐리게 만들 패널의 색상도 조절할 수 있다.
셰이더를 이용하여 블러 기능 만들기
유니티 셰이더 코드를 사용하여 특정 이미지 영역에 블러 기능을 넣는다. 위에서 설명한 알파값을 이용하는 것이 단순히 배경에 색상을 추가하는 것이라면 이 방법은 셰이더를 이용하여 실제 블러를 구현하는 것이다.
먼저 Shader - Image Effect Shader를 생성한다.
그럼 셰이더 파일이 하나 생성되는데 이 파일을 오픈한다. 기본적으로 셰이더가 동작하기 위한 필수 코드가 이미 작성되어 있다.
Shader "Hidden/BlurShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
// just invert the colors
col.rgb = 1 - col.rgb;
return col;
}
ENDCG
}
}
}
셰이더 코드를 전부 설명하기에는 한 세월이고 여기서 설명하기에 적합한 부분이 아니니 패스하도록 한다. ( 나중에 셰이더, 유니티 셰이더에 관하여 포스팅해보도록 하자.)
아래 코드를 복사하여 추가한다. 해당 코드는 아래 블로그에서 참조하였다.
{
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
}
}
}
}
BlurShader를 적용하기 위한 Material을 추가한다. Material(재질)은 셰이더, 이미지, 컬러값 등 다양한 프로퍼티를 사용하여 객체, 이미지 등의 표면을 처리하기 위한 기능이다.
BlurShader를 드래그앤드랍하여 BlurMaterial에 떨어트려준다. 그럼 자동으로 적용된다.
이제 아까 만들었던 Panel의 Image - Material에 드래그앤 드랍한다.
다만 이 때 Color값 중 Alpha가 0보다 커야한다. 0일 시 완전히 투명한 상태이기 때문에 Material이 보이지 않는다.
이 코드가 모바일 환경에서 심각한 프레임 드랍이 발생한다고 한다.
블러는 대충 이렇게 생성되는구나 정도로 이해하고 성능이 좋은 이미 구현된 블러를 사용하자.
'[Unity] > 기능' 카테고리의 다른 글
[Unity] 가중치 있는 랜덤 뽑기 기능 추가하기 (1) | 2023.01.31 |
---|---|
[Unity] 유니티 허브에서 프로젝트 열기 (0) | 2023.01.31 |
[Unity] 애니메이션 진행 중인지 확인하기 (1) | 2023.01.11 |
[유니티] 2D 중력 조절 (unity Gravity Scale) (0) | 2023.01.10 |
[Unity] 유니티 2D 레이캐스트로 충돌 판정 처리하기 (0) | 2023.01.09 |