UnityのShader Graphでステンシルを使えるかどうかは、Unityのバージョンとグラフの種類で答えが変わります。Lit・UnlitのグラフにはUnity 6.6までステンシルの設定項目が無く、2026年9月17日公開のUnity 6.7ベータ(6000.7.0b1)でURP向けに対応が入りました。一方、画面全体に効果をかけるFullscreenグラフと、uGUI用のCanvasグラフは、6.6以前からステンシルを扱えます。この記事では版ごとの対応状況を整理し、6.6以前のプロジェクトでマスクやくり抜きを作る手順(Render Objects・ShaderLab・Fullscreenグラフ)と、URPで使ってよいステンシルの値を説明します。基準は現行LTSのUnity 6.3と最新のUnity 6.6です。
まとめ:Shader Graphのバージョン・グラフ別ステンシル対応
- Lit・Unlitのグラフ:Unity 6.6まではステンシルの項目が無い。Unity 6.7ベータのURPでマテリアル単位のステンシル設定が追加された(正式版はまだ出ていない)。
- 6.6以前でマスク・くり抜きを作るなら、URPのRender Objectsでレイヤーごとにステンシルを書き込み、比較する。被マスク側はShader Graphのマテリアルをそのまま使える。色を書かないマスク用マテリアルは別途用意する必要があり、この記事では後述のShaderLabコードを使う。
- マスク形状をシェーダー側で持たせたいなら、ShaderLabで
Stencilブロックを書いた小さなマスク用シェーダーを用意する。Shader Graphの生成コードを書き換える方法は、グラフを保存し直すと消えるので使わない。 - FullscreenグラフはGraph SettingsのEnable Stencilで、ステンシル値の入った画素だけにポストエフェクトをかけられる。
- URPで自由に使えるのはビット0〜3(値0〜15)。LODのクロスフェードを「2×2 Stencil」にしている場合は値4と8のビットも埋まるので、値1〜3を使い、WriteMask・ReadMaskを3に絞る。
Shader Graphのステンシル対応状況:Unity 6.0〜6.7の比較
「Shader Graphはステンシル非対応」という説明は、Lit・Unlitのグラフについては6.6まで正しく、それ以外のグラフには当てはまりません。グラフの種類ごとの状況は次のとおりです。
| グラフの種類 | Unity 6.0〜6.6 | Unity 6.7ベータ | 設定する場所 |
|---|---|---|---|
| URP Lit・Unlit | 項目なし | マテリアル単位で設定可 | 6.7のマテリアル設定 |
| URP Fullscreen | あり | あり | Graph SettingsのEnable Stencil |
| Canvas(uGUI) | Mask用に自動生成 | Mask用に自動生成 | Maskコンポーネントが値を渡す |
| HDRP Lit・Unlit | 項目なし | リリースノートに記載なし | Custom PassのOverride Stencil |
Unity 6.6以前のLit・Unlitにステンシル項目が無い理由
ステンシルは色の計算ではなく、描画時のレンダーステート(どの画素に描くか)に属する設定です。Shader Graphのノードは画素ごとの値を計算する部品なので、レンダーステートを変えるノードはありません。Lit・Unlitのグラフでレンダーステートを決めるのはGraph Settings(Surface Type・Render Face・Depth Testなど)ですが、ここにもステンシルはありませんでした。Unity 6.6のURPマニュアルでも、Lit shader graphのリファレンスにStencilの語は1回も出てきません。Unity Discussionsの「Shader graph missing features」では2024年12月6日に「No stencil support」が挙がり、2025年1月23日に回答者が「Exactly what we need to make this a higher priority.」と返信していました。
Unity 6.7ベータで追加されたURPのマテリアル単位のステンシル設定
Unity 6000.7.0b1のリリースノートには「URP: Added support for stencil in Shader Graph.」と「Added a Stencil Shader Graph override sample for URP.」の2行があります。2026年9月21日のUnity公式のグラフィックス更新告知では、「Lit and Unlit materials gain per-material stencil settings」とあり、深度の上書きと、上書きを適用するパスの指定も加わったと説明されています。サンプルはPackage ManagerのURPのSamplesタブに「Shader Graph Stencil Override Samples」として入っています。
2026年10月19日時点で6.7はベータ(最新は10月15日の6000.7.0b5)で、Unity 6.7のマニュアルにもまだShader Graphのステンシル設定のページはありません。Unity 6.5のマニュアルは6.7をLTSと案内しているので、6.7が正式版になればLit・Unlitのステンシルはグラフ側で済むようになります。ただ、製品版のプロジェクトをベータに上げるのは避け、6.3 LTSや6.6で開発している間は次章以降の方法で組んでください。6.3 LTSの変更点はUnity 6.3 LTS(6000.3)の新機能と変更点にまとめています。
ステンシルテストの仕組み:Ref・Comp・Passと比較の向き
ステンシルバッファは画素ごとに8bitの整数(0〜255)を持つ領域です。描画のたびにGPUは、シェーダーの参照値(Ref)とバッファにある値を比較し、通れば描画して、結果に応じてバッファを書き換えます。ShaderLabのStencilコマンドのリファレンスにある主な項目と既定値は次のとおりです。
| 項目 | 意味 | 既定値 |
|---|---|---|
| Ref | 比較・書き込みに使う参照値(0〜255) | 0 |
| ReadMask | 比較のときに見るビット | 255 |
| WriteMask | 書き込むビット | 255 |
| Comp | 比較関数(Equal・NotEqual・Lessなど) | Always |
| Pass | ステンシルと深度の両方を通ったときの操作 | Keep |
| Fail | ステンシルテストに落ちたときの操作 | Keep |
| ZFail | ステンシルは通り深度で落ちたときの操作 | Keep |
Compは「Refとバッファの値」を比べる:WebGLでの再現結果
比較関数で取り違えやすいのが向きです。リファレンスでは、たとえばLessは「参照値がバッファの値より小さいときに描く」と定義されています。Unity Editorでの検証に代えて、WebGL(headless ChromiumのSwiftShaderによるソフトウェア描画)でステンシル比較を再現し、100×100画素の左半分だけに値を書いたあと全面に赤を描いて、通った画素を数えました。
| 条件 | 左半分(値あり) | 右半分(値0) |
|---|---|---|
| Ref 1を書く → Equal 1で描く | 5,000画素 | 0画素 |
| Equal 1で描く → Ref 1を書く(順序を逆) | 0画素 | 0画素 |
| Ref 1を書く → NotEqual 1で描く | 0画素 | 5,000画素 |
| 2を書く → Ref 1・Lessで描く | 5,000画素 | 0画素 |
| 2を書く → Ref 1・Greaterで描く | 0画素 | 5,000画素 |
Ref 1でLessを指定すると、バッファが2の画素(1<2)で通り、0の画素では落ちます。「バッファの値が参照値より小さいときに通る」と逆に読むと、マスクの内と外が反転します。なお、URPのFullscreen shader graphのリファレンスではComparisonの各選択肢の説明が深度値の比較の文面になっていますが、ステンシルの比較の向きはShaderLabのリファレンスの定義で読んでください。
URPのRender Objectsによるステンシルマスクの設定手順
6.6以前で、壁の穴から別空間が見えるくり抜きや、窓の内側にだけ物体を出すマスクを作るなら、URPのRender Objectsレンダラーフィーチャが最短です。シェーダーには手を入れず、Rendererの設定でレイヤーごとにステンシルの書き込みと比較を差し込みます。
マスク用・被マスク用レイヤーの通常描画からの除外
マスクの形になるオブジェクトに「Mask」、その内側にだけ出したいオブジェクトに「Masked」というレイヤーを割り当てます。次にプロジェクトのUniversal Renderer Data(URPテンプレートではAssets/Settings配下)を開き、Filtering欄のOpaque Layer MaskとTransparent Layer Maskからこの2つのチェックを外します。通常の描画から外れたレイヤーは、このあと追加するRender Objectsだけが描くようになります。
Render Objectsの書き込み側と読み取り側の設定値
Universal Renderer DataのAdd Renderer FeatureからRender Objectsを2つ追加し、次のように設定します。OverridesのStencilにチェックを入れると、Value・Compare Function・Pass・Fail・Z Failの5項目が出ます。
| 項目 | 1つ目:マスク書き込み | 2つ目:被マスク表示 |
|---|---|---|
| Event | AfterRenderingOpaques | AfterRenderingOpaques |
| Filters > Layer Mask | Mask | Masked |
| Override Mode | Material(後述のStencilMaskWriterを使用) | None |
| Stencil > Value | 1 | 1 |
| Compare Function | Always | Equal |
| Pass | Replace | Keep |
被マスク側のOverride ModeはNoneにします。URPのソースではOverride Modeの既定値がMaterialなので、そのままでは被マスク側がShader Graphのマテリアルで描かれない場合があります。Noneなら各オブジェクトに割り当てたShader Graphのマテリアルのまま、ステンシルの条件だけが加わります。ValueのスライダーはURPのエディタ上で0〜15までしか動きません。これは後述のビット0〜3の制約に合わせたものです。
何も表示されないときの確認点:並び順・Event・深度
この例のようにEventが同じRender Objects同士は、リストの上から順に実行されます。被マスク表示を上に置くと、比較の時点でまだ1が書かれていないため、何も描かれません。前章のWebGLの再現でも、順序を逆にした条件は左右とも0画素でした。並び順が正しいのに出ないときは、次の順に確かめます。
- 被マスクが壁の奥にある:被マスク側のOverridesでDepthを有効にし、Depth TestをAlwaysにする。くり抜きでは奥の物体が手前の壁の深度に負けて消えるのが典型。
- 半透明の被マスク:EventをAfterRenderingTransparentsにし、FiltersのQueueをTransparentにした別のRender Objectsを用意する。
- どの段階で値が入っていないか分からない:Window > Analysis > Frame Debuggerで、Render Objectsのパスごとにステンシルの状態を確認する。
ShaderLabでステンシルを書き込むマスク用シェーダー
マスクをレイヤーではなくマテリアルで持たせたい場合や、マテリアルごとにRefを変えたい場合は、マスク側だけShaderLabで書きます。次はURP公式の基本的なUnlitシェーダーの構造にStencilブロックを足した、色を出さずにステンシルだけを書く例です。Unity EditorでのコンパイルとURP上の描画結果は未確認で、前章のWebGLの再現はこのコードの動作確認ではありません。
Shader "Custom/StencilMaskWriter"
{
Properties
{
[IntRange] _StencilRef ("Stencil Ref", Range(1, 15)) = 1
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry-1" }
Pass
{
ColorMask 0
ZWrite Off
Stencil
{
Ref [_StencilRef]
WriteMask 15
Comp Always
Pass Replace
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes { float4 positionOS : POSITION; };
struct Varyings { float4 positionHCS : SV_POSITION; };
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
return 0;
}
ENDHLSL
}
}
}
ColorMask 0で色を書かず、ZWrite Offで後ろの物体を隠さないようにします。"Queue" = "Geometry-1"は、通常の不透明物体(Geometry=2000)より先にマスクを描くための指定です。WriteMask 15でURPが使う上位ビットを保護しています。ただし、このコードはLODの2×2 Stencilとの併用を想定していません。併用する場合はWriteMaskを3、Stencil Refの範囲を1〜3に変更し、読み取り側もReadMaskを3に設定できる実装に変更してください。マスクの値をマテリアルごとに変えたいときは、InspectorでStencil Refを1〜15の範囲で変えます。
読み取り側をShader Graphのマテリアルのままにする組み合わせ
読み取り側(窓の内側に出す物体)は、見た目をShader Graphで作ったマテリアルのまま、前章のRender Objectsの2つ目(Layer Mask=Masked、Override Mode=None、Compare Function=Equal)で比較させます。この組み合わせでは、掲載シェーダーで作ったマテリアルをMaskオブジェクトに割り当て、MaskレイヤーをOpaque Layer Maskに戻して通常描画させます。書き込み用のRender Objectsは無効にし、Maskedレイヤーは通常描画から外したまま、読み取り用のRender Objectsだけを残します。Shader Graphのノードの組み方はUnity Shader Graphの使い方で解説しています。
Shader Graphの生成コードにStencilを足しても残らない理由
Shader GraphのグラフからはInspectorの「View Generated Shader」で生成コードを開けますが、これは保存のたびに作り直される一時的なコードです。そこにStencilブロックを書き足しても、グラフを編集して保存し直した時点で消えます。生成コードをコピーして別のシェーダーとして固める方法もありますが、以後はグラフの変更が反映されなくなります。Unity 6.5で追加されたHLSL関数のreflection APIも、自作のHLSL関数をノードとして使えるようにする仕組みで、レンダーステートを変えるものではありません。
Fullscreen Shader Graphによるステンシル領域へのエフェクト適用
Fullscreenグラフは、画面全体に描くポストエフェクト用のグラフです。こちらはGraph SettingsにEnable Stencilがあり、Reference・Read Mask・Write Mask・Comparison・Pass・Fail・Depth Failを指定できます。Render Objectsやマスク用シェーダーで値1を書いた画素にだけ色調補正やアウトラインをかける、といった使い方ができます。
- Universal Renderer DataにFull Screen Pass Renderer Featureを追加し、Pass MaterialのNewから「ShaderGraph Fullscreen」でグラフとマテリアルを作る。
- 作ったグラフのGraph SettingsでEnable Stencilを有効にし、Referenceを1、ComparisonをEqual、Read Maskを15、Write Maskを0、Pass・Fail・Depth FailをKeepにする。LODの2×2 Stencilを使う場合はRead Maskを3にし、書き込み側もWriteMaskを3に限定する。
- Full Screen Pass Renderer FeatureのBind Depth-Stencilを有効にする。Full Screen Passのリファレンスには、この項目でカメラの深度ステンシルにアクセスできるようになる代わりに性能へ影響すると書かれている。
- Injection Pointは、半透明より後で処理したいならBefore Rendering Post Processingにする(既定はAfter Rendering Post Processing)。
画面全体の効果を一部の画素に絞る目的なら、Render Objectsで対象の物体をもう一度描くよりこちらの方が設定が少なく済みます。パーティクルの生成・挙動はParticle SystemやVFX Graphで制御し、描画するマテリアルはShader Graphでも作れます。VFX Graphによるエフェクト制作については、Unity VFX Graphの使い方も参照してください。
uGUIのMaskとCanvas Shader Graphの関係
uGUIのMaskコンポーネントは、子のImageを親の形で切り抜くためにステンシルバッファを使います。Maskは子のマテリアルの_Stencil・_StencilComp・_StencilOp・_StencilReadMask・_StencilWriteMask・_ColorMaskというプロパティに値を書き込むので、マテリアル側にこれらが無いと切り抜けません。
URPターゲットでマテリアルの種類をCanvasにしたグラフ(Canvas shader graph、Unity 2023.2で追加)なら、これらのプロパティを自動で生成します。Shader Graphのソース(CanvasSubTarget.cs)でも、Ref [_Stencil]やComp [_StencilComp]をレンダーステートに組み込んでいます。UIに通常のUnlitグラフを使ってMaskが効かないときは、Consoleに「doesn’t have _Stencil property」という警告が出ていないか確認し、グラフをCanvasに作り直してください。なお、UI ToolkitはCanvasとMaskを使わない別のUIシステムです(例:Unity UI ToolkitのScrollViewの使い方)。
URPとHDRPで使えるステンシルのビット
ステンシルバッファの8bitは、レンダーパイプライン自身も使っています。空いていないビットに書くと、ライティングやLODの表示が崩れます。
URPはビット0〜3(値0〜15)、LODの2×2 Stencil併用時は値1〜3
URPのUniversal Rendererのリファレンスは「ビット0〜3、つまり値0〜15をカスタム効果に使える」と明記しています。URPのソースのStencilUsageでは、Deferredレンダリングがビット4をライトの形状に、ビット5・6をマテリアルの種類に使っています。さらにURP AssetのLOD Cross Fade Dithering Typeを「2×2 Stencil」にすると、Unityはステンシルの値4と8を使います。この設定のプロジェクトで自前のマスクに使えるのはビット0・1、つまり値1〜3だけで、書き込み・読み取りのマスクも3に絞ります。Render ObjectsのStencil項目にはRead Mask・Write Maskが無くビットを絞れないので、2×2 Stencilと併用するマスクはShaderLabでWriteMask 3を付けて書きます。
書き込み側ではWriteMask 15を付けておくと、上位ビットを誤って消しません。WebGLの再現でWriteMask 15のままRef 17を書いたところ、バッファには1だけが残りました。読み取り側でRef 17・Equalを比べると0画素、Ref 1か、ReadMask 15を付けたRef 17なら5,000画素が通りました。ReadMaskとWriteMaskをそろえていないと、値を書いたつもりでも比較が合いません。
HDRPはUserBit0(64)とUserBit1(128)の2ビットだけ
HDRPは自身の処理にビット0〜5を使い、ユーザーに開放しているのはビット6と7だけです。UserStencilUsageのAPIリファレンスは、UserBit0(64)・UserBit1(128)を使うときにWrite Maskをそのビットだけに絞るよう求めています。HDRPにはRender Objectsが無いので、Custom PassのDrawRenderersでOverride Stencilを有効にし、Reference・Read Mask・Write Mask・Comparisonなどを指定します。Unity 6.7ベータのリリースノートにあるShader Graphのステンシル対応はURPのみです。
ステンシル以外で迷いやすいShader Graphのパネル:BlackboardとGraph Inspector
ステンシルを調べている途中で、設定がどのパネルにあるか分からなくなることがあります。BlackboardとGraph Inspectorは役割がはっきり分かれています。
Blackboard:Materialに出すプロパティとReference名の管理
Blackboardは、Materialのインスペクターに出すプロパティ(色・数値・テクスチャなど)とキーワードを追加・整理するパネルです。タイトルバーの「+」で型を選んで追加し、項目を選ぶとGraph InspectorのNode SettingsでName・Reference・Default・Precision・Exposedを編集できます。Referenceはシェーダー内部での変数名で、C#のMaterial.SetFloatなどから値を変えるときはこの名前を使います。Blackboardのマニュアルによると、HLSLで使えない文字はアンダースコアに置き換えられます。
Graph Inspector:Graph SettingsとNode Settingsの切り替え
Graph Inspectorは、グラフを開いた直後はGraph Settingsタブを表示し、ノードを選ぶとNode Settingsタブにそのノードの設定を出します。ターゲット(URP・HDRP・Built-In)、マテリアルの種類(Lit・Unlit・Canvas・Fullscreenなど)、Surface Type、Depth Test、そしてFullscreenのEnable StencilはGraph Settingsにあります。Shader GraphのGraph TargetはURP・HDRP・Built-Inの3つです。Built-InレンダーパイプラインはUnity 6.5で非推奨になりましたが、6.7 LTSのサポート期間中は保守が続きます。Unity 6の全体的な変更はUnityを日本語化する方法とUnity 6の新機能にまとめています。
ステンシルを使ったゲーム表現の設計や、URPへの移行を含むUnity開発の相談は、ゲームアプリ開発で受け付けています。
よくある質問
Shader Graphでステンシルは使えますか?
URPのLit・UnlitのグラフはUnity 6.6まで使えず、Unity 6.7ベータでマテリアル単位のステンシル設定が追加されました。FullscreenグラフはGraph SettingsのEnable Stencilで、Canvasグラフは自動生成されるプロパティで、6.6以前でもステンシルを扱えます。
Unity 6.6以前でShader Graphのマテリアルにマスクをかけるにはどうしますか?
URPのRender Objectsを2つ追加し、1つ目でマスク用レイヤーに値1を書き(Always・Replace)、2つ目で被マスク用レイヤーをEqualで描きます。2つ目のOverride ModeをNoneにすると、Shader Graphのマテリアルのまま表示されます。
ステンシルの値は何番を使えばよいですか?
URPでは1〜15を使います。LOD Cross Fade Dithering Typeが2×2 Stencilなら、値4と8に相当するビットを保護するため、自前の書き込み側のWriteMaskと読み取り側のReadMaskを3に限定し、Refには1〜3を使います。HDRPでは64(UserBit0)か128(UserBit1)です。
uGUIのMaskがShader Graphのマテリアルで効かないのはなぜですか?
MaskはマテリアルのStencil系プロパティに値を渡して切り抜くため、通常のUnlitグラフでは効きません。グラフのマテリアルの種類をCanvasにすると、必要なプロパティが自動で生成されます。
Unity 6.7のShader Graphのステンシル対応はHDRPでも使えますか?
6000.7.0b1のリリースノートが対応を明記しているのはURPだけです。HDRPでは、従来どおりCustom PassのDrawRenderersでOverride Stencilを設定し、UserBit0・UserBit1を使います。