T.TAO
Back to Works
2026/graphics / tools

Metal Shader Canvas

ネイティブ macOS リアルタイムシェーダーワークベンチ:レイヤー式 MSL オーサリング、ホットリロードコンパイル、マルチパスポストプロセス、そして AI が自らのレンダリング結果を検証するエージェント編集ループ。

MetalShadersToolsAI
Metal Shader Canvas

Metal Shader Canvas はネイティブ macOS アプリケーション(SwiftUI + Metal、約 2.2 万行の Swift)で、シェーダーオーサリングのための軽量リアルタイムレンダリングエンジンのように動作します。3D メッシュまたは 2D キャンバスの上に、頂点・フラグメント・フルスクリーンポストプロセスの各シェーダーをレイヤーとして積み重ね、アプリが MSL ソースをランタイムでコンパイルして即座に結果を表示します。

もともとは私のゲームエンジン MetalCaster のシェーダーイテレーションツールとして始まり、独立したプロジェクトに成長しました——そして、私が強い関心を持つ問い、**「レンダリングツールの中で LLM エージェントを本当に役立つものにするにはどうすればいいか?」**の主要な実験場にもなりました。

プロジェクトは GitHub でオープンソース公開しており、本サイトにはハンズオンのチュートリアルシリーズもあります:Shader Canvas の基本

Shader Canvas Editor

アーキテクチャ

アプリは厳密に分離された 2 つのレイヤーで構成されています:

  • SwiftUI フロントエンドがすべての状態を所有:コードエディタ(MSL シンタックスハイライト、オートインデント、スニペット)、レイヤー管理、チュートリアル、AI チャット、.shadercanvas / .shaderlab ワークスペースの永続化。
  • MetalRenderer バックエンドMTKViewDelegate、約 1,600 行)が GPU リソースを独占的に所有:パイプラインステート、オフスクリーンテクスチャ、ModelIO によるメッシュ読み込み、フレームごとのエンコーディング。

両者は薄い NSViewRepresentable ブリッジと疎結合な通知で通信します——レンダラーは決して UI 状態に触れず、これがランタイムのシェーダー再コンパイルがフレームをブロックしない理由です。

フレームの構成をパスごとに

3D モードは古典的な方法でレンダリングします:

  1. 背景 + メッシュパスをオフスクリーン HDR テクスチャへ。深度テスト(Depth32F)、右手系透視投影、Rodrigues 回転によるモデル変換を使用。
  2. フルスクリーンポストプロセスチェーンが 2 枚のオフスクリーンテクスチャ間を ping-pong ——ユーザーレイヤー 1 つが 1 パス。
  3. 最終 blit で drawable に表示。フルスクリーントライアングル(クアッドではなく NDC を覆う 3 頂点)と .private ストレージの GPU テクスチャを使用。

2D モードはこれをオブジェクトごとのパイプラインで拡張します:各 2D オブジェクトは独自の頂点シェーダー(変形)、フラグメントシェーダー(シェーディング)、そしてシステムが注入する SDF ラッパーを持ち、符号付き距離に基づくアルファマスクとアンチエイリアスエッジを計算します。各オブジェクトの描画前に現在のバックバッファが blit され、オブジェクトのシェーダーが背後の画面をサンプリングできます——これにより 2D でも屈折や影のような効果が実現できます。

Fullscreen Post-Processing

邪魔をしないホットリロードコンパイル

すべての編集がランタイムの device.makeLibrary(source:) コンパイルをトリガーしますが、素朴に全体を再コンパイルするとエディタは使い物になりません。レンダラーの工夫:

  • シェーダー状態を diff し、実際に変更のあったカテゴリのパイプラインだけを再構築(mesh / fullscreen / オブジェクトごとに独立)。
  • 専用キューでコンパイルを直列化し、epoch カウンターにより、後続の編集で上書きされた古い結果は競合せずに破棄。
  • 一時的な失敗は Metal コンパイラデーモンのクールダウン付きでリトライし、構造化された MSL エラーメッセージをエディタに返却。
  • フレームセマフォで in-flight フレーム数を制限し、重いシェーダーが GPU キューをハングさせないように。

データ駆動の頂点インターフェース

固定の頂点フォーマットの代わりに、Data Flow パネルでどの属性(法線、UV、ワールド座標、視線方向……)をシェーダーに流すかをトグルでき、アプリが共有 MSL ヘッダーを自動生成します。これはあらゆるシェーダーグラフシステムが解かねばならないインターフェース問題のミニチュア版です。

Data Flow

シェーダーはインラインで調整可能なパラメータも宣言できます——// @param _rimPower float 2.0 0.5 8.0 ——アプリはこれを GPU バッファに裏打ちされた UI スライダーに変換します。Houdini スタイルです:

Parameters

組み込みシェーディングライブラリ

10 種類の古典的ライティングモデル(Lambert、Phong、Blinn-Phong、トゥーン、リムライト、フレネル……)と 5 種類のポストエフェクト——Bloom(しきい値抽出 + ガウシアン + 加算合成)、ACES トーンマッピング、HSV 調整、ガウシアンブラー、エッジ検出——に加え、9 ステップのインタラクティブな Metal チュートリアルを内蔵。各プリセットはエディタでワンクリックで適用でき、アクティブレイヤーのソースに直接書き込まれます:

