WinCNT

“sampler2D object does not have methods” 에러 발생(URP) 본문

Unity/Unity 개발 중 발생한 이슈 정리

“sampler2D object does not have methods” 에러 발생(URP)

WinCNT_SSS 2023. 1. 24. 12:23

발생한 이슈

URP에서 텍스처를 추가하려고 하던 중에 다음과 같은 에러가 발생했다


이슈 상세

정확히는 shader파일에서 에러가 발생하고 있었다

작성한 쉐이더 코드는 다음과 같다

Shader "Text/Example"
{
    Properties
    {
       _BaseMap ("BaseMap", 2D) = "white" {}
        _BaseColor ("BaseColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        // SubShader Tags define when and under which conditions a SubShader block or a pass is executed.
        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "RenderType"="Opaque"
        }
        
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float4 positionOS   : POSITION;
                float2 uv           : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS  : SV_POSITION;
                float2 uv           : TEXCOORD0;
            };

            sampler2D _BaseMap;
            SAMPLER(sampler_BaseMap);
            
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                float4 _BaseColor;
            CBUFFER_END
            
            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
                return OUT;
            }

            half4 frag(Varyings IN) : SV_Target
            {
                half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
                return color;
            }
            ENDHLSL
        }
    }
}

발생 원인

분명 예제대로 코딩했을 텐데 이상하네…라고 생각했는데 자세히 보니 예제대로 코딩하지 않아서 이슈가 발생하고 있었다

정확히는 _BaseMap는 sampler2D(아마 HSLS)로 선언하고 프래그먼트 쉐이더에서는 SAMPLE_TEXTURE2D라는 (아마 유니티의)매크로를 사용하고 있던 것이 원인 이었다


해결법

_BaseMap를 똑같이 매크로 선언하거나, SAMPLE_TEXTURE2D라는 매크로 대신 tex2D이라는 hlsl함수를 사용하니 이슈가 해결되었다

(범용성을 위해 매크로를 쓰기로 함)

Shader "Text/Example"
{
    Properties
    {
       _BaseMap ("BaseMap", 2D) = "white" {}
        _BaseColor ("BaseColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        // SubShader Tags define when and under which conditions a SubShader block or a pass is executed.
        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "RenderType"="Opaque"
        }
        
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float4 positionOS   : POSITION;
                float2 uv           : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS  : SV_POSITION;
                float2 uv           : TEXCOORD0;
            };

            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
            
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                float4 _BaseColor;
            CBUFFER_END
            
            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
                return OUT;
            }

            half4 frag(Varyings IN) : SV_Target
            {
                half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);                
                return color;
            }
            ENDHLSL
        }
    }
}

사족

해당 이슈와 직접적인 상관은 없었지만 URP에서 텍스처를 추가할 때에는 몇 가지 규칙이 있었다

간단히 아래에 정리해보려고 한다

 

Tiling과 Offset

특정 텍스처에 대해 타일링과 오프셋을 설정하고 싶을 경우

해당 텍스처의 변수명 + _ST이라는 float4 변수를 만들어야 한다 

TEXTURE2D(_BaseMap);

CBUFFER_START(UnityPerMaterial)
    float4 _BaseMap_ST;
CBUFFER_END

 

또한 버텍스 쉐이더에서 TRANSFORM_TEX 매크로를 사용하면 타일링과 오프셋이 적용된 uv 좌표를 구할 수 있다

Varyings vert(Attributes IN)
{
    Varyings OUT;
    OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
    return OUT;
}
//ShaderLibrary/Macros.hlsl에 정의된 매크로
#define TRANSFORM_TEX(tex, name) ((tex.xy) * name##_ST.xy + name##_ST.zw)

 

Sampler State

Sampler State를 설정할 때는 SAMPLER 매크로나 SamplerState를 사용한다(매크로 추천)

변수명은 명명 규칙에 의해 sampler + 텍스처 변수명으로 선언해야 한다

// 매크로
SAMPLER(sampler_BaseMap);

// SamplerState
SamplerState sampler_BaseMap;

 

프래그먼트 쉐이더에서는 SAMPLE_TEXTURE2D매크로나 Sample함수를 사용한다

// 매크로
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);

// SamplerState
half4 color = _BaseMap.Sample(sampler_BaseMap, IN.uv);

참고 자료

https://docs.unity3d.com/kr/Packages/com.unity.render-pipelines.universal@8.2/manual/writing-shaders-urp-unlit-texture.html

 

텍스처 그리기 | Universal RP | 8.2.0

텍스처 그리기 이 예제의 Unity 셰이더는 메시에 텍스처를 그립니다. 컬러 입력을 제공하는 URP 언릿 셰이더 섹션의 Unity 셰이더 소스 파일을 사용하고 ShaderLab 코드에 다음 변경 사항을 적용하십시

docs.unity3d.com