본문 바로가기

Graphics/Unity

버텍스 포지션 기반으로 그라데이션을 적용해주는 유니티 셰이더

(유니티 빌트인 렌더 파이프라인 - Vertex&Fragment 및 Surface 셰이더 사용)

 

 

개요

유령 캐릭터를 만들면서, 캐릭터를 조금 더 '유령답게' 만들어주기 위해서 유령의 끝 부분을 그라디언트를 적용해 투명하게 하거나, 색을 그라데이션으로 적용할 수 있게 셰이더를 작업해야 했습니다. 다만 중요한 점은 '가볍게' 만들기였습니다.

 

셰이더가 적용된 유령 캐릭터 이미지

 

회사 분께 조언을 받았는데, 방법은 크게 두가지로 정리되었어요.

  1. 캐릭터를 정면 프로젝션한 별도 UV 채널을 추가해서, 해당 UV를 기반으로 그라데이션을 만드는 방법
  2. 버텍스 데이터의 y좌표값을 활용해서 버텍스 컬러에 그라데이션을 적용하는 방법

'가볍게'라는 중점에 맞게, 별도 UV채널을 사용해 연산하는 첫 번째 방식보다는,
UV채널을 추가하지 않고, 버텍스 셰이더에서 연산해주는 두 번째 방식으로 진행하기로 결정했습니다.

문제는 맨날 픽셀 셰이더만 만졌지 버텍스 셰이더를 작성해본 적은 없다는 거였는데...

 


 

버텍스 좌표 시각화

일단 버텍스의 위치 값에 어떻게 접근할 수 있는지 체크하고, 버텍스 y 위치를 시각화 할 수 있는지 간단하게 버텍스 프래그먼트 셰이더를 통해 슬라이더 값보다 버텍스의 y좌표값이 낮으면 검정색으로 표현되도록 해 확인했습니다.

 

Shader "Custom/Sample_VertFrag"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _ChangePoint ("Point for vertex color", Range(-1,1)) = 0 // 버텍스 컬러를 설정해주는 기준점
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                fixed4 color : COLOR; // Color 추가
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR; // Color 추가
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float _ChangePoint;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                o.color = v.vertex.y > _ChangePoint;
                // 버텍스 좌표의 y값이 _ChangePoint 보다 클 경우 버텍스의 색상을 하얀색,
                // 아닐 경우엔 검정색으로 설정

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                col = i.color; // 최종 색상값을 버텍스 컬러로 대체

                return col;
            }
        ENDCG
        }
    }
}

 

 

아래 유니티 매뉴얼 내용을 참고하며 작성했습니다!

 

버텍스 프로그램에 버텍스 데이터 제공하기 - Unity 매뉴얼

Cg/HLSL 버텍스 프로그램에서 메시 버텍스 데이터는 버텍스 셰이더 함수에 입력으로 전달됩니다. 각 입력에는 입력에 대해 지정된 시맨틱이 있어야 합니다. 예를 들어, POSITION 입력은 버텍스 포지

docs.unity3d.com

 

버텍스 데이터 시각화 - Unity 매뉴얼

빌트인 렌더 파이프라인에 대한 예제 셰이더는 버텍스 데이터를 시각화하는 다양한 방법을 보여줍니다.

docs.unity3d.com

 


 

버텍스 좌표 기반 그라디언트 생성 및 Surface 셰이더로 코드 옮기기

버텍스 위치를 시각화할 수 있다는 걸 확인했으니, 단순하게 그라디언트 색이 적용될 버텍스의 버텍스 컬러에 그라데이션 색상 범위에서 어디에 위치해주었는지 그 색상 값을 넣어주면 그라데이션을 만들 수 있을 거라고 생각했습니다.

 

 

그리고, 그라데이션이 시작하는 지점과 끝나는 지점을 프로퍼티로 선언해 그라데이션이 적용되는 범위를 조절할 수 있게 하면 됩니다.

 

// Vertex Gradient Shader
fixed4 _Color;
fixed4 _StartColor;

float _StartPos;
float _EndPos;

v2f vert (appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    
    float interpolValue;
    float range = _EndPos - _StartPos;
    interpolValue = clamp((_EndPos - v.vertex.y) / range, 0, 1);
    // 버텍스가 그라디언트 상에서 어디에 위치하고 있는지를 구하고,
    // clamp 로 값이 0과 1을 벗어나지 않도록 고정

    o.color = lerp(_StartColor, _Color, interpolValue);
    // 버텍스 컬러에 그라디언트 상의 위치에 맞게 색상을 적용

    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
}

 

 

버텍스 좌표를 기반으로 하는 부드러운 그라데이션이 만들어졌습니다! 🎉
버텍스들 사이의 픽셀 색상들은 래스터라이저에 의해 버텍스 컬러 값을 기준으로 보간되어 적용됩니다.

정상 동작을 확인했으니, 라이팅을 쉽게 적용할 수 있게 서페이스 셰이더로 옮겨줍니다.
이 과정에서, 서페이스 내부에 버텍스 셰이더를 사용한다고 선언해주고, 구조체에 컬러 변수를 추가해줍니다.

 

Shader "Custom/Surface_VertexGradientShader"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0

        // 프로퍼티 추가
        [Space]
        [Header(Gradation Option)]
        [Space]
        _StartColor ("Gradation Start Color", Color) = (1,1,1,1)
        _EndColor ("Gradation End Color", Color) = (1,1,1,1)
        _StartPos ("Gradation Start Position", Range(-1,1)) = 0
        _EndPos ("Gradation End Position", Range(-1,1)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        Blend SrcAlpha OneMinusSrcAlpha
        // RenderType / RenderQueue / Blend 추가 및 변경

        CGPROGRAM
        #pragma surface surf Standard vertex:vert alpha:blend
        // 버텍스 셰이더 사용을 위해 vertex:vert 구문 추가
        // 알파값이 적용되도록 alpha:blend 구문 추가

        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
            float4 color : COLOR; // color 변수 추가
        };

        // Vertex Gradient Shader
        half _StartPos;
        half _EndPos;
        fixed4 _StartColor;
        fixed4 _EndColor;

        void vert (inout appdata_full v)
        {
            float interpolValue;
            float range = _EndPos - _StartPos;
            interpolValue = clamp((_EndPos - v.vertex.y) / range, 0, 1);

            v.color = lerp(_EndColor, _StartColor, interpolValue);
        }
        // Vertex Gradient Shader End

        half _Glossiness;
        half _Metallic;

        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb * IN.color.rgb; // 버텍스 컬러의 rgb값 적용

            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;

            o.Alpha = c.a * IN.color.a; // 버텍스 컬러의 알파값 적용
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

작성된 셰이더를 유령 캐릭터에 적용해주면, 글의 초반부에 있던 하단 부분이 반투명한 무서운 유령이 완성됩니다! 👻

 

 


 

GitHub - rkato0128/ShaderStudy_Unity

Contribute to rkato0128/ShaderStudy_Unity development by creating an account on GitHub.

github.com

 

 

 

'Graphics > Unity' 카테고리의 다른 글

Color Blend Mode  (0) 2024.05.27
Chat GPT로 유니티 셰이더 만들기  (0) 2023.02.20
사각형 패턴 셰이더 만들기  (0) 2023.01.11