4
3

More than 1 year has passed since last update.

【Unity】Samplerが消える問題

Last updated at Posted at 2022-12-06

はじめに

本記事はAdvent Calendar 2022の7日目の記事です。

環境

  • Unity 2021.3.11f1
  • URP
  • RenderDoc

Samplerには制限がある

問題の前に前提の話をします。

Samplerは最大で16個までしか使えません。

float4 frag (v2f i) : SV_Target
{
    float4 col = tex2D(_MainTex0, i.uv);

    col += tex2D(_MainTex1, i.uv);
    col += tex2D(_MainTex2, i.uv);
    col += tex2D(_MainTex3, i.uv);
    // _MainTex4~14まである
    col += tex2D(_MainTex15, i.uv);    
    // 17枚目のテクスチャはまだ使わない
    // col += tex2D(_MainTex16, i.uv);
    return col;
}

image.png
全16枚のテクスチャがしっかりと読み込まれています。

ここで17枚目のテクスチャを使ってみます。

float4 frag (v2f i) : SV_Target
{
    float4 col = tex2D(_MainTex0, i.uv);

    col += tex2D(_MainTex1, i.uv);
    col += tex2D(_MainTex2, i.uv);
    col += tex2D(_MainTex3, i.uv);
    // _MainTex4~14まである
    col += tex2D(_MainTex15, i.uv);    
    // 17枚目を使う
    col += tex2D(_MainTex16, i.uv);
    return col;
}

image.png
テクスチャの読み込みに失敗しました。

Shader error in 'Unlit/Test': maximum ps_4_0 sampler register index (16) exceeded at

エラー文ではSamplerが16を超えた的な内容が出ます。

何が問題なのか

Samplerの数=テクスチャの枚数
といった感じでShaderを書いていると16枚以上テクスチャを使えないことになります。

解決方法

ですがSamplerは使い回して使うことができるので1つのSamplerで何枚ものテクスチャを出すことができます。
これを利用すればSamplerは16個、Textureは128個まで使うことができます。

Texture2D _MainTex0;
SamplerState sampler_MainTex0;

Texture2D _MainTex1;
Texture2D _MainTex2;
// _MainTex3~_MainTex15まである
Texture2D _MainTex16;

float4 frag (v2f i) : SV_Target
{
    float4 col = _MainTex0.Sample(sampler_MainTex0, i.uv);
    col += _MainTex1.Sample(sampler_MainTex0, i.uv);
    col += _MainTex2.Sample(sampler_MainTex0, i.uv);
    // _MainTex3~_MainTex15まで上と同じような処理
    col += _MainTex16.Sample(sampler_MainTex0, i.uv);
    // これでTextureを0~16で17枚使用してる

    return col;
}

image.png
しっかりとテクスチャが17枚読み込まれています。

しかし…

SamplerStateが消える?ことがあります。

Texture2D _MainTex0;
SamplerState sampler_MainTex0;

Texture2D _MainTex1;

float4 frag (v2f i) : SV_Target
{
    float4 col=(float4)0;
    float4 col2=(float4)0;

    col = _MainTex0.Sample(sampler_MainTex0, i.uv);
    col2=_MainTex1.Sample(sampler_MainTex0, i.uv);

    // colは使わずcol2だけを返す
    return col2;
}

image.png

最終的に返す値はcol2なのでcolの分の計算がすっ飛ばされて結果的にsampler_MainTex0が消えてエラーを出します。

image.png
colを返すときSamplerStateはしっかりと残っています。

returnまでの計算でそのSamplerStateを使わないことが問題なので

float4 frag (v2f i) : SV_Target
{
    float4 col=(float4)0;
    float4 col2=(float4)0;

    col = _MainTex0.Sample(sampler_MainTex0, i.uv);
    col2=_MainTex1.Sample(sampler_MainTex0, i.uv);

    // col,col2どっちも計算に使う
    col2 = col2+col;
    return col2;
}

image.png
このようにreturnまででちゃんと数値を使ってあげればエラーはなくなります。

しかし、このままだと#ifして分岐するプログラムなどを書いたときにSamplerStateが消えてエラーが出る可能性があります。

解決策

エラー文を確認すると

Shader error in 'Unlit/Test': Fragment program 'frag': Unrecognized sampler 'sampler_maintex0' - does not match any texture and is not a recognized inline name (should contain filter and wrap modes)
'Unlit/Test' のシェーダー エラー: フラグメント プログラム 'frag': 認識されないサンプラー 'sampler_maintex0' - どのテクスチャとも一致せず、認識されたインライン名ではありません (フィルター モードとラップ モードを含める必要があります)

フィルターモードとラップモードを含める必要があるといわれるので素直に追加します。

Texture2D _MainTex0;
// これをやめて
// SamplerState sampler_MainTex0;

// こんな感じにする
SamplerState sampler_linear_clamp_MainTex0;

Texture2D _MainTex1;

float4 frag (v2f i) : SV_Target
{
    float4 col=(float4)0;
    float4 col2=(float4)0;

    col = _MainTex0.Sample(sampler_linear_clamp_MainTex0, i.uv);
    col2=_MainTex1.Sample(sampler_linear_clamp_MainTex0, i.uv);

    // colは使わずcol2だけを返す
    return col2;
}

image.png
無事にエラーが消えます。

フィルター

  • Point
  • Linear
  • Trilinear

ラップ

  • Clamp
  • Repeat
  • Mirror
  • MirrorOnce
    SamplerStateの変数名に書き足せば使えます。

これらの名前が入っていればいいので

  • sampler_linear_clamp_MainTex0(上で使ってた名前)
  • samplerlinearclamp_MainTex0(_を一部消した)
  • samplerclamp_MainTex0_linear(linearを最後に書いた)
  • ClAmP_MainTex0_linear(大文字小文字がぐちゃぐちゃ)

でも問題なく動きます。
image.png
デバッグ結果にも含まれています。

まとめ

SamplerStateが消えてしまう問題をフィルターモードとラップモードを書くことで回避しました。
消えないテクニックが存在するかShaderの書き方が悪いのか分かりませんが現状はこの方法でこの問題を私は乗り越えています。

これをしなくても回避する方法がありましたら教えて頂きたいです。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3