[Unity] 모델의 윤곽선만 묘사하는 셰이더

16708 단어 HLSLUnity3DUnity


소개



툰 쉐이딩에서는 모델의 윤곽을 그리는 것이 큰 특징입니다.
흔한 툰 셰이더는 "안쪽으로 면을 향해 조금 부풀어 오른 오브젝트"뒤에 "원래 오브젝트"를 묘사하고, 겹치지 않은 부분을 윤곽으로 하고 있습니다. 이러한 쉐이더로 메인 칼라를 투명하게 해도, 아웃라인마다 투명해져 버리거나, 「안쪽에 면을 향해 조금 부풀린 오브젝트」가 남아 버려, 잘 투과할 수 없습니다.
이번에는 아웃라인만을 그리는 셰이더를 스텐실 버퍼를 사용해 구현합니다.

구현



일반적인 툰 셰이더에서는 아웃라인 부분은 앞에서 설명한 2단계

단계 1. 안쪽으로 면을 향해 약간 부풀어 오른 물체를 묘사합니다.
단계 2. 원래 개체를 묘사합니다. 겹치지 않고 남은 부분이 윤곽이 된다.

하지만 이번에는 아래의 3단계로 구현합니다.

단계 1. 안쪽으로 면을 향해 약간 부풀린 물체로 스텐실을 씁니다.
2단계. 원본 개체에서 스텐실 재설정
3단계. 스텐실이 쓰여진 부분에 색칠

단계 1. 안쪽으로 면을 향해 약간 부풀린 물체로 스텐실을 씁니다.



스텐실을 원래 스텐실 값에 관계없이 42로 덮어씁니다.

outline.hlsl
            Stencil{
                Ref 42
                Comp always
                Pass replace
            }

정점 쉐이더에서는 이 오브젝트를 법선 방향으로 조금 부풀립니다.

outline.hlsl
            v2f vert (appdata v){
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex + v.normal * 0.05);
                return o;
            }

조각 셰이더는 적당하고 좋습니다. (ColorMask 0으로 좋음)

2단계. 원본 개체에서 스텐실 재설정



스텐실을 원래 스텐실 값에 관계없이 0으로 재설정합니다.

outline.hlsl
            Stencil{
                Ref 0
                Comp always
                Pass replace
            }

정점 쉐이더는 특별히 괴롭히지 않습니다.

outline.hlsl
            v2f vert (appdata v){
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }

이쪽도 조각 셰이더는 적당하고 좋습니다.

3단계. 스텐실이 쓰여진 부분에 색칠



1단계에서 스텐실이 기록되고 2단계에서 재설정되지 않은 스텐실 값이 42개 부분에만 묘사되도록 합니다.

outline.hlsl
            Stencil{
                Ref 42
                Comp eqal
                Pass keep
            }

정점 쉐이더는 지금까지의 모든 오브젝트를 덮을 필요가 있으므로, 이 오브젝트를 부풀립니다.

outline.hlsl
            v2f vert (appdata v){
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex + v.normal * 0.05);
                return o;
            }

프래그먼트 셰이더는 윤곽선의 색상을 그대로 출력합니다.

outline.hlsl
         fixed4 frag (v2f i) : SV_Target{
                return _color;
            }
        }

완제품



아래와 같은 코드가 되면 완성입니다.

outline.hlsl
Shader "Custom/outline" {
    Properties{
        _OutlineWidth ("Outline Width", float) = 0.1
        _color ("color",Color) = (1.0,0.0,0.0,1.0)
    }
    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        ZWrite On

        Pass {
            Stencil {
                Ref 42
                Comp always
                Pass replace //ステンシル42を書き込む
            }

            Cull Front //面を内側に向ける
            ColorMask 0

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                half4 vertex : POSITION;
                half3 normal : NORMAL;
            };

            struct v2f {
                half4 pos : SV_POSITION;
            };

            half _OutlineWidth;

            v2f vert (appdata v) {
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex + v.normal * _OutlineWidth);//オブジェクトを法線方向に膨らませる
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                return 0;
            }
            ENDCG
        }

        Pass {
            Stencil {
                Ref 0
                Comp always
                Pass replace //ステンシルを0でリセット
            }

            Cull back
            ColorMask 0

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                half4 vertex : POSITION;
            };

            struct v2f{
                half4 pos : SV_POSITION;
            };

            v2f vert (appdata v) {
                v2f o = (v2f)0;

                o.pos = UnityObjectToClipPos(v.vertex);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                return 0;
            }
            ENDCG
        }

        Pass {
            Stencil {
                Ref 42 
                Comp equal
                Pass keep //ステンシルが42なら描写
            }

            Cull back

           CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag

           #include "UnityCG.cginc"

            struct appdata {
                half4 vertex : POSITION;
                half3 normal : NORMAL;
            };

            struct v2f {
                half4 pos : SV_POSITION;
            };

            half _OutlineWidth;
            fixed4 _color;

            v2f vert (appdata v) {
                v2f o = (v2f)0;

                o.pos = UnityObjectToClipPos(v.vertex + v.normal * _OutlineWidth);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                return _color;
            }
            ENDCG
        }
    }
}

© Unity Technologies Japan/UC

좋은 웹페이지 즐겨찾기