반응형

유니티의 아웃라인 셰이더는 구글에 돌아다니는 레퍼런스가 많아 손쉽게 구현이 가능합니다.

하지만, 자세하게 여러가지를 따지다 보면 불편한 사항이나 제약이 많이 뒤따른다는 것을 쉽게 발견할 수 있습니다.

 

 

일반적인 공식으로 알려져있는 아래 수식대로 셰이더를 만들어 아래 오브젝트에 연결해 보면..

 

        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        fixed3 norm   = mul ((fixed3x3)UNITY_MATRIX_MVP, v.normal);
        fixed2 offset = TransformViewToProjection(norm.xyz);
     
        o.pos.xy += offset * o.pos.z * _Outline;

        o.pos.z += 0.01 * _Outline;


        o.color = _OutlineColor;
        return o;

 

 

 

3D형태의 메쉬를 가진 오브젝트에는 잘 적용되지만 플랜 상태의 오브젝는 제대로 출려되지 않는 문제가 발생합니다. 아래 그림 참조

 

 

 

이 문제를 해결하기 위해서는 버텍스의 노멀 값 뿐 아니라 사이즈자체도 커지도록 한번 더 계산해 주는 수식을 넣어줘야 합니다.

 

fixed3 norm   = mul ((fixed3x3)UNITY_MATRIX_MVP, v.normal); //요 수식에서

 

fixed3 norm   = mul ((fixed3x3)UNITY_MATRIX_MVP, v.vertex + v.normal); //버텍스 값이 더해지도록 수식을 추가해 준다.

 

 

이렇게해도 제대로 출력되지 않을땐 아웃라인 패스 부분에 Cull back 을 추가해 줍니다.

 

 

 

그러면 아래 그림처럼 플랜에서도 정상적인 아웃라인을 만들어 지게 됩니다.

 

 

 

 

하지만 이 셰이더를 사용할 때 주의해야할 점이 있는데 바로 배칭이 안된다는 것입니다.

 

스태틱 배칭을 키고나면 버텍스 연산이 다르게 되어 아래그림처럼 엉뚱한 형태로 출력되게 됩니다.

 

 

 

위 셰이더를 사용하고자 할 때는 메터리얼을 따로 만들어 관리하는 것이 최적화에 도움이 될겁니다.

 

 

 

아래는 위 오브젝트의 아웃라인을 구현한 셰이더 코드입니다.

 

{
    Properties {
        _MainColor ("Main Color"Color) = (.5,.5,.5,1)
        _OutlineColor ("Outline Color"Color) = (0,0,0,1)

        _Outline ("Outline width"Range (010)) = 1
        _MainTex ("Base (RGB)"2D) = "white" { }
        _Rim ("Rim"Float) = 0.0
        _scale("Z Position(Only Plane)"FLoat) = 1.0

        //Sorting
        _ZTest ("ZTest Less = 4 / Always = 6 "FLoat) = 1
    }
 
    CGINCLUDE
    #include "UnityCG.cginc"
    #pragma target 3.0

    struct v2f {
        fixed4 pos : SV_POSITION;
        fixed4 color : COLOR;

    };
     
    uniform fixed _Outline;
    uniform fixed4 _OutlineColor;
    uniform fixed _Rim;
    uniform fixed _scale;
     
    v2f vert(appdata_base v) {
        
        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        v.vertex.xyz += v.normal.xyz * _scale;
        fixed3 norm   = mul ((fixed3x3)UNITY_MATRIX_IT_MV, v.normal + v.vertex * _Outline);
        fixed2 offset = TransformViewToProjection(norm.xyz);
     
        o.pos.xy += (offset * o.pos.z * _Outline) * 0.001;

        o.pos.z += 0.01 * _Outline;


        o.color = _OutlineColor;
        return o;
    }
    ENDCG
 
    SubShader {
        Tags {"Queue"="Geometry+200" "IgnoreProjector"="True" "RenderType"="Opaque"}
         Blend One Zero
//         ZTest NotEqual
//         ZWrite on
        Pass
        {
            ColorMask 0
        }
//
        Pass
        {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull off
            Blend SrcColor OneMinusSrcColor
            ZTest Always
//            ZWrite off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            fixed4 frag( v2f i ) : COLOR
            {
                fixed4 c = i.color;

                return i.color;
            }
            ENDCG
        }         
             
            CGPROGRAM
            #pragma surface surf Lambert

            struct Input {
                fixed2 uv_MainTex;
                fixed3 worldPos;
            };


            sampler2D _MainTex;
            //sampler2D _BumpMap;
            uniform fixed3 _MainColor;
            void surf(Input IN, inout SurfaceOutput o) {
//                IN.worldPOS.z;
                o.Emission = tex2D(_MainTex, IN.uv_MainTex).rgb * _MainColor * _Rim;
            //    o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
            }
            ENDCG
 
    }

}

반응형

+ Recent posts