구현 방법들

알파 마스크

둥근 사각형을 만드는 방법들은 여러가지가 있겠지만 흔히 사용되는 방법중에는 알파 마스크 기법이 있습니다. 알파 마스크는 원본 이미지와 알파블렌딩 된 텍스쳐를 합성하여 원하는 위치의 픽셀을 렌더링에서 제외해 버리는 방법 입니다. 원본 이미지를 렌더링 할 때 알파값은 별도의 텍스쳐에서 읽어온 값으로 사용하는 것이죠.

아래는 알파 마스크를 구현한 셰이더 코드 입니다.

Shader "CustomMask/AlphaMask"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_AlphaTex ("AlphaTexture", 2D) = "white" {}
	}
	SubShader
	{
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		LOD 100
   
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			struct appdata_t {
				float4 vertex : POSITION;
				float2 texcoord : TEXCOORD0;
			};

			struct v2f {
				float4 vertex : SV_POSITION;
				half2 texcoord : TEXCOORD0;
			};

			sampler2D _MainTex;
			sampler2D _AlphaTex;
           
			float4 _MainTex_ST;
           
			v2f vert (appdata_t v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}
           
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.texcoord);
				fixed4 col2 = tex2D(_AlphaTex, i.texcoord);

				// rgb는 원본 텍스쳐에서,
				// 알파값은 알파 텍스쳐에서 가져온다.
				return fixed4(col.r, col.g, col.b, col2.a);
			}
			ENDCG
		}
	}
}

이 방법은 구현이 간단하지만 별도의 텍스쳐가 필요하다는 단점이 있습니다. 또한 텍스쳐가 그려진 모양대로 마스킹이 되기 때문에 다른 모양을 원한다면 또다른 텍스쳐가 필요하게 됩니다.

알파값을 가진 이미지는 꼭 검은색일 필요는 없습니다. 어차피 알파성분만 사용할것이기 때문이죠. 따라서 RGBA중 R채널만 가진 이미지를 만들어 알파값으로 사용하는 최적화도 가능합니다.

수학적 계산 방법

알파텍스쳐를 사용하지 않고 수학적으로 모서리 영역을 계산하여 픽셀을 걸러내는 방법도 있습니다. 사각형의 모서리에 가상의 원을 그리고 그 원의 바깥쪽에 있는 픽셀들은 렌더링 하지 않는 방식으로 구현하는 것이죠.

기본적인 구현 방법은 다음과 같습니다.

  • 이미지의 모서리에 일정 크기의 가상의 원이 있다고 가정합니다.

  • 각각의 픽셀을 렌더링 할 때 해당 원의 바깥쪽에 있는지를 체크합니다. (원의 중심에서 각 픽셀까지의 거리와 반지름의 길이를 비교)

  • 바깥쪽이라고 판단되는 픽셀들은 렌더링에서 제외합니다(알파값을 주거나 discard를 시키는등).

그림을 보면 간단해 보이지만 실제 코드로 구현하려면 신경써야 할 부분이 많습니다.

위 그림처럼 반지름의 길이보다 더 큰 픽셀이라고 하더라도 제외하면 안되는 영역이 있습니다. 정확히 모서리쪽에 존재하는 픽셀들만 걸러내야 하는 것이죠. 이 구현의 핵심 키워드는 벡터와 좌표변환 입니다. 벡터는 3D렌더링에서 흔히 사용하는 개념이므로 크게 어려운것은 없습니다. 다만 좌표변환이 약간 헷갈릴 수 있는데 실제 셰이더 코드와 함께 원리를 살펴보도록 하겠습니다.

Last updated