Shader

[Shader] (2024_10_01) Stencil Shader와 2D Shader Rnedering (벽 뒤에 랜더링 처리)

HK1206 2024. 10. 2. 00:00

깃헙 링크 : https://github.com/ljs1206/NKProject-Script-

 

GitHub - ljs1206/NKProject-Script-: collection of scripts

collection of scripts. Contribute to ljs1206/NKProject-Script- development by creating an account on GitHub.

github.com

 

유니티를 하다보면 한번쯤은 2D 랜더링 환경에서 벽 뒤에 적을 그려보고 싶을 떄가 있다... 처음에 나는 코드를 일일히 처리해줬는데. 이젠 다르다!

유니티에는 이럴 때 사용할 수 있는 두 가지 방법이 있다 (내가 아는 기준)

첫번째는? RenderObjects

두번쨰는 Stencil Shader이다.

저는 RenderObjects가 복잡한 관계로 Stencil Shader를 사용하여 간단하게 구현하여 주었다.

빨간색인데 랜더 이슈 때문에 표현이 안됨 (order In Layer를 건들면 플레이어를 가린다, sort도 같음)

Shader "Splatter/Splatter"
{
	Properties
	{
		[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
		_Color ("Tint", Color) = (1,1,1,1)
	}

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

		Cull Off
		Lighting Off
		ZWrite Off
		Blend One OneMinusSrcAlpha

		Pass
		{
			Stencil
			{
				Ref 5
				Comp Equal
			}

		HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

			struct Attributes
			{
				float4 vertex   : POSITION;
				float4 color    : COLOR;
				float2 texcoord : TEXCOORD0;
			};

			struct Varyings
			{
				float4 vertex   : SV_POSITION;
				half4 color    : COLOR;
				half2 texcoord  : TEXCOORD0;
			};

			half4 _Color;

			Varyings vert(Attributes IN)
			{
				Varyings OUT;
				OUT.vertex = TransformObjectToHClip(IN.vertex);
				OUT.texcoord = IN.texcoord;
				OUT.color = IN.color * _Color;

				return OUT;
			}

			sampler2D _MainTex;
			sampler2D _AlphaTex;
			float _AlphaSplitEnabled;

			half4 SampleSpriteTexture (float2 uv)
			{
				half4 color = tex2D (_MainTex, uv);
				if (_AlphaSplitEnabled)
					color.a = tex2D (_AlphaTex, uv).r;

				return color;
			}

			half4 frag(Varyings IN) : SV_Target
			{
				half4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
				c.rgb *= c.a;
				return c;
			}
		ENDHLSL
		}
	}
}

실제 스탠실이 처리가 될 오브젝트의 스크립트이다. 랜더링 처리 과정을 거치고 Stencil를 추가해서 값을 5로 설정하고 Epual로 조건을 정해줌

참고로 2D는 3D와 랜더링이 달라서 "Queue"="Transparent"를 사용해야 하며 Texture2D를 뽑아 오는 작업을 해줘야 한다...

Shader "Splatter/Surface"
{
    Properties
    {
       [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
       _Color ("Tint", Color) = (1,1,1,1)
       _AlphaCutoff("Alpha Cutoff", Range(0.01, 1.0)) = 0.01
    }

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

       Cull Off
       Lighting Off
       ZWrite Off
       Blend One OneMinusSrcAlpha

       Pass
       {
          Stencil
          {
             Ref 5
             Comp Always
             Pass Replace
          }

       HLSLPROGRAM
          #pragma vertex vert
          #pragma fragment frag

          #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

          struct Attributes
          {
             float4 vertex   : POSITION;
             float4 color    : COLOR;
             float2 texcoord : TEXCOORD0;
          };

          struct Varyings
          {
             float4 vertex   : SV_POSITION;
             half4 color    : COLOR;
             half2 texcoord  : TEXCOORD0;
          };

          half4 _Color;
          half _AlphaCutoff;

          Varyings vert(Attributes IN)
          {
             Varyings OUT;
             OUT.vertex = TransformObjectToHClip(IN.vertex);
             OUT.texcoord = IN.texcoord;
             OUT.color = IN.color * _Color;

             return OUT;
          }

          sampler2D _MainTex;
          sampler2D _AlphaTex;
          float _AlphaSplitEnabled;

          half4 SampleSpriteTexture (float2 uv)
          {
             half4 color = tex2D (_MainTex, uv);
             if (_AlphaSplitEnabled)
                color.a = tex2D (_AlphaTex, uv).r;

             return color;
          }

          half4 frag(Varyings IN) : SV_Target
          {
             half4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
             c.rgb *= c.a;

             // 스탠실 이외에 것이 랜더가 되지 않도록 짤라줌
             clip(c.a - _AlphaCutoff);

             return c;
          }
       ENDHLSL
       }
    }
}

Stencil Object가 그려질 Surface이다. 5의 값이 아닌 것들을 전부 Pass 해주게 Stencil를 작성한다.

사실 유니티 공식문서에서 굉장히 친절하게 StencilShader를 다루고 있으니 참고 하도록 하자.. 

(대신 3D 기준임 2D도 유사함 랜더링 부분만 2D로 바꿔주면됨...)

https://docs.unity3d.com/Manual/SL-Stencil.html

 

Unity - Manual: ShaderLab command: Stencil

ShaderLab command: Offset ShaderLab command: UsePass ShaderLab command: Stencil Configures settings relating to the stencil bufferA memory store that holds an 8-bit per-pixel value. In Unity, you can use a stencil buffer to flag pixels, and then only rende

docs.unity3d.com

여튼 이런식으로 작성하고 Mat을 만들어서 넣어주면

잘 된다!

앞으로는 Shader Scripting을 하면서 재밌게 다뤘던 내용을 간간히 올릴 생각이다.