【Unity】【シェーダ】インラインサンプラーステートを使ってテクスチャのWrap ModeやFilter Modeをシェーダで指定する

Unityでインラインサンプラーステートを使ってテクスチャのWrap ModeやFilter Modeをシェーダで指定する方法についてまとめました。

Unity2020.3.15f2

サンプラーステートをシェーダで指定する

サンプラーステートとは、テクスチャのラッピングモードやフィルタリングモードといった情報のことです。
基本的にはテクスチャに紐づく情報であり、Unityではテクスチャのインポート設定として設定できます。

f:id:halya_11:20210913193446p:plain
インポート設定

Unityのシェーダでは、例えば以下のように記述することでこのインポート設定を使わずにサンプラーステートを直接指定することができます。

SamplerState sampler_point_clamp;

上記のサンプラはフィルタリングモードがPoint、ラッピングモードがClampに設定されます。
サンプラの設定は名前により決まります。命名ルールは以下の通りです。

命名ルール 指定が必須か 説明
Point / Linear / Trilinear YES フィルタリングモードを指定
Clamp / Repeat / Mirror / MirrorOnce YES ラッピングモードを指定
ClampU_RepeatVのように軸ごとに指定も可能
AnisoX NO 異方性フィルタリングの値を指定
Xには2/4/8/16の数値を指定する
Compare NO 深度比較のためのサンプラを設定する

大文字小文字の区別はなく、SamplerState型の名前に上記の単語を使っていれば良いようです。
linearmirrorとかでも行けました。

またこの機能はマニュアルによると使えるプラットフォームが限られるようです。

Currently they are implemented on Direct3D 11/12, PS4, XboxOne and Metal.

ただしこのページは2017年から更新されていないのでアテにならなそうです。
実際VulkanのAndroid(Snapdragon439)でも動作確認ができました。

シェーダを書く

さてそれではインラインサンプラーステートを使ったシェーダを記述します。

※URP用のシェーダです

Shader "Example"
{
    Properties
    {
        _BaseMap("Base Map", 2D) = "white" {}
    }

    SubShader
    {
        Tags
        {
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
            "IgnoreProjector" = "True"
            "Queue" = "Geometry"
        }

        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);
            // インラインサンプラーステート
            SamplerState sampler_point_mirror;

            CBUFFER_START(UnityPerMaterial)
            float4 _BaseMap_ST;
            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
            {
                // インラインサンプラーステートを使ったサンプリング
                return _BaseMap.Sample(sampler_point_mirror, IN.uv);
            }
            ENDHLSL
        }
    }
}

説明はコメントに書いた通りです。
今回はフィルタリングモードをPoint、ラッピングモードをMirrorにしたサンプラを使ってみました。

結果

それでは実際にこのシェーダを使ってレンダリングしてみます。
以下のようなテクスチャを用意して、インポート設定でWrap ModeをClampにしておきます。

f:id:halya_11:20210913213513p:plain
テクスチャ

Tilingを2x2にして、先程のシェーダで描画すると以下の通りの結果となります。

f:id:halya_11:20210913213657p:plain
結果

Wrap ModeがMirrorの状態でサンプリングできていることが確認できました。

参考

docs.unity3d.com