게임 개발 자료

화면 블러 처리 관련 자료 메모

원소랑 2024. 3. 6. 17:40

정규 분포 함수도 가우스 함수 중 하나. 흐려짐 수치에 곱하기 유용함.

https://www.desmos.com/calculator/trhru2deav?lang=ko

최대값을 1로 한 함수 : https://www.desmos.com/calculator/gkpftewc06

 

위 함수 값을 가져다가 텍스쳐의 텍셀을 샘플링 한다.

블러의 설질상 해상도를 축소해도 별 문제가 없기 때문에 0.5 스케일로 샘플링 해도 됨.

 

아래는 셰이더 코드

Shader "Custom/BlurEffect" 
{ 
    Properties 
    { 
        _MainTex("Texture", 2D) = "white" {} 
    } 
    SubShader 
    { 
        Tags { "RenderType"="Opaque" } 
        LOD 100 

        Pass 
        { 
            ZTest Off 
            ZWrite Off 
            Cull Back 

            CGPROGRAM 
            #pragma ARB_precision_hint_fastest 
            #pragma vertex vert 
            #pragma fragment frag 
            #include "UnityCG.cginc" 

            struct appdata 
            { 
                float4 vertex : POSITION; 
                float2 uv : TEXCOORD0; 
                } 
            ; 

            struct v2f 
            { 
                float4 vertex 
            : 
            SV_POSI _MainTex; 
            half4 _Offsets; 
            static const int samplingCount = 10; 
            half _Weights[samplingCount]; 
            v2f vert (appdata v) 
            { 
                v2f o; 
                o.vertex = UnityObjectToClipPos(v.vertex); 
                o.uv = v.uv; 
                return o; 
            } 
            fixed4 frag (v2f i) : SV_Target 
            { 
                half4 col = 0; 
                [unroll] 
                for (int j = samplingCount - 1; j > 0; j--) 
                { 
                    col += tex2D(_MainTex, i.uv - (_Offsets.xy * j )) * _Weights[j]; 
                } 
                [unroll] 
                for (int j = 0; j < samplingCount; j++) 
                { 
                    col += tex2D(_MainTex, i.uv + (_Offsets.xy * j)) * _Weights[j] ; 
                } 
                return col; 
            } 
            ENDCG 
        } 
    } 
}

 

half4 _Offsets; 
half _Weights[samplingCount];

위 두 개 값은 C# 스크립트에서 전달해서 처리.

 

frag 셰이더에서 samplingCount 만큼 루프 돌면서 tex2D 함수로 _MainTex 의 특정 uv 컬러값을 가져와서 연산.

 

C# 코드. 정상동작하지 않는 코드고, 참고만.

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.Rendering ;
 
namespace Sample {
public class GaussianBlur : MonoBehaviour 
{ 
	[SerializeField] 
	private Texture _texture ; 
	[ SerializeField ] 10f )]
	private float _offset = 1f ; 
	[SerializeField, Range( 10f , 1000f )]
	private float _blur = 100f ;
	private Material _material;
	private Renderer _renderer;
	// Apply sevral blur efect . 
	RenderTexture _rt2;
	private float [] _weights = new float [ 10 ];
	
	 private bool _isInitialized = false ;
#region ### MonoBehaviour ###
	 
	private void Awake( ) 
	{ 
		Initialize ( ) ! Application.isPlaying) 
		{ return ; 
		}
		
		UpdateWeights(); 
		Blur(); 
	}
#endregion ### MonoBehaviour ### /// < summary > /// Initialize (setup) /// </ summary >

	private void Initialize( ) 
	{
		if (_isInitialized) 
		{
			return ; 
		} 
		_material = new Material (_shader);
		_material.hideFlags = HideFlags.HideAndDontSave ; // Down scale. 
		_rt1 = new RenderTexture(_texture.width / 2, _texture.height / 2, 0, RenderTextureFormat.ARGB32);
		_rt2 = new RenderTexture(_texture.width / 2, _texture.height / 2, 0, RenderTextureFormat.ARGB32); 

		_renderer = GetComponent<Renderer>(); 
		UpdateWeights(); _is / < summary > /// Do blur to the texture. /// </ summary >
		
		
	public void Blur() 
	{
		if ( ! _isInitialized) 
		{ 
			Initialize(); 
		}
		
		Graphics.Blit(_texture, _rt1); 
		_material.SetFloatArray( "_Weights" , _weights);
        float x = _offset / _rt1.width;
		 float y = _offset / _rt1.height ;
         
         // for horizontal blur. 
		_material.SetVector( "_Offsets" , new Vector4(x, 0 , 0 , 0 ); 
		Graphics.Blit(_rt1, _rt2, _material);
        
        // for vertical blur. 
		_material.SetVector( "_Offsets" , new Vector4( 0 , y, 0 , 0 )); 
		Graphics.Blit(_rt2, _rt1, _material) ; 
		_renderer.material.mainTexture = _rt1; 
	}
	
	private  void UpdateWeights() 
	{
		float total = 0 ;
		float d = _blur * _blur * 0.001f ;
		for ( int i = 0 ; i < _weights.Length; i ++ ) 
		{
			// Offset position per x.
            float x = i * 2f ;
			float w = Mathf.Exp( - 0.5f * (x * x) / d); 
			_weights[i] = w; if (i > 0 ) 
			{ 
				w *= 2.0f ; 
			} 
			total += w; 
		}
		for ( int i = 0 ; i < _weights.Length; i ++ ) 
		{ 
			_weights[i] /= total; 
		} 
	}
	
} 
}

 

