본문 바로가기
유니티/Shader Study

URP Shader Study #4 - Texture Sampling

by witn331ss 2023. 11. 30.

hlsl에서는 fixed를 지원을 하지 않는다.

컬러 연산은 half면 충분하고

float는 그보다 훨씬 정밀한 range값 정도 사용할때 사용된다.

(최소를 half라고 생각하면 된다)

Texture Sampling - Coupled textures and samplers

샘플러와 텍스쳐를 한번에 선언하여 사용하는 경우이다.

 

메모리에 올려진 텍스쳐를 해당 픽셀에 맵핑하는 과정이라고 생각하면 된다.

(정확히는 Texture filtering된 texel의 정보값을 해당 pixel에 맵핑하는 과정

 

먼저 프로퍼티스에서 텍스쳐를 제어할 수 있게끔 만들어준다.

   _MainTex("Texture2D", 2D) = "white" {}

 

 

그 다음 우리는 UV를 사용할 것이기 때문에 VertexBuffer에 UV를 불러와주자 (보간기에도 동일하게 넣어주자)

                float2 uv : TEXCOORD0;

 

 

그 다음 텍스쳐를 입힐 것을 하나 생성해주고 그 것을 제어해줄 변수를 넣어준다 (버텍스 쉐이더 바로 이전에 넣어주자)

 sampler2D _MainTex;
 float4 _MainTex_ST;

 

그 다음 버텍스 쉐이더에서 UV를 계산해준다. 오프셋과 스케일은 버텍스 레벨에서도 조정이 가능하기에 여기에 입력해주자

         	o.vertex = TransformObjectToHClip(v.vertex.xyz);
            o.uv = v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw; // xy = scale zw = offset

 

텍스쳐를 만들기 위한 계산은 얼추 끝났다. 이제 이것을 픽셀 쉐이더를 통해 우리가 볼 수 있게끔 만들어주자

미리 버텍스 레벨에서 offset , scale 을 계산했기에 그냥 텍스쳐랑 UV만 넣어주면 된다

 half4 color = tex2D(_MainTex, i.uv);
          	      return color;

 

 

이 방식이 바로 샘플러와 텍스쳐를 한번에 선언하여 사용하는 방법이다.

 

 

 

##################

 

 

Texture Sampling - Separate textures and samplers

샘플러와 텍스쳐를 분리해서 사용하는 방법이다.

굳이 나눠쓰는 이유는 기종에 따라서 쉐이더모델이 달라서 

좀더 적은 숫자의 보간기를 사용해 다양한 것을 사용하기 위해 텍스쳐와 샘플러를 분리시킨 것이다.

 

 

프로퍼티스에 제어할 텍스쳐를 두개 만든다.

                _MainTex("Texture2D", 2D) = "white" {}
                _MainTex02("RGB02", 2D) = "white" {}

 

그다음 버텍스 버퍼에서 제어할 두 UV를 꺼낸다

           float2 uv : TEXCOORD0;
           float2 uv2 : TEXCOORD1;

 

그 다음 해당 변수들을 선언해주자

 

            Texture2D _MainTex;
            Texture2D _MainTex02;

            float4 _MainTex_ST;
            float4 _MainTex02_ST;


            SamplerState sampler_MainTex;

 

버텍스 쉐이더에서 두 uv 따로 한번 계산해주자

           o.uv = v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw; // xy = scale zw = offset 
            o.uv2 = v.uv2.xy * _MainTex02_ST.xy + _MainTex02_ST.zw;

 

그 다음 픽셀쉐이더에서 두가지를 대입시켜주면 된다.

마지막 lerp 는 활용할 수 있는 방법 중 하나다.

            half4 col01 = _MainTex.Sample(sampler_MainTex, i.uv);
            half4 col02 = _MainTex02.Sample(sampler_MainTex, i.uv2);

            half color = lerp(col01, col02 , 0.5);
          	
            return color;

 

 

 

##############

 

작성한 코드는 다음과 같다

 // Shader 시작. 셰이더의 폴더와 이름을 여기서 결정합니다.
Shader "URPTraining/URPBasic"
{


   Properties
             {   
// Properties Block : 셰이더에서 사용할 변수를 선언하고 이를 material inspector에 노출시킵니다

                _TintColor("Color", color) = (1,1,1,1)
                _MainTex("Texture2D", 2D) = "white" {}
                _MainTex02("RGB02", 2D) = "white" {}
           	}  

	SubShader
	{  

	Tags
            {
//Render type과 Render Queue를 여기서 결정합니다.
	   "RenderPipeline"="UniversalPipeline"
                "RenderType"="Opaque"          
                "Queue"="Geometry"
            }
    	Pass
    	{  		
     	 Name "Universal Forward"
              Tags { "LightMode" = "UniversalForward" }

       	HLSLPROGRAM

        	#pragma prefer_hlslcc gles
        	#pragma exclude_renderers d3d11_9x
        	#pragma vertex vert
        	#pragma fragment frag

//cg shader는 .cginc를 hlsl shader는 .hlsl을 include하게 됩니다.
       	#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"        	
  
//vertex buffer에서 읽어올 정보를 선언합니다. 	
         	struct VertexInput
         	{
            	float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 uv2 : TEXCOORD1;
          	};

//보간기를 통해 버텍스 셰이더에서 픽셀 셰이더로 전달할 정보를 선언합니다.
        	struct VertexOutput
          	{
           	float4 vertex  	: SV_POSITION;
            float2 uv : TEXCOORD0;
            float2 uv2 : TEXCOORD1;


      	};

            half4 _TintColor;
            //sampler2D _MainTex;
            Texture2D _MainTex;
            Texture2D _MainTex02;

            float4 _MainTex_ST;
            float4 _MainTex02_ST;


            SamplerState sampler_MainTex;
            

//버텍스 셰이더
      	VertexOutput vert(VertexInput v)
        	{

          	VertexOutput o;      
          	o.vertex = TransformObjectToHClip(v.vertex.xyz);
            o.uv = v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw; // xy = scale zw = offset 
            o.uv2 = v.uv2.xy * _MainTex02_ST.xy + _MainTex02_ST.zw;
            //o.uv = v.uv;

         	return o;
        	}

//픽셀 셰이더
        half4 frag(VertexOutput i) : SV_Target
        {
            /*
            float2 uv = i.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;
            float2 uv02 = i.uv.xy * _MainTex02_ST.xy + _MainTex02_ST.zw;
            */

            //half4 color = tex2D(_MainTex, i.uv);
            half4 col01 = _MainTex.Sample(sampler_MainTex, i.uv);
            half4 col02 = _MainTex02.Sample(sampler_MainTex, i.uv2);

            half color = lerp(col01, col02 , 0.5);
          	
            return color;
       	
        	}

        	ENDHLSL  
    	}
     }
}

 

 

이걸 쉐이더 그래프로 표현하면 다음과 같다

 

간단하다....

 

.

.

.

..