[UNITY] 2018.2. 2d 캐릭터 외각선 그리기. 2d Sprite outline

     



2D 그래픽은 갖는 게임에서 오브젝트에 대한 외각선(out-line)을 표시하는 것은 사용자가 해당 오브젝트와 상호작용(interaction, 클릭이나 마우스 오버 등)을 나타내기위한 좋은 수단입니다. 


사실 아웃라인을 그리는 것이 체크박스 on/off 처럼 간단하게 구현될 것이라고 생각했는데, 생각보다 복잡하게 만들어야하더군요 ㅎ_ㅎ.


구글링해보면 생각보다 다양한 방법으로 아웃라인을 그리는 방법이 있습니다. 유니티 스토어에도 아웃라인을 그리는 패키지가 상당히 많이 있습니다. 제가 원하는건 위처럼 도트 이미지에 아웃라인을 넣는 간단한 것이었습니다. 


하지만 저렇게 간단해보이는 것도 쉐이더를 사용해서 그려야 하더군요. 쉐이더.. 뭔가 고오오급 그래픽 작업처럼 보이는 용어입니다...


일단 유니티에서도 쉐이더를 만드는 툴이 갖춰져있지만, 1도 모르는 상태에서 만들기에는 역부족이었습니다. 상당히 많은 지식이 필요하더라구요.. 


그래서 그냥 인터넷에 구현되어있는 쉐이더를 가져다 쓰기로 했습니다. 아웃라인 쉐이더가 여러종류가 있는데, 그중에서 카메라에 따로 소스를 추가하지 않아도 구현이 되는 쉐이더를 선택했습니다.




일단 쉐이더를 하나 만듭니다. 



만들어진 쉐이더를 열면 기본으로 설정되있는 코드들이 보입니다. 이 코드가 쉐이더가 어떻게 작동될 것인지를 정의하고 있습니다. 기본으로 설정되있는 코드를 다 지우고 아래 코드를 붙여넣기합니다.


Shader "Sprites/Outline"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture"2D) = "white" {}
        _Color ("Tint"Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap"Float) = 0
        [HideInInspector] _RendererColor ("RendererColor"Color) = (1,1,1,1)
        [HideInInspector] _Flip ("Flip"Vector) = (1,1,1,1)
        [PerRendererData] _AlphaTex ("External Alpha"2D) = "white" {}
        [PerRendererData] _EnableExternalAlpha ("Enable External Alpha"Float) = 0

        // Add values to determine if outlining is enabled and outline color.
        [PerRendererData] _Outline("Outline"Float) = 0
        [PerRendererData] _OutlineColor("Outline Color"Color) = (1,1,1,1)
        [PerRendererData] _OutlineSize("Outline Size"int) = 1
    }

    SubShader
    {
        Tags
        { 
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        {
        CGPROGRAM
            #pragma vertex SpriteVert
            #pragma fragment frag
            #pragma target 2.0
            #pragma multi_compile_instancing
            #pragma multi_compile _ PIXELSNAP_ON
            #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
            #include "UnitySprites.cginc"

            float _Outline;
            fixed4 _OutlineColor;
            int _OutlineSize;
            float4 _MainTex_TexelSize;

            fixed4 frag(v2f IN) : SV_Target
            {
                fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;

                // If outline is enabled and there is a pixel, try to draw an outline.
                if (_Outline > 0 && c.a != 0) {
                    float totalAlpha = 1.0;

                    [unroll(16)]
                    for (int i = 1; i < _OutlineSize + 1; i++) {
                        fixed4 pixelUp = tex2D(_MainTex, IN.texcoord + fixed2(0, i * _MainTex_TexelSize.y));
                        fixed4 pixelDown = tex2D(_MainTex, IN.texcoord - fixed2(0,i *  _MainTex_TexelSize.y));
                        fixed4 pixelRight = tex2D(_MainTex, IN.texcoord + fixed2(i * _MainTex_TexelSize.x, 0));
                        fixed4 pixelLeft = tex2D(_MainTex, IN.texcoord - fixed2(i * _MainTex_TexelSize.x, 0));

                        totalAlpha = totalAlpha * pixelUp.a * pixelDown.a * pixelRight.a * pixelLeft.a;
                    }

                    if (totalAlpha == 0) {
                        c.rgba = fixed4(1111) * _OutlineColor;
                    }
                }

                c.rgb *= c.a;

                return c;
            }
        ENDCG
        }
    }
}



이름은 Sprite-Outline.shader로 바꿔줍니다.


이제 외각선을 그리는 쉐이더를 만들었습니다. 이 쉐이더를 스프라이트에 붙여줄 스크립트를 만들어야합니다. SpriteOutline이라는 신규 스크립트를 만들고 아래 코드를 붙여넣기합니다.


using UnityEngine;


[ExecuteInEditMode]
public class SpriteOutline : MonoBehaviour {
    public Color color = Color.white;

    [Range(0, 16)]
    public int outlineSize = 1;

    private SpriteRenderer spriteRenderer;

    void OnEnable() {
        spriteRenderer = GetComponent<SpriteRenderer>();

        UpdateOutline(true);
    }

    void OnDisable() {
        UpdateOutline(false);
    }

    void Update() {
        UpdateOutline(true);
    }

    void UpdateOutline(bool outline) {
        MaterialPropertyBlock mpb = new MaterialPropertyBlock();
        spriteRenderer.GetPropertyBlock(mpb);
        mpb.SetFloat("_Outline", outline ? 1f : 0);
        mpb.SetColor("_OutlineColor", color);
        mpb.SetFloat("_OutlineSize", outlineSize);
        spriteRenderer.SetPropertyBlock(mpb);
    }
}


이제 마지막으로 Material을 추가합니다.



Materials이름은 SpriteOutline으로 변경해줍니다.


이제 외각선을 그리는 모든 준비는 끝났습니다. 다음과 같은 순서로 스프라이트에 옵션을 주면 외각선이 추가됩니다.


1. 스프라이트의 Material을 SpriteOutline으로 변경




2. 스프라이트에 SpriteOutline 스크립트 추가




3. 색, 크기 변경




현재 소스는 항상 스프라이트에 외각선을 표시하는 것이지만, 소스를 수정하면 특정조건에만 외각선을 표시할 수 있습니다. 


외각선 표시하기 끝!



참조 -

https://nielson.io/2016/04/2d-sprite-outlines-in-unity/

반응형

댓글

Designed by JB FACTORY