インタラクティブチュートリアルで Blinn-Phong プリセットを適用

Fresnel リムシェーディングプリセット

メッシュパスの上にフルスクリーンレイヤーを重ねると、フレーム全体がポストプロセスチェーンを通ります:

メッシュパスに重ねたフルスクリーンポストプロセスレイヤー

Bloom

エージェントワークフロー:レンダラーとのループを閉じる

このプロジェクトで最も興味深いのは個々のシェーダーではなく、AI システムの設計です。多くの「AI + シェーダー」ツールは、生成コードをエディタに貼り付けるところで止まっています。Shader Canvas は代わりにリアルタイムレンダラーをエージェントの ground truth として扱います:エージェントの行動はすべて実際のコンパイルと実際のレンダリングで検証され、レンダリング結果がモデルにフィードバックされます。エージェントループを高速かつ信頼できるものにしているのはレンダラーです——人間なら「コピー・コンパイル・確認」で数分かかるシェーダーの 1 イテレーションを、エージェントは数秒でこなします。コンパイル結果とレンダリングフレームが自動的にコンテキストへ流れ込むからです。

1. コードの投げ捨てではなく、構造化されたアクション

エージェントは JSON の AgentResponse で応答します——canFulfillexplanation、型付き actions のリスト(addLayermodifyLayeraddObject2DsetObjectShader2D など)、そしてリクエストがパイプラインの能力を超える場合の明示的な barriers。アクションは UI と同じコードパスを通じてレンダーグラフを直接変更し、実行前にワークスペースチェックポイントを取得するため、エージェントの編集はすべて取り消し可能です。

2. コンパイル → レンダリング → 検証、すべて自動

Plan モードでは、複数ステップのタスクがタスクツリーになり、各ステップが検証ループを実行します:

  1. シェーダーアクションを生成・適用する。
  2. レンダラーから実際のコンパイル結果を待つ
  3. 失敗した場合、MSL エラーをフィードバックして自動修正(回数制限付きリトライ)。
  4. 成功した場合、レンダリングフレームをキャプチャし、ビジョンモデルがステップの意図に対して視覚的な結果を検証する。
  5. 検証を通過して初めてステップを完了とマークする。

キャプチャの経路は偶然ではなく設計されたものです:レンダラーは GPU タイムライン上でオフスクリーン HDR ターゲットを読み戻し、512px にダウンスケールし、メインスレッド外で JPEG に圧縮してマルチモーダルコンテキストに添付します。2D モードでは、エージェントは変更したオブジェクトだけを分離してレンダリングするプレビュークローンまで作れます——ユーザーが受け入れるまで、変更がユーザーのオブジェクトを上書きすることはありません。

3. シェーダーのためのコンテキストエンジニアリング

生の MSL をプロンプトに流し込むやり方はスケールしません。ContextManager がトークン予算を意識した階層的コンテキストを組み立て、ShaderAnalyzer がユーザーの MSL を静的解析して意味的な要約を生成します——30 以上のエフェクトパターン(PBR 近似、bloom、SDF ブーリアン、レイマーチング、時間アニメーション……)を認識し、モデルがテキストではなくシェーダーが何をしているかについて推論できるようにします。予算が逼迫すると会話履歴も圧縮されます。

4. Lab モード:ドキュメント駆動のコラボレーション

Lab モードは長期的な作業をフェーズに構造化します——リファレンス → 分析 → 設計ドキュメント → 実装 → チューニング → アドバーサリアルレビュー。1 回のエージェント応答で、設計ドキュメントの更新、調整可能パラメータの登録、シェーダーコードの記述を同時に行えます。アドバーサリアルフェーズでは、AI が現在のシェーダーに対する競合バリアント(パラメータとコードの変更)を提案し、ユーザーは受け入れ・拒否・部分採用を選べます。パラメータスナップショットで A/B 比較も可能です。

このプロジェクトから学んだこと

エージェントの性能は、与えるフィードバックの質で決まります。レンダラーをループに組み込むこと——コンパイル結果、レンダリングフレーム、意味的なシェーダー解析——によって、AI は単なるコードジェネレーターから「自分の仕事を自分で確認するジュニアテクニカルアーティスト」に近い存在へと変わりました。この原則は MetalCaster のマルチエージェントシステムにそのまま受け継がれています。

スコープの正直な説明

Shader Canvas は設計上ラスタライゼーションパイプラインです:頂点/フラグメントステージとフルスクリーンパス、2D では SDF ベースのプロシージャルシェーディング(ユーザーがレイマーチングのフラグメントを手書きすることも可能)。ハードウェアレイトレーシング、コンピュートパイプライン、シャドウマッピングは実装していません——エージェントのシステムプロンプトはこれらを能力の境界として明示的に宣言しており、できないことをできるふりは決してしません。GPU レイマーチングは、MetalCaster リポジトリ内の姉妹プロジェクト SDF Canvas に実装されています。

技術スタック: Swift、SwiftUI、Metal、MetalKit、ModelIO、simd、MSL · macOS 26+