이렇게 적용하면 끝.

 

원문 : Unityでガウシアンブラーを実装する

(유니티로 가우시안 블러 구현하기)

https://edom18.hateblo.jp/entry/2018/12/30/171214

 

Unityでガウシアンブラーを実装する - e.blog

概要 よく使う&表現力の高いぼかし処理。 以前にもぼかしを利用したコンテンツを作成したり、記事を書いたりしていましたがちゃんとぼかしだけにフォーカスしたことはなかったので改

edom18.hateblo.jp

 


 

위 방법은 Graphics.Blit 을 써서 GPU의 텍스쳐 데이터를 렌더 텍스쳐로 복사해서 처리하는 방식. 아래는 GrapPass 를 사용해서 멀티 패스 쉐이더로 처리하는 방식.

 

아래는 GrabPass 를 써서 화면을 캡쳐하는 기본 셰이더 샘플.

Shader "Custom/GrabPass"

{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
    SubShader
    {

        Tags{ "Queue" = "Transparent" }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;

            half4 frag(v2f i) : SV_Target
            {
                half4 col = tex2Dproj(_GrabTexture, i.grabPos);
                return col;
            }
            ENDCG
        }
    }
}

https://docs.unity3d.com/kr/2022.3/Manual/SL-GrabPass.html

 

ShaderLab 커맨드: GrabPass - Unity 매뉴얼

GrabPass는 프레임 버퍼의 콘텐츠를 텍스처로 가져오는 특별한 패스 타입을 만드는 커맨드입니다. 이 텍스처를 이후 패스에 사용하여 고급 이미지 기반 효과를 수행할 수 있습니다.

docs.unity3d.com

URP 에선 지원 안 함. Built-in Render Pipiline 에서만 지원.

 

아래는 셰이더 코드 전문

Shader "Custom/Blur"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Blur("Blur", Float) = 10
    }
    SubShader
    {

        Tags{ "Queue" = "Transparent" }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float x = -blur; x <= blur; x += 1)
                {
                    float distance_normalized = abs(x / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(x * _GrabTexture_TexelSize.x, 0, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }
        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float y = -blur; y <= blur; y += 1)
                {
                    float distance_normalized = abs(y / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(0, y * _GrabTexture_TexelSize.y, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }

    } 
}

 

Unity로 손쉽게 만드는 Blur 쉐이더

https://ichinisann.tistory.com/37

 

Unity로 손쉽게 만드는 Blur 쉐이더

Blur UI는 좋아합니까 저는 엄청 좋아합니다. 하겠습니다. 방침 묘사중인 화면의 텍스쳐로서 얻을 수 있는 GrabPass를 사용하여, 그 녀석에 가우시안 블러를 얹는 쉐이더를 작성합니다. 가우시안 블

ichinisann.tistory.com


URP 블러 처리

https://github.com/lukakldiashvili/Unified-Universal-Blur

 

GitHub - lukakldiashvili/Unified-Universal-Blur: URP UI blur (translucent) effect for Unity.

URP UI blur (translucent) effect for Unity. Contribute to lukakldiashvili/Unified-Universal-Blur development by creating an account on GitHub.

github.com


게임 개발에 필수적인 내용을 담는 명서들을 소개합니다.

 

<유니티 교과서 개정6판>(유니티 최신 버전)
https://link.coupang.com/a/be3P0t

 

유니티 교과서 개정6판

COUPANG

www.coupang.com

 

<대마왕의 유니티 URP 셰이더 그래프 스타트업>

https://link.coupang.com/a/bs8qyC

 

대마왕의 유니티 URP 셰이더 그래프 스타트업

COUPANG

www.coupang.com


<리얼-타임 렌더링(REAL-TIME RENDERING) 4/e>
https://link.coupang.com/a/8VWas

 

리얼-타임 렌더링 4/e

COUPANG

www.coupang.com

 

<이득우의 게임 수학:39가지 예제로 배운다! 메타버스를 구성하는 게임 수학의 모든 것>
https://link.coupang.com/a/9BqLd

 

이득우의 게임 수학:39가지 예제로 배운다! 메타버스를 구성하는 게임 수학의 모든 것

COUPANG

www.coupang.com

 

유니티 에셋 스토어 링크
https://assetstore.unity.com?aid=1011lvz7h

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

(링크를 통해 도서/에셋 구입시 일정액의 수수료를 지급받습니다.)


 

728x90
반응형