본문 바로가기

[Unity] UI 뒷 배경 뿌옇게(Blur, 블러) 처리하기

Kwonriver 2023. 2. 5.
728x90

 

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
            }
        }
    }
}

 

 

[Unity3D] UI 배경 흐리게/뿌옇게 만들기, Panel에 Blur 효과 주기

참고한 페이지 : https://forum.unity.com/threads/solved-dynamic-blurred-background-on-ui.345083/ UI 배경 흐리게 만들기 게임 UI를 만들면서 원하는 부분을 강조하기 위해서 원래는 가장 간단한 방법인 뒤의 panel을

etst.tistory.com

 

BlurShader를 적용하기 위한 Material을 추가한다. Material(재질)은 셰이더, 이미지, 컬러값 등 다양한 프로퍼티를 사용하여 객체, 이미지 등의 표면을 처리하기 위한 기능이다.

 

 

BlurShader를 드래그앤드랍하여 BlurMaterial에 떨어트려준다. 그럼 자동으로 적용된다.

 

 

이제 아까 만들었던 Panel의 Image - Material에 드래그앤 드랍한다.

 

 

다만 이 때 Color값 중 Alpha가 0보다 커야한다. 0일 시 완전히 투명한 상태이기 때문에 Material이 보이지 않는다.

 

Raidus를 3정도로 변경한 스크린 샷

이 코드가 모바일 환경에서 심각한 프레임 드랍이 발생한다고 한다.

블러는 대충 이렇게 생성되는구나 정도로 이해하고 성능이 좋은 이미 구현된 블러를 사용하자.

 

 

GitHub - PavelDoGreat/Super-Blur: Screen and UI gaussian blur for Unity

Screen and UI gaussian blur for Unity. Contribute to PavelDoGreat/Super-Blur development by creating an account on GitHub.

github.com

 

728x90